How to Configure Cross-Account ECR Image Pull Permissions in AWS: Solving Invalid Policy Errors


3 views

When setting up cross-account ECR access, many developers encounter policy validation errors that aren't immediately intuitive. The key issue lies in how AWS interprets the principal field in ECR repository policies.

For cross-account access, you must use the account ID as the principal - not IAM ARNs. Here's the proper JSON structure:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT_B_ID:root"
      },
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability"
      ]
    }
  ]
}

Here's a full working example that grants pull permissions to Account B (123456789012):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CrossAccountPull",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability",
        "ecr:DescribeImages",
        "ecr:DescribeRepositories",
        "ecr:ListImages"
      ]
    }
  ]
}

To set this policy using AWS CLI:

aws ecr set-repository-policy \
  --repository-name your-repo \
  --policy-text file://policy.json \
  --region us-east-1

After applying the policy, test the access from Account B:

aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin ACCOUNT_A_ID.dkr.ecr.us-east-1.amazonaws.com

docker pull ACCOUNT_A_ID.dkr.ecr.us-east-1.amazonaws.com/your-repo:latest

If you still encounter problems:

  • Ensure no Service Control Policies (SCPs) are blocking cross-account access
  • Verify that the IAM user in Account B has permission to call ECR actions
  • Check that VPC endpoints (if used) allow cross-account traffic

For more granular control, you can specify specific IAM roles rather than the entire account:

{
  "Principal": {
    "AWS": [
      "arn:aws:iam::123456789012:role/ecr-pull-role1",
      "arn:aws:iam::123456789012:role/ecr-pull-role2"
    ]
  }
}

Many teams encounter issues when configuring Amazon ECR repositories to allow cross-account image pulls. The AWS console's policy editor limitations often compound these problems. Here's what actually works.

The key misunderstanding comes from principal formatting. For ECR cross-account access, you must use this format:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::TARGET_ACCOUNT_ID:root"
      },
      "Action": [
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer",
        "ecr:GetRepositoryPolicy",
        "ecr:DescribeRepositories",
        "ecr:ListImages"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "TARGET_ACCOUNT_ID"
        }
      }
    }
  ]
}

Common mistakes include:

  • Using raw account numbers instead of ARN format for principals
  • Missing the :root suffix in the ARN
  • Attempting to specify individual IAM users (which requires additional AssumeRole setup)

For reliable execution, use the CLI:

aws ecr set-repository-policy \
  --repository-name YOUR_REPO \
  --policy-text file://ecr-policy.json \
  --region YOUR_REGION

After applying the policy:

  1. Create an IAM role in Account B with ECR read permissions
  2. Assume the role and test pulling an image:
aws ecr get-login-password --region YOUR_REGION | \
  docker login --username AWS --password-stdin \
  SOURCE_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com

For production environments, consider adding these security measures:

"Condition": {
  "ArnLike": {
    "aws:SourceArn": "arn:aws:iam::TARGET_ACCOUNT_ID:role/YOUR_ROLE_NAME"
  },
  "IpAddress": {
    "aws:SourceIp": ["YOUR_APPROVED_IP_RANGE"]
  }
}