Search code examples
terraformamazon-iamamazon-ecs

IAM Role or User for ECS access to 2 AWS accounts


I have an ECS task that needs to access multiple AWS accounts. I need this access to be uninterrupted - meaning that I cannot assign the ECS task an IAM role as a task execution role since from the AWS docs

Users have permanent long-term credentials, but roles provide temporary credentials

I tried to solve the problem by:

  1. Creating an IAM role on account A with all the required permissions to access the services I need on account A
  2. The role on account A has a trust policy which allows the containers running the ECS task on account A to assume it and perform the required actions
  3. Creating an IAM role on account B with all the required permissions to access the services I need on account B
  4. The role on account B has a trust relation configured which allows it to be assumed from the role on account A.

And now the problems start:

  • The containers on account A are running with an assumed role but the trust relationship configured on step 4 is configured on the account A role itself. How do I configure a trust relationship on an assumed role? I know that I can specify something like this
"Principal": { "AWS": "arn:aws:sts::AWS-account-ID:assumed-role/role-name/role-session-name" }

but the role-session-name is a UUID which will change over time. It's also worth mentioning here that I am doing all these using Terraform and I cannot find a Terraform directive which can give me access to the assumed role ARN of the container so that I can add it to the trust relationship on account B.

  • Even if I solve this, these credentials are going to be temporary. How can I solve this using a User who has permanent credentials?

Solution

  • So I made it in the end and this is the setup:

    1. Create an IAM role on account A with all the required permissions to access the services I need on account A.

    2. The role on account A has to have a trust policy which allows the containers running the ECS task on account A to assume it and perform the required actions.

    3. Apart from the permissions required to access AWS services, this role also needs to have an Allow permission on sts:AssumeRole. This will allow the containers which have assumed the role - and now have sts:account_id:assumed-role/source-role-name/session-name - to perform the assume role that they need on the destination account (account B).

    4. Create an IAM role on account B with all the required permissions to access the services I need on account B

    5. The role on account B has to have a trust relation configured which allows it to be assumed from the assumed-role that the container that the ECS task has spawned. This is integral.

    6. Achieving the goal on 4 is tricky. I tried to do it with the following trust policy

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Statement1",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "aws:arn:sts:<account-id>:assumed-role/source-role-from-account-A"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    "StringLike": {
                        "sts:RoleSessionName": [
                            "*"
                        ]
                    }
                }
            }
        ]
    }
    

    This did not work because IAM does not allow you to define assumed roles without session names. And session names CANNNOT be replaced by woldcards. But the following worked

           {
                "Sid": "",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    "StringLike": {
                        "aws:userId": "<role_id>:*"
                    }
                }
            }
    

    User ids are assigned to both IAM users and roles!

    For IAM users, the request context value is the user ID. For IAM roles, this value format can vary. Although the condition is called "aws:UserId", it is not limited to IAM Users alone and supports IAM Roles with the help of Role-ID and Session Names in the context.

    In order to get the user id (which in this case is the role id)

    aws iam get-role --role-name role_name
    

    Now for the ephemeral STS tokens, as @MarkB mentioned

    The part you quoted about roles being temporary is just some boilerplate security documentation that AWS has copied into the "security" documentation section for several of their different services. ECS will automatically refresh the security tokens, so you don't need to worry about them being temporary.

    Nevertheless, I found these docs here which describe that tokens are shortlived and their lifespan can vary from 1 to 12 hours. One way to control this is using the MaxSessionDuration and update the role.

    For now, my service is running for more than 12 hours and the STS credentials are still working so I think @MarkB was right.

    In case they do expire at some point I think I would create a lambda that restarts my service. It is a monitoring tool anyway and it's not mission-critical if it gets restarted every 5 hours or so.

    IAM is spaghetti :) I hope this helps people!