Using Amazon EC2 Container Registry with IAM

If you're using Amazon Web Services and Docker containers, you might be familiar with EC2 Container Service (ECS) - Amazon's container orchestration and management service. It is a relatively simple tool compared to e.g. Kubernetes, but the capabilities of ECS still allow you to do wonderful things with your infrastructure in very short time.

Similarly to other container orchestration tools, ECS allows you to create clusters of EC2 instances (yes, you can enable autoscaling too), run tasks on these instances and optionally group tasks into services. Each task (defined as a JSON object called Task Definition) is a composition of one or more Docker containers, volumes and their runtime configurations.

You need to store your Docker images somewhere before you spin up a cluster. Amazon provides EC2 Container Registry - an alternative to Docker Hub or managing Docker self-hosted registry. Unlike in Docker Hub, there are no public repositories in ECR, no automated builds, no README pages. Push, pull, that's it. However, there's one important benefit of using ECR and that is the fact that ECR inherits Amazon's complex, yet easy to use Identity and Access Managemenent (IAM). What that practically means we'll see shortly.

Amazon ECR pricing model is based on combination of storage and transfers used. That might be appealing if you manage many seldom accessed private repositories, since you don't pay by the number of repos, but only for what you actually use. But on the other hand great number of large image pulls can become expensive quickly. Keep it in mind.

In this article you will learn how to:

  • store Docker images in ECR
  • automate authorization with ECR
  • limit access to specific ECR repositories

Storing Docker images in EC2 Container Registry

Migrating your existing Docker images to EC2 Container Registry is as simple as creating a repository in ECR using either the web interface or AWS CLI, tagging your image with the full prefix (e.g. 456941701234.dkr.ecr.us-east-1.amazonaws.com/my-repository) and pushing it into the repository. But of course you need to authenticate first.

AWS CLI has a command aws ecr get-login (since version 1.9.15) which returns docker login command for your account, with a short-lived authorization token valid for 12 hours. This is actually a good idea from security perspective, since developers are better motivated to automate authentication flow and not rely on hardcoded passwords or one-off logins.

Let the following commands illustrate a simple example of automated authorization:

$ # set AWS Key ID and Secret Access Key of your AWS IAM user
$ # and optionally select default region
$ aws configure 
$
$ # use this command in your script to authenticate Docker with ECR
$ eval $(aws ecr get-login) 

Note: if you haven't set your default region using aws configure or if you want to use another region than set in your defaults, then you'll need to provide the aws ecr get-login command with --region parameter, for instance aws ecr get-login --region us-east-1. This is not very well documented at the time of writing this article.

Limiting access to ECR repositories

Let's assume that you maintain several Docker repositories related to various projects. If you are using Docker Hub, you most likely end up having a separate account (or organization) for each of the projects, since authenticating Docker client with Docker Hub gives the Docker client access to all repositories stored in that account.

With ECS it's a different kind of burrito. You can create a user in IAM and grant it access to specific repositories with very fine granularity. Let's see how we can do it step by step.

Create a user in IAM

Log in to your AWS account and go to Users management in AWS Security Credentials section. Create a user for your project. Leave the Generate an access key for each user checkbox checked, since you will need these Access Keys later during authorization.

Note: Users and their Access Keys are valid globally, across all AWS regions.

Create user policy

AWS users that you want to use with ECR need to have a special policy called ecr:GetAuthorizationToken to be able to successfully invoke aws ecr get-login command. Go to User Details and add an Inline Policy on Permissions tab. The policy should look like this:

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

Set Docker repository permissions

Now you're ready to switch to EC2 Container Repository. Select the repository you want to set the permissions to, and on Permissions tab add a new Permission Statement. Choose a descriptive Sid for the policy, select who you're granting the permissions to (Principal) and Allow only required actions.

A reasonable subset required for standard push/pull operations could be:

  • ecr:GetDownloadUrlForLayer
  • ecr:PutImage
  • ecr:CompleteLayerUpload
  • ecr:BatchGetImage
  • ecr:InitiateLayerUpload
  • ecr:BatchCheckLayerAvailability
  • ecr:UploadLayerPart

Summary

AWS Identity and Access Managemenent can be used to limit access to Docker images stored in EC2 Container Registry. The bottom line is that you should never use root AWS user with AWS command line interface. Instead, try to always create users with only the permissions required for performing their tasks, and use those to authenticate with the cloud.