terraform/builtin/providers/aws/resource_aws_iam_policy_att...

375 lines
9.7 KiB
Go
Raw Normal View History

package aws
import (
2015-06-17 16:56:33 +02:00
"fmt"
"log"
2016-02-01 23:32:38 +01:00
"strings"
"time"
2015-06-17 16:56:33 +02:00
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/iam"
2016-02-01 23:32:38 +01:00
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)
2015-06-17 16:56:33 +02:00
func resourceAwsIamPolicyAttachment() *schema.Resource {
return &schema.Resource{
Create: resourceAwsIamPolicyAttachmentCreate,
Read: resourceAwsIamPolicyAttachmentRead,
Update: resourceAwsIamPolicyAttachmentUpdate,
Delete: resourceAwsIamPolicyAttachmentDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
if v.(string) == "" {
errors = append(errors, fmt.Errorf(
"%q cannot be an empty string", k))
}
return
},
2015-06-17 16:56:33 +02:00
},
"users": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"roles": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"groups": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"policy_arn": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}
2015-06-17 16:56:33 +02:00
func resourceAwsIamPolicyAttachmentCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).iamconn
name := d.Get("name").(string)
arn := d.Get("policy_arn").(string)
users := expandStringList(d.Get("users").(*schema.Set).List())
roles := expandStringList(d.Get("roles").(*schema.Set).List())
groups := expandStringList(d.Get("groups").(*schema.Set).List())
if len(users) == 0 && len(roles) == 0 && len(groups) == 0 {
return fmt.Errorf("[WARN] No Users, Roles, or Groups specified for IAM Policy Attachment %s", name)
2015-06-17 16:56:33 +02:00
} else {
var userErr, roleErr, groupErr error
if users != nil {
userErr = attachPolicyToUsers(conn, users, arn)
}
if roles != nil {
roleErr = attachPolicyToRoles(conn, roles, arn)
}
if groups != nil {
groupErr = attachPolicyToGroups(conn, groups, arn)
}
if userErr != nil || roleErr != nil || groupErr != nil {
return composeErrors(fmt.Sprint("[WARN] Error attaching policy with IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr)
2015-06-17 16:56:33 +02:00
}
}
2015-06-17 21:21:41 +02:00
d.SetId(d.Get("name").(string))
2015-06-17 16:56:33 +02:00
return resourceAwsIamPolicyAttachmentRead(d, meta)
}
2015-06-17 21:21:41 +02:00
2015-06-17 16:56:33 +02:00
func resourceAwsIamPolicyAttachmentRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).iamconn
arn := d.Get("policy_arn").(string)
name := d.Get("name").(string)
_, err := conn.GetPolicy(&iam.GetPolicyInput{
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "NoSuchEntity" {
log.Printf("[WARN] No such entity found for Policy Attachment (%s)", d.Id())
2015-06-17 16:56:33 +02:00
d.SetId("")
return nil
}
}
return err
}
ul := make([]string, 0)
rl := make([]string, 0)
gl := make([]string, 0)
2015-06-17 16:56:33 +02:00
args := iam.ListEntitiesForPolicyInput{
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
}
err = conn.ListEntitiesForPolicyPages(&args, func(page *iam.ListEntitiesForPolicyOutput, lastPage bool) bool {
for _, u := range page.PolicyUsers {
ul = append(ul, *u.UserName)
}
for _, r := range page.PolicyRoles {
rl = append(rl, *r.RoleName)
}
for _, g := range page.PolicyGroups {
gl = append(gl, *g.GroupName)
}
return true
})
if err != nil {
return err
2015-06-17 16:56:33 +02:00
}
userErr := d.Set("users", ul)
roleErr := d.Set("roles", rl)
groupErr := d.Set("groups", gl)
if userErr != nil || roleErr != nil || groupErr != nil {
return composeErrors(fmt.Sprint("[WARN} Error setting user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr)
2015-06-17 16:56:33 +02:00
}
return nil
}
func resourceAwsIamPolicyAttachmentUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).iamconn
name := d.Get("name").(string)
var userErr, roleErr, groupErr error
if d.HasChange("users") {
userErr = updateUsers(conn, d, meta)
}
if d.HasChange("roles") {
roleErr = updateRoles(conn, d, meta)
}
if d.HasChange("groups") {
groupErr = updateGroups(conn, d, meta)
}
if userErr != nil || roleErr != nil || groupErr != nil {
return composeErrors(fmt.Sprint("[WARN] Error updating user, role, or group list from IAM Policy Attachment ", name, ":"), userErr, roleErr, groupErr)
2015-06-17 16:56:33 +02:00
}
2015-06-17 21:21:41 +02:00
return resourceAwsIamPolicyAttachmentRead(d, meta)
}
2015-06-17 21:21:41 +02:00
2015-06-17 16:56:33 +02:00
func resourceAwsIamPolicyAttachmentDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).iamconn
name := d.Get("name").(string)
arn := d.Get("policy_arn").(string)
users := expandStringList(d.Get("users").(*schema.Set).List())
roles := expandStringList(d.Get("roles").(*schema.Set).List())
groups := expandStringList(d.Get("groups").(*schema.Set).List())
2015-06-17 16:56:33 +02:00
var userErr, roleErr, groupErr error
if len(users) != 0 {
2015-06-17 16:56:33 +02:00
userErr = detachPolicyFromUsers(conn, users, arn)
}
if len(roles) != 0 {
2015-06-17 16:56:33 +02:00
roleErr = detachPolicyFromRoles(conn, roles, arn)
}
if len(groups) != 0 {
2015-06-17 16:56:33 +02:00
groupErr = detachPolicyFromGroups(conn, groups, arn)
}
if userErr != nil || roleErr != nil || groupErr != nil {
return composeErrors(fmt.Sprint("[WARN] Error removing user, role, or group list from IAM Policy Detach ", name, ":"), userErr, roleErr, groupErr)
2015-06-17 16:56:33 +02:00
}
return nil
}
func composeErrors(desc string, uErr error, rErr error, gErr error) error {
errMsg := fmt.Sprintf(desc)
errs := []error{uErr, rErr, gErr}
for _, e := range errs {
if e != nil {
errMsg = errMsg + "\n " + e.Error()
}
}
return fmt.Errorf(errMsg)
}
2015-06-17 16:56:33 +02:00
func attachPolicyToUsers(conn *iam.IAM, users []*string, arn string) error {
for _, u := range users {
_, err := conn.AttachUserPolicy(&iam.AttachUserPolicyInput{
UserName: u,
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
return err
}
}
return nil
}
2015-06-17 16:56:33 +02:00
func attachPolicyToRoles(conn *iam.IAM, roles []*string, arn string) error {
for _, r := range roles {
_, err := conn.AttachRolePolicy(&iam.AttachRolePolicyInput{
RoleName: r,
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
return err
}
2016-02-01 23:32:38 +01:00
var attachmentErr error
attachmentErr = resource.Retry(2*time.Minute, func() *resource.RetryError {
2016-02-01 23:32:38 +01:00
input := iam.ListRolePoliciesInput{
RoleName: r,
}
attachedPolicies, err := conn.ListRolePolicies(&input)
if err != nil {
return resource.NonRetryableError(err)
2016-02-01 23:32:38 +01:00
}
if len(attachedPolicies.PolicyNames) > 0 {
var foundPolicy bool
for _, policyName := range attachedPolicies.PolicyNames {
if strings.HasSuffix(arn, *policyName) {
foundPolicy = true
break
}
}
if !foundPolicy {
return resource.NonRetryableError(err)
2016-02-01 23:32:38 +01:00
}
}
return nil
})
if attachmentErr != nil {
return attachmentErr
}
2015-06-17 16:56:33 +02:00
}
return nil
}
2015-06-17 16:56:33 +02:00
func attachPolicyToGroups(conn *iam.IAM, groups []*string, arn string) error {
for _, g := range groups {
_, err := conn.AttachGroupPolicy(&iam.AttachGroupPolicyInput{
GroupName: g,
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
return err
}
}
return nil
}
func updateUsers(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error {
arn := d.Get("policy_arn").(string)
o, n := d.GetChange("users")
if o == nil {
o = new(schema.Set)
}
if n == nil {
n = new(schema.Set)
}
os := o.(*schema.Set)
ns := n.(*schema.Set)
remove := expandStringList(os.Difference(ns).List())
add := expandStringList(ns.Difference(os).List())
if rErr := detachPolicyFromUsers(conn, remove, arn); rErr != nil {
return rErr
}
if aErr := attachPolicyToUsers(conn, add, arn); aErr != nil {
return aErr
}
return nil
}
func updateRoles(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error {
arn := d.Get("policy_arn").(string)
o, n := d.GetChange("roles")
if o == nil {
o = new(schema.Set)
}
if n == nil {
n = new(schema.Set)
}
os := o.(*schema.Set)
ns := n.(*schema.Set)
remove := expandStringList(os.Difference(ns).List())
add := expandStringList(ns.Difference(os).List())
2015-06-17 16:56:33 +02:00
if rErr := detachPolicyFromRoles(conn, remove, arn); rErr != nil {
return rErr
}
if aErr := attachPolicyToRoles(conn, add, arn); aErr != nil {
return aErr
}
return nil
}
2015-06-17 16:56:33 +02:00
func updateGroups(conn *iam.IAM, d *schema.ResourceData, meta interface{}) error {
arn := d.Get("policy_arn").(string)
o, n := d.GetChange("groups")
if o == nil {
o = new(schema.Set)
}
if n == nil {
n = new(schema.Set)
}
os := o.(*schema.Set)
ns := n.(*schema.Set)
remove := expandStringList(os.Difference(ns).List())
add := expandStringList(ns.Difference(os).List())
if rErr := detachPolicyFromGroups(conn, remove, arn); rErr != nil {
return rErr
}
if aErr := attachPolicyToGroups(conn, add, arn); aErr != nil {
return aErr
}
return nil
}
2015-06-17 16:56:33 +02:00
func detachPolicyFromUsers(conn *iam.IAM, users []*string, arn string) error {
for _, u := range users {
_, err := conn.DetachUserPolicy(&iam.DetachUserPolicyInput{
UserName: u,
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
return err
}
}
return nil
}
2015-06-17 16:56:33 +02:00
func detachPolicyFromRoles(conn *iam.IAM, roles []*string, arn string) error {
for _, r := range roles {
_, err := conn.DetachRolePolicy(&iam.DetachRolePolicyInput{
RoleName: r,
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
return err
}
}
return nil
}
2015-06-17 16:56:33 +02:00
func detachPolicyFromGroups(conn *iam.IAM, groups []*string, arn string) error {
for _, g := range groups {
_, err := conn.DetachGroupPolicy(&iam.DetachGroupPolicyInput{
GroupName: g,
PolicyArn: aws.String(arn),
2015-06-17 16:56:33 +02:00
})
if err != nil {
return err
}
}
return nil
}