github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_iam_policy_attachment.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/service/iam" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func resourceAwsIamPolicyAttachment() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceAwsIamPolicyAttachmentCreate, 19 Read: resourceAwsIamPolicyAttachmentRead, 20 Update: resourceAwsIamPolicyAttachmentUpdate, 21 Delete: resourceAwsIamPolicyAttachmentDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 29 if v.(string) == "" { 30 errors = append(errors, fmt.Errorf( 31 "%q cannot be an empty string", k)) 32 } 33 return 34 }, 35 }, 36 "users": &schema.Schema{ 37 Type: schema.TypeSet, 38 Optional: true, 39 Elem: &schema.Schema{Type: schema.TypeString}, 40 Set: schema.HashString, 41 }, 42 "roles": &schema.Schema{ 43 Type: schema.TypeSet, 44 Optional: true, 45 Elem: &schema.Schema{Type: schema.TypeString}, 46 Set: schema.HashString, 47 }, 48 "groups": &schema.Schema{ 49 Type: schema.TypeSet, 50 Optional: true, 51 Elem: &schema.Schema{Type: schema.TypeString}, 52 Set: schema.HashString, 53 }, 54 "policy_arn": &schema.Schema{ 55 Type: schema.TypeString, 56 Required: true, 57 ForceNew: true, 58 }, 59 }, 60 } 61 } 62 63 func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface{}) error { 64 conn := meta.(*AWSClient).iamconn 65 66 name := d.Get("name").(string) 67 arn := d.Get("policy_arn").(string) 68 users := expandStringList(d.Get("users").(*schema.Set).List()) 69 roles := expandStringList(d.Get("roles").(*schema.Set).List()) 70 groups := expandStringList(d.Get("groups").(*schema.Set).List()) 71 72 if len(users) == 0 && len(roles) == 0 && len(groups) == 0 { 73 return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for IAM Policy Attachment %s", name) 74 } else { 75 var userErr, roleErr, groupErr error 76 if users != nil { 77 userErr = attachPolicyToUsers(conn, users, arn) 78 } 79 if roles != nil { 80 roleErr = attachPolicyToRoles(conn, roles, arn) 81 } 82 if groups != nil { 83 groupErr = attachPolicyToGroups(conn, groups, arn) 84 } 85 if userErr != nil || roleErr != nil || groupErr != nil { 86 return composeErrors(fmt.Sprint("[WARN] Error attaching policy with IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) 87 } 88 } 89 d.SetId(d.Get("name").(string)) 90 return resourceAwsIamPolicyAttachmentRead(d, meta) 91 } 92 93 func resourceAwsIamPolicyAttachmentRead(d *schema.ResourceData, meta interface{}) error { 94 conn := meta.(*AWSClient).iamconn 95 arn := d.Get("policy_arn").(string) 96 name := d.Get("name").(string) 97 98 _, err := conn.GetPolicy(&iam.GetPolicyInput{ 99 PolicyArn: aws.String(arn), 100 }) 101 102 if err != nil { 103 if awsErr, ok := err.(awserr.Error); ok { 104 if awsErr.Code() == "NoSuchEntity" { 105 log.Printf("[WARN] No such entity found for Policy Attachment (%s)", d.Id()) 106 d.SetId("") 107 return nil 108 } 109 } 110 return err 111 } 112 113 ul := make([]string, 0) 114 rl := make([]string, 0) 115 gl := make([]string, 0) 116 117 args := iam.ListEntitiesForPolicyInput{ 118 PolicyArn: aws.String(arn), 119 } 120 err = conn.ListEntitiesForPolicyPages(&args, func(page *iam.ListEntitiesForPolicyOutput, lastPage bool) bool { 121 for _, u := range page.PolicyUsers { 122 ul = append(ul, *u.UserName) 123 } 124 125 for _, r := range page.PolicyRoles { 126 rl = append(rl, *r.RoleName) 127 } 128 129 for _, g := range page.PolicyGroups { 130 gl = append(gl, *g.GroupName) 131 } 132 return true 133 }) 134 if err != nil { 135 return err 136 } 137 138 userErr := d.Set("users", ul) 139 roleErr := d.Set("roles", rl) 140 groupErr := d.Set("groups", gl) 141 142 if userErr != nil || roleErr != nil || groupErr != nil { 143 return composeErrors(fmt.Sprint("[WARN} Error setting user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) 144 } 145 146 return nil 147 } 148 func resourceAwsIamPolicyAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { 149 conn := meta.(*AWSClient).iamconn 150 name := d.Get("name").(string) 151 var userErr, roleErr, groupErr error 152 153 if d.HasChange("users") { 154 userErr = updateUsers(conn, d, meta) 155 } 156 if d.HasChange("roles") { 157 roleErr = updateRoles(conn, d, meta) 158 } 159 if d.HasChange("groups") { 160 groupErr = updateGroups(conn, d, meta) 161 } 162 if userErr != nil || roleErr != nil || groupErr != nil { 163 return composeErrors(fmt.Sprint("[WARN] Error updating user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) 164 } 165 return resourceAwsIamPolicyAttachmentRead(d, meta) 166 } 167 168 func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error { 169 conn := meta.(*AWSClient).iamconn 170 name := d.Get("name").(string) 171 arn := d.Get("policy_arn").(string) 172 users := expandStringList(d.Get("users").(*schema.Set).List()) 173 roles := expandStringList(d.Get("roles").(*schema.Set).List()) 174 groups := expandStringList(d.Get("groups").(*schema.Set).List()) 175 176 var userErr, roleErr, groupErr error 177 if len(users) != 0 { 178 userErr = detachPolicyFromUsers(conn, users, arn) 179 } 180 if len(roles) != 0 { 181 roleErr = detachPolicyFromRoles(conn, roles, arn) 182 } 183 if len(groups) != 0 { 184 groupErr = detachPolicyFromGroups(conn, groups, arn) 185 } 186 if userErr != nil || roleErr != nil || groupErr != nil { 187 return composeErrors(fmt.Sprint("[WARN] Error removing user, role, or group list from IAM Policy Detach ", name, ":"), userErr, roleErr, groupErr) 188 } 189 return nil 190 } 191 192 func composeErrors(desc string, uErr error, rErr error, gErr error) error { 193 errMsg := fmt.Sprintf(desc) 194 errs := []error{uErr, rErr, gErr} 195 for _, e := range errs { 196 if e != nil { 197 errMsg = errMsg + "\n– " + e.Error() 198 } 199 } 200 return fmt.Errorf(errMsg) 201 } 202 203 func attachPolicyToUsers(conn *iam.IAM, users []*string, arn string) error { 204 for _, u := range users { 205 _, err := conn.AttachUserPolicy(&iam.AttachUserPolicyInput{ 206 UserName: u, 207 PolicyArn: aws.String(arn), 208 }) 209 if err != nil { 210 return err 211 } 212 } 213 return nil 214 } 215 func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error { 216 for _, r := range roles { 217 _, err := conn.AttachRolePolicy(&iam.AttachRolePolicyInput{ 218 RoleName: r, 219 PolicyArn: aws.String(arn), 220 }) 221 if err != nil { 222 return err 223 } 224 225 var attachmentErr error 226 attachmentErr = resource.Retry(2*time.Minute, func() *resource.RetryError { 227 228 input := iam.ListRolePoliciesInput{ 229 RoleName: r, 230 } 231 232 attachedPolicies, err := conn.ListRolePolicies(&input) 233 if err != nil { 234 return resource.NonRetryableError(err) 235 } 236 237 if len(attachedPolicies.PolicyNames) > 0 { 238 var foundPolicy bool 239 for _, policyName := range attachedPolicies.PolicyNames { 240 if strings.HasSuffix(arn, *policyName) { 241 foundPolicy = true 242 break 243 } 244 } 245 246 if !foundPolicy { 247 return resource.NonRetryableError(err) 248 } 249 } 250 251 return nil 252 }) 253 254 if attachmentErr != nil { 255 return attachmentErr 256 } 257 } 258 return nil 259 } 260 func attachPolicyToGroups(conn *iam.IAM, groups []*string, arn string) error { 261 for _, g := range groups { 262 _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicyInput{ 263 GroupName: g, 264 PolicyArn: aws.String(arn), 265 }) 266 if err != nil { 267 return err 268 } 269 } 270 return nil 271 } 272 func updateUsers(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { 273 arn := d.Get("policy_arn").(string) 274 o, n := d.GetChange("users") 275 if o == nil { 276 o = new(schema.Set) 277 } 278 if n == nil { 279 n = new(schema.Set) 280 } 281 os := o.(*schema.Set) 282 ns := n.(*schema.Set) 283 remove := expandStringList(os.Difference(ns).List()) 284 add := expandStringList(ns.Difference(os).List()) 285 286 if rErr := detachPolicyFromUsers(conn, remove, arn); rErr != nil { 287 return rErr 288 } 289 if aErr := attachPolicyToUsers(conn, add, arn); aErr != nil { 290 return aErr 291 } 292 return nil 293 } 294 func updateRoles(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { 295 arn := d.Get("policy_arn").(string) 296 o, n := d.GetChange("roles") 297 if o == nil { 298 o = new(schema.Set) 299 } 300 if n == nil { 301 n = new(schema.Set) 302 } 303 os := o.(*schema.Set) 304 ns := n.(*schema.Set) 305 remove := expandStringList(os.Difference(ns).List()) 306 add := expandStringList(ns.Difference(os).List()) 307 308 if rErr := detachPolicyFromRoles(conn, remove, arn); rErr != nil { 309 return rErr 310 } 311 if aErr := attachPolicyToRoles(conn, add, arn); aErr != nil { 312 return aErr 313 } 314 return nil 315 } 316 func updateGroups(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { 317 arn := d.Get("policy_arn").(string) 318 o, n := d.GetChange("groups") 319 if o == nil { 320 o = new(schema.Set) 321 } 322 if n == nil { 323 n = new(schema.Set) 324 } 325 os := o.(*schema.Set) 326 ns := n.(*schema.Set) 327 remove := expandStringList(os.Difference(ns).List()) 328 add := expandStringList(ns.Difference(os).List()) 329 330 if rErr := detachPolicyFromGroups(conn, remove, arn); rErr != nil { 331 return rErr 332 } 333 if aErr := attachPolicyToGroups(conn, add, arn); aErr != nil { 334 return aErr 335 } 336 return nil 337 338 } 339 func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) error { 340 for _, u := range users { 341 _, err := conn.DetachUserPolicy(&iam.DetachUserPolicyInput{ 342 UserName: u, 343 PolicyArn: aws.String(arn), 344 }) 345 if err != nil { 346 return err 347 } 348 } 349 return nil 350 } 351 func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) error { 352 for _, r := range roles { 353 _, err := conn.DetachRolePolicy(&iam.DetachRolePolicyInput{ 354 RoleName: r, 355 PolicyArn: aws.String(arn), 356 }) 357 if err != nil { 358 return err 359 } 360 } 361 return nil 362 } 363 func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) error { 364 for _, g := range groups { 365 _, err := conn.DetachGroupPolicy(&iam.DetachGroupPolicyInput{ 366 GroupName: g, 367 PolicyArn: aws.String(arn), 368 }) 369 if err != nil { 370 return err 371 } 372 } 373 return nil 374 }