37
votes

I want to attach multiple IAM Policy ARNs to a single IAM Role.

One method is to create a new policy with privileges of all the policies (multiple policies).

But in AWS, we have some predefined IAM policies like AmazonEC2FullAccess, AmazomS3FullAccess, etc. I want to use a combination of these for my role.

I could not find a way to do so in the Terraform documentation.

As per documentation we can use aws_iam_role_policy_attachment to attach a policy to a role, but not multiple policies to a role as this is available via AWS console.

Please let me know if there is a method to do the same or is it still a feature to be added.

The Terraform version I use is v0.9.5

5

5 Answers

38
votes

Thanks Krishna Kumar R for the hint.

A little more polished answer I reached from your answer.

# Define policy ARNs as list
variable "iam_policy_arn" {
  description = "IAM Policy to be attached to role"
  type = "list"
}

# Then parse through the list using count
resource "aws_iam_role_policy_attachment" "role-policy-attachment" {
  role       = "${var.iam_role_name}"
  count      = "${length(var.iam_policy_arn)}"
  policy_arn = "${var.iam_policy_arn[count.index]}"
}

And finally the list of policies should be specified in *.tfvars file or in command line using -var, for example:

iam_policy_arn = [ "arn:aws:iam::aws:policy/AmazonEC2FullAccess", "arn:aws:iam::aws:policy/AmazonS3FullAccess"]

26
votes

For Terraform versions >= 0.12 the cleanest way to add multiple policies is probably something like this:

resource "aws_iam_role_policy_attachment" "role-policy-attachment" {
  for_each = toset([
    "arn:aws:iam::aws:policy/AmazonEC2FullAccess", 
    "arn:aws:iam::aws:policy/AmazonS3FullAccess"
  ])

  role       = var.iam_role_name
  policy_arn = each.value
}

As described in Pranshu Verma's answer, the list of policies can also be put into a variable.

Using for_each in favor of count has the advantage, that insertions to the list are properly recognized by terraform so that it would really only add one policy, while with count all policies after the insertion would be changed (this is described in detail in this blog post)

23
votes

Did you try something like this:

resource "aws_iam_role" "iam_role_name" {
  name = "iam_role_name"
}

resource "aws_iam_role_policy_attachment" "mgd_pol_1" {
  name       = "mgd_pol_attach_name"
  role       = "${aws_iam_role.iam_role_name.name}"
  policy_arn = "${aws_iam_policy.mgd_pol_1.arn}"
}

resource "aws_iam_role_policy_attachment" "mgd_pol_2" {
  name       = "mgd_pol_attach_name"
  role       = "${aws_iam_role.iam_role_name.name}"
  policy_arn = "${aws_iam_policy.mgd_pol_2.arn}"
}
2
votes

Adding another option, which is similar to the excepted answer but instead of:

policy_arn = "${var.iam_policy_arn[count.index]}"

You can use the element function:

policy_arn = "${element(var.iam_policy_arn,count.index)}"

I think that in some cases (like a project with a large amount of code) this could be more readable.

0
votes

This is an example how i did it:

resource "aws_iam_group_policy_attachment" "policy_attach_example" {
  for_each   = aws_iam_policy.example
  group      = aws_iam_group.example.name
  policy_arn = each.value["arn"]
}

So basically "aws_iam_policy.example" is a list of policies that i have made in the same way, with for_each

Hope that this help you, i know i come late but i had this simillar issue