Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with aws_iam_instance_profile roles #3851

Closed
davidblewett opened this issue Nov 10, 2015 · 21 comments
Closed

Problem with aws_iam_instance_profile roles #3851

davidblewett opened this issue Nov 10, 2015 · 21 comments

Comments

@davidblewett
Copy link

The documentation for aws_iam_instance_profile suggests that you can attach multiple roles to a given instance profile. However, when I did so I got the following error:

  • aws_iam_instance_profile.default: Error adding role dev_eyrie to IAM instance profile dev_eyrie: LimitExceeded: Cannot exceed quota for InstanceSessionsPerInstanceProfile: 1

I then looked up the documentation ( http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html ):

The following are the default maximums for IAM entities:
Roles in an instance profile: 1 (each instance profile can contain only 1 role)

What I needed to do instead was create multiple aws_iam_policy and attach them to a single role, which is then assigned in the aws_iam_instance_profile.

@davidblewett
Copy link
Author

Hmm, but there doesn't appear to be a way to apply an indeterminate number of policies to a given role. iam_policy_attachment is for a single policy, to multiple other users/groups/roles. I would like to be able to pass a list of policy IDs and attach them all to a single role.

I tried the following (using terraform 0.6.6):

resource "aws_iam_policy_attachment" "default" {
  count = "${var.iam_policy_count}"
  name = "${var.name_prefix}_attachment_${count.index}"
  roles = ["${aws_iam_role.default.arn}"]
  policy_arn = "${element(split(",", var.iam_policy_ids), count.index)}"
}

With the iam_policy_count being passed in like so:

iam_policy_count = "${length(split(",", var.iam_policy_ids))}"

But I get this error when running plan:

  • strconv.ParseInt: parsing "${var.iam_policy_count}": invalid syntax

@davidblewett
Copy link
Author

This could possibly be solved by #953. If the iam_policy_attachment resource doesn't support count, I can wrap it in a module and push in each policy ID via calls to element. It seems that iam_policy_attachment should support the count argument (maybe it does and there's just a bug in how it handles variable input?) .

I tried to invert the dependency chain, and attach policies to the instance role after the entire instance is created but ran into more problems. Different policies grant access to keys in S3 that are necessary during Chef provisioning. Since they wouldn't be granted until after the instance is created, Chef bails out with an HTTP 403 Forbidden when trying to download the secrets.

@jen20
Copy link
Contributor

jen20 commented Nov 11, 2015

I've hit this in the past as well - I think the documentation needs updating in the first instance to reflect the Amazon API docs, and then we should consider further whether to do something to make this easier on users.

@davidblewett
Copy link
Author

If the iam_policy_attachment supported variable-based counts, this issue could be resolved fairly cleanly. Failing that, the module-level count would work as well. As it is, I've had to resort to explicitly defining all expected policy IDs as independent variables. This works for my use case for now, as it appears there's a relatively small number that I need to bubble through. If I get into a spot where only a subset of applications should have some IDs, then I would be truly stuck and have to resort to something like a Jinja or Mako pre-processor.

@davidblewett
Copy link
Author

After refactoring my modules to pass around the policy ARNs, and do multiple calls to aws_iam_policy_attachment, it's now clear that this will not do what I want. It appears that multiple calls to aws_iam_policy_attachment for the same target role ID result in overwriting the previous attachments (instead of accumulating policy IDs, which is possible to do via the AWS UI/CLI).

This means that I will have to refactor again to instead build up a combined policy representation of all the items into a single policy statement and then attach this to the role. This is definitely not optimal; I am willing to test any potential fixes, but I don't have any experience with Go to help write them.

@davidblewett
Copy link
Author

Just for clarity's sake, the reason I want multiple, distinct IAM polices is to represent atomic permissions. This makes it possible to view in the console what roles have been assigned specific permissions. The model that the current state of Terraform resources seems to encourage is a role with inline policy granting multiple, unrelated statements granting access to different resources. This makes it very difficult to audit later, as you have to check every single role.

@antonbabenko
Copy link
Contributor

I also hit this issue today and wonder if anyone (ping @davidblewett) has figure out the way to add multiple roles into one aws_iam_instance_profile ?

@davidblewett
Copy link
Author

@antonbabenko: With the state of the code in 0.6.6, it is not possible. What I did instead was do inline-policy declarations. I do one inline-policy ( via aws_iam_role_policy: https://www.terraform.io/docs/providers/aws/r/iam_role_policy.html ), that grants every instance access to baseline secrets. Then if a particular instance needs extra grants, I use aws_iam_policy + in-line policy and aws_iam_policy_attachment.

IMHO, this is not a good long-term solution as it makes auditing (from standard AWS tools) who has access to what much more difficult.

@antonbabenko
Copy link
Contributor

@davidblewett I did exactly the same today. Thank you!

@conorgil
Copy link

I just hit this same issue using v0.6.9.

What I am trying to accomplish is attaching multiple iam_roles to a single iam_instance_profile. All of my EC2 instances need to be able to publish events to AWS Cloudwatch Logs in addition to their application specific access requirements. My approach was to define a single central iam_role called awslogs_iam_role, which would allow the instance to publish events to the Cloudwatch Logs API.

resource "aws_iam_instance_profile" "my_application_iam_instance_profile" {
    name = "my_application_iam_instance_profile"
    roles = ["my_application_iam_role", "awslogs_iam_role"]
}

This blows up with the same error as @davidblewett shared in his opening comment.

The terraform documentation defines a required roles param as a list and shows an example:

# Example Usage
resource "aws_iam_instance_profile" "test_profile" {
    name = "test_profile"
    roles = ["${aws_iam_role.role.name}"]
}

# Argument Reference
roles - (Required) A list of role names to include in the profile.

Isn't Terraform simply incorrect and the roles field should really just be a role field to accept a single iam_role?

The AWS documentation on Using Instance Profiles says:

Note
An instance profile can contain only one IAM role. However, a role can be included in multiple instance profiles.

and Limitations on IAM Entities and Objects says:

Roles in an instance profile: 1 (each instance profile can contain only 1 role)

This sounds like an AWS limitation which Terraform would not be able to solve for me if I am reading the AWS documentation correctly. Am I missing something?

@davidblewett
Copy link
Author

@conorgil Yes, an instance may only have a single IAM role. However, that single IAM role can have multiple policy statements attached to it. You can also attach a complete policy statement in-line for that role, that can have multiple grants in it. Terraform supports the latter, but does not support the former currently.

IMO, the latter (while effective) is not preferable because it becomes more complicated to audit. Instead of being able to look at a single policy statement and being able to tell all the roles that were granted it, you have to check every role's in-line statement to see if it contains the permission.

@conorgil
Copy link

@davidblewett thanks for the info. Actually, Terraform can support creating multiple inline policies in a single IAM Role. See this gist for the general approach I took.

I was debating whether or not to reply with my novel here since the following comments are not exclusively Terraform related, but I decided that others who might be having this same issue would benefit from the general discussion and it could also impact what/how Terraform supports IAM related roles and policies. Apologies if this is too long and/or off topic.

I have had a pretty difficult time wrapping my head around how to implement my IAM roles and policies in Terraform, but I believe the fault really lies with AWS because of the difference between how AWS handles IAM roles in the AWS Console versus in the API. In the Console, you can visit IAM > Roles and it shows you a list of IAM Roles which you can apply to an EC2 instance as you launch it. However, that is misleading because, as the documentation on Using Instance Profiles states:

Managing Instance Profiles using the AWS Management Console

If you use the AWS Management Console to create a role, the console automatically
creates an instance profile and gives it the same name as the role. When you then
use the Amazon EC2 console to launch an instance with an IAM role, you can select
a role to associate with the instance. In the console, the list that's displayed is
actually a list of instance profile names.

This discrepancy made grokking the Terraform implementation much more difficult for me because I had previously been using the AWS Console to create my IAM Roles and I did not understand what an iam_instance_profile was. Because the Terraform documentation lists the roles field as a list, I assumed that I could create an iam_instance_profile, which would use multiple roles; one for my application specific policies and one for a general AWS Cloudwatch Logs policy. However, as has been explained previously in this thread, that does not work because AWS only allows an iam_instance_profile to contain a single iam_role.

That brings to light two questions in my mind:

  1. As asked above, why does Terraform require a list type for the roles field in the iam_instance_profile resource since only a single role is supported by the AWS API? @jen20 Any thoughts/comments on that?
  2. Why does AWS even have the iam_instance_profile resource if it can only have a single role? Seems pretty superfluous to me. The AWS Console doesn't even really support the concept, so why not just ditch it and simplify things so that we assign an iam_role to an EC2 instance when launching instead of assigning an iam_instance_profile? I realize Terraform is not AWS, so I don't expect an actual answer, but wanted to throw it out there.

As @davidblewett mentioned in his previous comment, the AWS API allows you to add multiple policies to a single iam_role. The Console view of an IAM Role shows the managed and inline policies associated with the role. The AWS CLI supports putting new policies into a role and listing existing policies on a role. So, instead of applying multiple iam_roles to a single iam_instance_profile, the approach would instead be to apply multiple iam_role_policys to a single iam_role.

Basically, I define each shared iam_role_policy in a module, which I then reference for each iam_role which requires those permissions. I outline my general approach in this gist, which I also shared above.

@pll
Copy link

pll commented Feb 12, 2016

@conorgil - Thank you so much for dropping your novel in here! HUGE help!

@portovep
Copy link
Contributor

@conorgil thanks a lot for the explanation!

We switched to use aws_iam_policy instead of aws_iam_role_policy so that we can use iam_policy_attachment to attach a specific policy to several roles at once.

@simonvanderveldt
Copy link

As asked above, why does Terraform require a list type for the roles field in the iam_instance_profile resource since only a single role is supported by the AWS API? @jen20 Any thoughts/comments on that?

@conorgil Terraform just mimics what AWS offers us, which actually is the key roles (plural) which expects a list.
https://docs.aws.amazon.com/cli/latest/reference/iam/create-instance-profile.html#examples

I've asked AWS support why this is and if it's somehow possible to add more roles to an instance profile.

What I don't like about iam_policy_attachment is that it attaches the permission from the roles instead of defining within a role which policies shoud be attached. This makes it difficult to get a quick overview of which policies are attached to a role.

@simonvanderveldt
Copy link

Received an answer from AWS, and it's currently not possible to add more than 1 role to an instance profile. Response from AWS quoted below:

I received feedback from our service team and they advised that it is not possible to attach more than one role to your instance profiles. We are aware of this request and will consider when planning for future releases.

I'd advise to raise a support ticket with AWS if you'd like this to be possible to make sure it's on their radar.

@portovep
Copy link
Contributor

portovep commented Mar 3, 2016

Thanks @simonvanderveldt. I agree, having the policies declared in the role is nicer.

@peterticketfly
Copy link

peterticketfly commented Jul 15, 2016

Fell into the same trap and found this issue, Hashicorp really needs to clarify aws_iam_instance_profile.roles

I assume they are just following cloudformation:

Type: List of references to AWS::IAM::Roles. Currently, a maximum of one role can be assigned to an instance profile.

@jen20
Copy link
Contributor

jen20 commented Sep 29, 2016

Hi @davidblewett et al! I just hit this again (a year later...). I'll pick this up and work out what to do with it - the reasons this uses the name "Roles" is because that is what the underlying API uses and we try not to deviate from it.

In this case however I think it is confusing that we don't make it clearer what can be expected from this API. The documentation makes it clear that only one role is allowed in an instance profile and experimenting with the command line interface suggests the same.

My initial suggestion is to deprecate roles and introduce role as a string. Does anyone have any strong opinions that we should take a different approach?

@stack72
Copy link
Contributor

stack72 commented Apr 18, 2017

Hi all

I have deprecated the use of roles and replaced with role

This is now live and I am going to close this issue

Thanks

Paul

@stack72 stack72 closed this as completed Apr 18, 2017
@ghost
Copy link

ghost commented Apr 13, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Apr 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants