1

I have an EC2 Ubuntu host, where I have a single user account responsible for running different tasks at different times. Each task requires particular permissions represented by a corresponding IAM role (I call them "profile roles"). The idea is to grant this user a permission to assume these roles, when needed.

For now, the ~/.aws/credentials configuration looks as follows:

[default]
aws_access_key_id = XXX
aws_secret_access_key = YYY

[profile1]
role_arn = arn:aws:iam::XXXXXXXXXX:role/role-for-profile1
source_profile = default

[profile2]
role_arn = arn:aws:iam::XXXXXXXXXX:role/role-for-profile2
source_profile = default

...

[profileN]
role_arn = arn:aws:iam::XXXXXXXXXX:role/role-for-profileN
source_profile = default

The user in default profile has a single permission: to assume any role that starts with role-for-profile. The policy JSON looks as follows:

{
  "Version": "2012-10-17",
  "Statement": [
    {
        "Sid": "Stmt1494333413000",
        "Effect": "Allow",
        "Action": [
            "sts:AssumeRole"
        ],
        "Resource": [
            "arn:aws:iam::XXXXXXXXXX:role/role-for-profile*"
        ]
    }
  ]
}

Thus, any application who needs to access specific AWS services in order to perform a specific task (no matter whether it uses AWS CLI, or Boto, or Ansible modules, or whatever) can just specify a profile name and assume the required profile role transparently.

Now my concern is: since this is running on an EC2 host, I don't need to explicitly put any credentials to this host at all. In theory, I could just attach the "master" IAM role directly to the EC2 host instead of creating a user, granting it switching role permission, and explicitly putting its credentials into default profile.

However, I can't seem to do that, as source_profile parameter is mandatory. Does anyone have an idea, how could I authorize the EC2 host assume roles without giving it any credentials? In other words, I want the host to authenticate by principle "something I am" (an EC2 instance with a given IAM role), not "something I know" (explicitly supplied access key and secret key of an IAM user).

UPDATE. Found a couple of feature requests - looks like this is not supported yet :(

UPDATE2. It looks like I need to clarify the purpose of this setup. I have different scripts that run on the same hosts (may be even in parallel). Each script requires a specific set of permissions. What I want to achieve, is that each script had only this set of permission, and not more than that. In my view, the best way to achieve this is as follows:

  1. On host level provide no permissions at all, except for a permission to assume a number of specific roles.
  2. When a script starts working, it needs to assume a corresponding role in order to get required permissions.
  3. At the same time, I don't want to bake the role ARN into the script. Instead, I'd like to define a number of profiles in ~/.aws/credentials, each defined to assume a particular role.

I have no problems with the first two items. However, implementing the third one requires me to create a "default" profile that other profiles will use as a reference, and this "default" profile for some reason has to have a user's credentials. What I'd like is to refer to the role attached to the EC2 instance where all this stuff is running.

5
  • That's an interesting solution. Are they scripts you wrote? It could be easier to write and test the scripts properly than to get this technique working.
    – Tim
    May 14, 2017 at 19:31
  • The scripts are "homebred", and they are under version control. Yet no matter where they come from, hardcoding any role ARNs (not to mention credentials) into them looks like a bad practice to me. Moreover, that's exactly what profiles in ~/.aws/credentials are for - this decouples access control logic from execution logic. That is, you write AWS_PROFILE=profileN before running the script, and you are good. However, I still don't see why one can define a role-based profile with reference to a credentials-based profile, but at the same time can't do it with reference to EC2 instance role. May 15, 2017 at 8:01
  • I forgot to mention that putting all permissions for all scripts into a single role seems to me an even worse practice - from both security and maintainability standpoint :) May 15, 2017 at 8:04
  • Have you tried putting wrong/fake credentials in there.i have just switched from storing credentials on server to using a role and emptied the access key lines
    – jdog
    May 18, 2017 at 9:04
  • Just tried, but getting an error. It's either aws_access_key_id missing if I completely wipe the access key lines, or invalid credentials if I put wrong credentials. Can you explain in more detail how you got it to work? May 19, 2017 at 10:02

4 Answers 4

1

I have been trying to solve the same issue. The closest thing I've been able to find is this gist: https://gist.github.com/gene1wood/34b02fa3091e184e1997

It uses the aws sts assume-role command to get a temporary set of credentials (expires in 60 minutes by default). I supposed you could use this script to get temporary credentials for the role assigned to the EC2 instances and update the AWS access key and AWS secret key for the "default" profile. Since the temporary credentials expire every hour you would need a cron job to update them on a regular basis.

Kind of an ugly hack but until it is suported I think it has a good chance of working.

1
  • Thank you, that worked! Since my script is Boto-based, I didn't need the aaws aliasing part, therefore I simply replaced it with exporting environment variables (access key ID and all the secrets). Before running my script I just source yours, and everything works like a charm! Jun 26, 2017 at 11:26
1

AWS only lets you assign one role to an EC2 instance. That role should have all the permissions that the EC2 instance may need to assume. Reference.

You can change roles assigned to an instance using the command line, but it's not something you want to do regularly, at runtime.

3
  • I'm sorry, but you seem to be missing the point of the question. Everything you said is correct, except for the second sentence: "That role should have all the permissions that the EC2 instance may need to assume". This is not true. The role attached to the EC2 instance may have just one permission: to assume other roles. This works perfectly when I want to assume a role directly by its name, e.g. in Boto: sts_conn.assume_role('arn:aws:iam::XXXXXXXXXX:role/role-for-profile1', 'profile1'). My problem is that I can't hide the ARN behind an AWS profile. May 13, 2017 at 18:35
  • Agree, but the role the instance assumes can have any number of permissions. That means the EC2 instance can be given permission for anything based on one IAM role. Can you describe why you've split things up like you have, your business / user case? Suggest the best way to do that is to edit the question then comment to let me know it's done.
    – Tim
    May 13, 2017 at 22:29
  • Added another update with explanation what I'm trying to achieve. May 14, 2017 at 12:10
1

This now works. Detailed instructions here: https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#using-aws-iam-roles

See update in issue from Oct/Dec 2018: https://github.com/aws/aws-cli/issues/1390

1
  • 2
    Thanks for providing an answer. SF prefers people write useful content in the message, as links can go stale, reducing the future value of answers. Perhaps you could edit your answer to flesh it out a bit?
    – Tim
    Feb 5, 2019 at 0:45
0

Attach the 'default' role as the primary role for the instance. This avoids the need for credentials on your default profile.

Create non default profiles with credentials for the other roles.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .