0

What works

We have several EC2 instances that pull things out of an S3 bucket on boot (and at other times). To allow this, we have an IAM policy granting read-only access...

"Effect": "Allow",
"Action": [
    "s3:ListBucket"
],
"Resource": [
    "arn:aws:s3:::BUCKET"
]

"Effect": "Allow",
"Action": [
    "s3:GetObject"
],
"Resource": [
    "arn:aws:s3:::BUCKET/prefix-for-folder",
    "arn:aws:s3:::BUCKET/prefix-for-folder/*",
]

# other similar Get/List/Read permissions for S3, EFS, etc, all
# specifically to support automated read-only instance actions

...and yes, those should probably be combined into single Statement blocks; some of them are generated and some are managed by hand. Anyhow, we also have an IAM role with the above policy attached. EC2 instances for this account then list that role as their "instance role" and magically get read permissions at boot.

Works like a charm.

The goal

Trying to create some EC2 instances in a different AWS account. Ideally we'd like them to be able to list the "instance role" from the first account, and get the same read-only access to the buckets-and-whatnot in the first account.

What I've tried

Trying to edit the IAM role mentioned above. Following the various "give access to resources across accounts" tutorials, it's clear that the permissions in the policy/role aren't the crucial bit here, but rather the trust relationships in the role. In the "instance role", the working trust relationships are

"Effect": "Allow",
"Principal": {
    "Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"

and in the examples given for sharing across accounts, the principal is instead the AWS account ID of the account being shared to:

# they're careful to point out that 'root' means any authenticated
# user in that account, not the special root user for the account
"Principal": {
    "AWS": "arn:aws:iam::other-account-12-digit-ID:root",
},

I'm hoping to avoid duplicating the role and the entire complex policy for just the sake of a different principal, and according to the AWS IAM user guide there can be more than once principal listed, so I tried changing the existing role's trust relationship to

"Effect": "Allow",
"Principal": {
    "AWS": "arn:aws:iam::other-account-12-digit-ID:root",
    "Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"

The IAM Console was okay with the Principal syntax, and I've verified that EC2 instances in this same account continue to boot up and take on the specified instance role/policy.

However, creating an EC2 instance in other-account-12-digit-ID doesn't display this role as an option for the instance role. (In the EC2's "new launch experience" wizard, if that's relevant.)

My vague theory is that the arn:aws:iam::other-account-12-digit-ID:root is the wrong ARN to specify EC2 instances in the other account -- guessing that maybe this syntax is for people, not instance profiles -- but I don't know what I should be trying instead? I'm also assuming that any of this is even possible in the first place -- all the examples of sharing across accounts that I can find refer to S3 buckets directly, rather than an EC2 instance role. Dunno how much that matters?

There are some other SO/SE/ServerFault questions involving IAM roles like this one, but the problem and answers all involve additional pieces like Ansible or Elastic Beanstalk. I'm hoping to figure out what I need to do to IAM (or the EC2 launcher) itself by hand, and will eventually apply it to CloudFormation and AWS CDK and so forth.

Ti Strga
  • 101
  • 3

2 Answers2

1

Use an external ID and account principal as below. This works for generic role sharing, but I'm not convinced it will work with sharing an instance role - probably not as I'm not sure how you'd pass the external ID.

RoleAbc:
  Type: "AWS::IAM::Role"
  Properties:
    RoleName: RoleNameGoesHere
    AssumeRolePolicyDocument:
      Version: 2012-10-17
      Statement:
      - Effect: Allow
        Principal:
          AWS: 'arn:aws:iam::123456789012:root'
        Action: 'sts:AssumeRole'
        Condition:
          StringEquals:
            'sts:ExternalId': abc123abc123abc123
    ManagedPolicyArns:
      - arn:aws:iam::123456789012:role/PowerUserRoleOrWhatever
    
Tim
  • 31,888
  • 7
  • 52
  • 78
  • I'm having trouble figuring out what the `sts:ExternalId` or `PowerUserRoleOrWhatever` is meant to map to in the case of an instance profile. It's not going to be a human user who's manually triggering a role change; it's just an EC2 instance doing... whatever instance profiles do? – Ti Strga Jun 09 '22 at 15:51
  • It might not work with instance profiles. This works for generic sharing of roles, but MLu above may be right. Your easiest option is to simply create the profile in each account. – Tim Jun 09 '22 at 19:51
1

There's a couple of things:

  1. When creating the EC2 you don't see the IAM Role from the other account - that's expected. The console wizard will only list compatible IAM Roles from the same account.

    I don't think you can actually use an instance role from the other account directly. Instead you will have to create the instance role that grants it the permission to assume role in the other account through trust relationship and then in the instance do something like aws sts assume-role --role-arn arn:aws:iam::{other-acct-id}:role/ThatS3Role. That will come back with temporary credentials that you can later use run aws cli command as if the instance was in the other account.

    Alternatively instead if aws sts assume-role you can use a helper script like assume-role that you can later use as assume-role -r arn:aws:iam::{other-acct}:role/ThatS3Role aws s3 cp ... - here the "aws s3 cp" command will run with the other account credentials.

  2. If it's only about S3 you can as well give the 2nd account read-only access to the S3 bucket in the other account directly. Here are some good examples: https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html

Hope that helps :)

MLu
  • 24,849
  • 5
  • 59
  • 86
  • I guess I can't do what I'm hoping to do, then; instance profiles simply "take effect" without needing to do `sts-assume-role` by hand or in a script. – Ti Strga Jun 09 '22 at 15:53
  • Ultimately you want to run the `aws s3` command. With an instance role you can just do it without worrying about the creds. With cross account access all you have to do is run `aws sts assume-role` and then continue with your script (`aws s3`) as usual. It’s just one extra call to sts and you achieve what you want. – MLu Jun 09 '22 at 20:06
  • The current policy (for instances in the same account as the IAM role) lists other resources than S3, but even getting just S3 access working has been frustrating. I gave up trying to get IAM roles working, and just tried creating a policy attached to a known-working bucket, following the examples in your second point. None of these approaches worked either, and I've no idea what test is failing or where it's going wrong. Nothing generates any errors on the "granting" side, just endless failures on the accessing accounts. I think this project may have just come to a halt. – Ti Strga Jun 10 '22 at 19:47