github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/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 policyEntities, err := conn.ListEntitiesForPolicy(&iam.ListEntitiesForPolicyInput{ 107 PolicyArn: aws.String(arn), 108 }) 109 110 if err != nil { 111 return err 112 } 113 114 ul := make([]string, 0, len(policyEntities.PolicyUsers)) 115 rl := make([]string, 0, len(policyEntities.PolicyRoles)) 116 gl := make([]string, 0, len(policyEntities.PolicyGroups)) 117 118 for _, u := range policyEntities.PolicyUsers { 119 ul = append(ul, *u.UserName) 120 } 121 122 for _, r := range policyEntities.PolicyRoles { 123 rl = append(rl, *r.RoleName) 124 } 125 126 for _, g := range policyEntities.PolicyGroups { 127 gl = append(gl, *g.GroupName) 128 } 129 130 userErr := d.Set("users", ul) 131 roleErr := d.Set("roles", rl) 132 groupErr := d.Set("groups", gl) 133 134 if userErr != nil || roleErr != nil || groupErr != nil { 135 return composeErrors(fmt.Sprint("[WARN} Error setting user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) 136 } 137 138 return nil 139 } 140 func resourceAwsIamPolicyAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { 141 conn := meta.(*AWSClient).iamconn 142 name := d.Get("name").(string) 143 var userErr, roleErr, groupErr error 144 145 if d.HasChange("users") { 146 userErr = updateUsers(conn, d, meta) 147 } 148 if d.HasChange("roles") { 149 roleErr = updateRoles(conn, d, meta) 150 } 151 if d.HasChange("groups") { 152 groupErr = updateGroups(conn, d, meta) 153 } 154 if userErr != nil || roleErr != nil || groupErr != nil { 155 return composeErrors(fmt.Sprint("[WARN] Error updating user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr) 156 } 157 return resourceAwsIamPolicyAttachmentRead(d, meta) 158 } 159 160 func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error { 161 conn := meta.(*AWSClient).iamconn 162 name := d.Get("name").(string) 163 arn := d.Get("policy_arn").(string) 164 users := expandStringList(d.Get("users").(*schema.Set).List()) 165 roles := expandStringList(d.Get("roles").(*schema.Set).List()) 166 groups := expandStringList(d.Get("groups").(*schema.Set).List()) 167 168 var userErr, roleErr, groupErr error 169 if len(users) != 0 { 170 userErr = detachPolicyFromUsers(conn, users, arn) 171 } 172 if len(roles) != 0 { 173 roleErr = detachPolicyFromRoles(conn, roles, arn) 174 } 175 if len(groups) != 0 { 176 groupErr = detachPolicyFromGroups(conn, groups, arn) 177 } 178 if userErr != nil || roleErr != nil || groupErr != nil { 179 return composeErrors(fmt.Sprint("[WARN] Error removing user, role, or group list from IAM Policy Detach ", name, ":"), userErr, roleErr, groupErr) 180 } 181 return nil 182 } 183 184 func composeErrors(desc string, uErr error, rErr error, gErr error) error { 185 errMsg := fmt.Sprintf(desc) 186 errs := []error{uErr, rErr, gErr} 187 for _, e := range errs { 188 if e != nil { 189 errMsg = errMsg + "\n– " + e.Error() 190 } 191 } 192 return fmt.Errorf(errMsg) 193 } 194 195 func attachPolicyToUsers(conn *iam.IAM, users []*string, arn string) error { 196 for _, u := range users { 197 _, err := conn.AttachUserPolicy(&iam.AttachUserPolicyInput{ 198 UserName: u, 199 PolicyArn: aws.String(arn), 200 }) 201 if err != nil { 202 return err 203 } 204 } 205 return nil 206 } 207 func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error { 208 for _, r := range roles { 209 _, err := conn.AttachRolePolicy(&iam.AttachRolePolicyInput{ 210 RoleName: r, 211 PolicyArn: aws.String(arn), 212 }) 213 if err != nil { 214 return err 215 } 216 217 var attachmentErr error 218 attachmentErr = resource.Retry(2*time.Minute, func() *resource.RetryError { 219 220 input := iam.ListRolePoliciesInput{ 221 RoleName: r, 222 } 223 224 attachedPolicies, err := conn.ListRolePolicies(&input) 225 if err != nil { 226 return resource.NonRetryableError(err) 227 } 228 229 if len(attachedPolicies.PolicyNames) > 0 { 230 var foundPolicy bool 231 for _, policyName := range attachedPolicies.PolicyNames { 232 if strings.HasSuffix(arn, *policyName) { 233 foundPolicy = true 234 break 235 } 236 } 237 238 if !foundPolicy { 239 return resource.NonRetryableError(err) 240 } 241 } 242 243 return nil 244 }) 245 246 if attachmentErr != nil { 247 return attachmentErr 248 } 249 } 250 return nil 251 } 252 func attachPolicyToGroups(conn *iam.IAM, groups []*string, arn string) error { 253 for _, g := range groups { 254 _, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicyInput{ 255 GroupName: g, 256 PolicyArn: aws.String(arn), 257 }) 258 if err != nil { 259 return err 260 } 261 } 262 return nil 263 } 264 func updateUsers(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { 265 arn := d.Get("policy_arn").(string) 266 o, n := d.GetChange("users") 267 if o == nil { 268 o = new(schema.Set) 269 } 270 if n == nil { 271 n = new(schema.Set) 272 } 273 os := o.(*schema.Set) 274 ns := n.(*schema.Set) 275 remove := expandStringList(os.Difference(ns).List()) 276 add := expandStringList(ns.Difference(os).List()) 277 278 if rErr := detachPolicyFromUsers(conn, remove, arn); rErr != nil { 279 return rErr 280 } 281 if aErr := attachPolicyToUsers(conn, add, arn); aErr != nil { 282 return aErr 283 } 284 return nil 285 } 286 func updateRoles(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { 287 arn := d.Get("policy_arn").(string) 288 o, n := d.GetChange("roles") 289 if o == nil { 290 o = new(schema.Set) 291 } 292 if n == nil { 293 n = new(schema.Set) 294 } 295 os := o.(*schema.Set) 296 ns := n.(*schema.Set) 297 remove := expandStringList(os.Difference(ns).List()) 298 add := expandStringList(ns.Difference(os).List()) 299 300 if rErr := detachPolicyFromRoles(conn, remove, arn); rErr != nil { 301 return rErr 302 } 303 if aErr := attachPolicyToRoles(conn, add, arn); aErr != nil { 304 return aErr 305 } 306 return nil 307 } 308 func updateGroups(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error { 309 arn := d.Get("policy_arn").(string) 310 o, n := d.GetChange("groups") 311 if o == nil { 312 o = new(schema.Set) 313 } 314 if n == nil { 315 n = new(schema.Set) 316 } 317 os := o.(*schema.Set) 318 ns := n.(*schema.Set) 319 remove := expandStringList(os.Difference(ns).List()) 320 add := expandStringList(ns.Difference(os).List()) 321 322 if rErr := detachPolicyFromGroups(conn, remove, arn); rErr != nil { 323 return rErr 324 } 325 if aErr := attachPolicyToGroups(conn, add, arn); aErr != nil { 326 return aErr 327 } 328 return nil 329 330 } 331 func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) error { 332 for _, u := range users { 333 _, err := conn.DetachUserPolicy(&iam.DetachUserPolicyInput{ 334 UserName: u, 335 PolicyArn: aws.String(arn), 336 }) 337 if err != nil { 338 return err 339 } 340 } 341 return nil 342 } 343 func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) error { 344 for _, r := range roles { 345 _, err := conn.DetachRolePolicy(&iam.DetachRolePolicyInput{ 346 RoleName: r, 347 PolicyArn: aws.String(arn), 348 }) 349 if err != nil { 350 return err 351 } 352 } 353 return nil 354 } 355 func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) error { 356 for _, g := range groups { 357 _, err := conn.DetachGroupPolicy(&iam.DetachGroupPolicyInput{ 358 GroupName: g, 359 PolicyArn: aws.String(arn), 360 }) 361 if err != nil { 362 return err 363 } 364 } 365 return nil 366 }