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