ecr:GetAuthorizationToken Across Accounts for EKS to Pull Images from ECR

0

I have a few accounts in the following structure:

  • mycompany-management (billing account)
    • mycompany-artifacts (where ECR registry lives)
    • mycompany-production (where EKS lives)
    • mycompany-development (another account where a different EKS lives)

We set up our account structure this way so that our container images live in a single place and are accessed by the various accounts using IAM roles on EKS nodes. Each node role for each node group for each EKS cluster is added to each ECR repository's IAM policy to grant access to either pull or push (or both) actions.

This resource-based policy works for assigning what a given IAM principal can do with resources in the ECR repository, but unfortunately this cannot be used to allow the critical ecr:GetAuthorizationToken action required to allow docker login to work. That specific permission needs to have a wildcard for resources, and assigning them on the repository doesn't accomplish anything.

I have created a role in the artifacts account where ECR lives, and even though I have granted the role access to ECR actions in the ECR repository policy, it does not work without assigning a policy to the role allowing ecr:GetAuthorizationToken.

ECR Repository IAM Policy

Here is the IAM policy attached to the ECR repository directly:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPush",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::0123456789012:role/ecr-push-my-demo-service-role"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:CompleteLayerUpload",
        "ecr:DescribeRepositories",
        "ecr:GetDownloadUrlForLayer",
        "ecr:InitiateLayerUpload",
        "ecr:ListImages",
        "ecr:PutImage",
        "ecr:UploadLayerPart"
      ]
    },
    {
      "Sid": "AllowPull",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/production-eks-node-role"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:DescribeRepositories",
        "ecr:GetDownloadUrlForLayer",
        "ecr:ListImages"
      ]
    }
  ]
}

Note that for AllowPush, I am granting access to a role in the same account which is the artifacts account.

For AllowPull, I am granting access to a role across accounts in the production account to the EKS node role to allow EKS in that account to pull images from this account.

The above is insufficient and does not work, as clients cannot generate a login password for docker login.

IAM Role Attached Policy

Since the "push role" above is in the same account, I have created an IAM policy and attached it to the role with the following contents:

{
    "PolicyVersion": {
        "Document": {
            "Statement": [
                {
                    "Action": "ecr:GetAuthorizationToken",
                    "Effect": "Allow",
                    "Resource": "*",
                    "Sid": "AllowGetAuthToken"
                }
            ],
            "Version": "2012-10-17"
        }
    }
}

The combination of the ECR repository policy and this IAM role-attached policy allow the ecr-push-my-demo-service role to authenticate with ECR and to then push images to the repository.

Problem

The problem, of course, is that there doesn't appear to be a way for me to allow ecr:GetAuthorizationToken from an IAM principal that is not in the local account, in my case a cross-account role.

Given an IAM role in another account, is there any way to allow it to generate an ECR authorization token for Docker login, or is there no way to do this?

Alternately, is there a way to configure EKS in my production account to use the node role to assume a role in the artifacts account, granting access?

  • please accept the answer if it was helpful

2 Answers
2
profile picture
EXPERT
answered a month ago
profile picture
EXPERT
Artem
reviewed 21 days ago
0

Alright, so this is really strange but I do have it working.

Taking a look at other questions and at aws ecr get-login-password help, that command does something fairly unexpected. You cannot specify which ECR registry to generate a login password for, so the generation of the token is irrespective of which account you are in. This means that you simply generate the password in whatever account you are pulling from, and AWS associates that password with the IAM principal being used to generate it. In my case, this means that the role in the production account is bound to that password/identity, and then when we authenticate using docker login, we target the artifacts account's registry, i.e.

# generate a login password from within the **production** account
aws --profile mycompany-prod ecr get-login-password | \
  # and log in using that password to the **artifacts** account's registry: \
  docker login -u AWS --password-stdin ${ARTIFACTS_ACCOUNT_ID}.dkr.ecr.${ARTIFACTS_ACCOUNT_REGION}.amazonaws.com

For this to work, the IAM principal being used in aws ecr get-login-password (i.e. the output of aws sts get-caller-identity) must have the permission (in the production account) to ecr:GetAuthorizationToken. My IAM principal is an IAM role prod-ecr-pull-role, and this means I have to attach the following policy to it in that account:

{
  "Statement": [
    {
      "Action": "ecr:GetAuthorizationToken",
      "Effect": "Allow",
      "Resource": "*",
      "Sid": "AllowGetAuthToken"
    }
  ],
  "Version": "2012-10-17"
}

Next, in the ECR account (in my case, the artifacts account), we must add the IAM role ARN (or any IAM principal from the production account you want to target) to the ECR repository policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPull",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::987654321098:role/prod-ecr-pull-role"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:DescribeRepositories",
        "ecr:GetDownloadUrlForLayer",
        "ecr:ListImages"
      ]
    }
  ]
}

So to boil this down to a checklist:

  1. In the account which contains the IAM principal (user or role) which needs to pull across accounts from ECR, that IAM principal must have ecr:GetAuthorizationToken on Resource: "*". This amounts to authentication.
  2. In the account which contains the ECR repository, you must grant the appropriate ecr:* permissions to a Principal of type AWS which gives the IAM principal ARN (e.g. arn:aws:iam::987654321098:role/prod-ecr-pull-role) the ability to the ecr:* permissions you wish to grant. This amounts to authorization.

The implications of this are that ECR login passwords are globally identifiable across all AWS accounts and are bound to the IAM principal that generated them. Then, when docker login occurs, AWS behind the scenes identifies the login password with that IAM principal, and then evaluates in the ECR repository policy whether that principal can take the specified actions.

answered a month ago