github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/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  }