Setting permissions on Amazon ECR repositories

Setting up permissions for images on Docker hub is pretty straightforward, which follows a simple Github-like model. Amazon (EC2 Container Registry)ECR is a great service for storing the images but setting correct permissions is slightly complicated. This is especially true when configuring user specific permissions on the images. We’ll create a few users and repos and set up repo permissions. We’ll use  aws command line tool for this. Using cli makes it easier to script all the steps and automate the entire process. Everything we do using cli can be done using the web interface
The objective is to setup following rules for any image pushed on ECR
– user usr1 should have push/pull permissions for Repo1 and Repo2
– user usr2 should have push/pull permissions for Repo2 only
– user usr3 should have only pull permissions for Repo1
Step 0: Configuring local environment.
We have to configure the local system to enable aws cli to talk to the account. Download and install aws cli which should have ecr module available.
Next, provide the Access Key Id, Secret Key and region for the following command
$ aws configure --profile admin
The reason we’re setting up different profiles is that it’ll make it easier to test the changes by just switching user profiles before executing commands
Once the keys are in right place, the command to list keys should return valid data
$ aws --profile admin iam list-access-keys
{
  "AccessKeyMetadata": [
    {
      "UserName": "b-deva",
      "Status": "Active",
      "CreateDate": "2015-11-14T18:18:49Z",
      "AccessKeyId": "AKIAIRKI4PQD4N3JRVJA"
    }
  ]
}
Step 1: Creating IAM policy.
Its ideal to have users permissions that are at need-to-know basis, so by default the users do not have any permissions on AWS. We will create a policy that will allow users to just request authentication token from AWS.
Create a file called authPolicy.json and add following content
$ cat << EOM > authPolicy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    }
  ]
}


$ aws --profile admin iam create-policy --policy-name=authOnly --policy-document file://authPolicy.json
{
  "Policy": {
    "PolicyName": "authOnly",
    "CreateDate": "<date>",
    "AttachmentCount": 0,
    "IsAttachable": true,
    "PolicyId": "<policy id>",
    "DefaultVersionId": "v1",
    "Path": "/",
    "Arn": "arn:aws:iam::<account number>:policy/authOnly",
    "UpdateDate": "<date>"
  }
}
So now that we have a policy in place, we can start creating users and assigning this policy to them.
Step 2: Creating Users.
All three users need permission to authenticate, so we’ll first create the users and attach the policy
$ aws --profile=admin iam create-user --user-name=usr1
{
  "User": {
    "UserName": "usr1",
    "Path": "/",
    "CreateDate": "<date>",
    "UserId": "<user id>",
    "Arn": "arn:aws:iam::<account id>:user/usr1"
  }
}

$ aws --profile=admin iam attach-user-policy --user-name usr1 --policy-arn arn:aws:iam::<account number>:policy/authOnly
Run both these commands for usr2 and usr3 also. Also, once the users are created, we need to configure local environment with their credentials
$ aws configure --profile usr1 // do this for usr2 and usr3 also
Step 3: Creating a repository.
An image should be stored (ideally) in a different ECR Repository. One can potentially push multiple images in the same repository with different tags but it becomes difficult to manage all the tags this way.
Use following command to create a repository
aws ecr create-repository --repository-name=repo1
{
  "repository": {
    "registryId": "<account id>",
    "repositoryName": "repo1",
    "repositoryArn": "arn:aws:ecr:us-east-1:<account-id>:repository/repo1"
  }
}

$ aws ecr create-repository --repository-name=repo2
{
  "repository": {
    "registryId": "<account id>",
    "repositoryName": "repo2",
    "repositoryArn": "arn:aws:ecr:us-east-1:<account-id>:repository/repo2"
  }
}

Step 4: Repository permissions.
Almost there. The last step is give user level permissions. For this, each repository will have a different policy document for each user.
create file usr1Policy.json and add following content in it

$ cat << EOM > usr1Policy.json
{
  “Version”: “2008-10-17”,
  “Statement”: [
    {
      “Sid”: “new statement”,
      “Effect”: “Allow”,
      “Principal”: {
        “AWS”: “arn:aws:iam::<account id>:user/<usr1>“
      },
      “Action”: [
        “ecr:GetDownloadUrlForLayer”,
        “ecr:PutImage”,
        “ecr:InitiateLayerUpload”,
        “ecr:UploadLayerPart”,
        “ecr:CompleteLayerUpload”,
        “ecr:DescribeRepositories”,
        “ecr:GetRepositoryPolicy”,
        “ecr:ListImages”,
        “ecr:DeleteRepository”,
        “ecr:BatchDeleteImage”,
        “ecr:SetRepositoryPolicy”,
        “ecr:DeleteRepositoryPolicy”,
        “ecr:GetAuthorizationToken”,
        “ecr:BatchCheckLayerAvailability”,
        “ecr:BatchGetImage”
      ]
    }
  ]
}
EOM

$ aws –profile admin ecr set-repository-policy –repository-name repo1 –policy-text file://usr1Policy.json $ aws –profile admin ecr set-repository-policy –repository-name repo2 –policy-text file://usr1Policy.json

The following command should now return an empty array

$ aws –profile usr1 ecr list-images –repository-name=repo1
{
“imageIds”: []
}
 
$ aws –profile usr1 ecr list-images –repository-name=repo2
{
“imageIds”: []
}

Next is to give usr2 permissions on Img2 only. Create a file usr2Policy.json and add following content

$ cat << EOM > usr2Policy.json
{
  “Version”: “2008-10-17”,
  “Statement”: [
    {
      “Sid”: “new statement”,
      “Effect”: “Allow”,
      “Principal”: {
        “AWS”: “arn:aws:iam::<account id>:user/usr2”
      },
      “Action”: [
        “ecr:GetDownloadUrlForLayer”,
        “ecr:PutImage”,
        “ecr:InitiateLayerUpload”,
        “ecr:UploadLayerPart”,
        “ecr:CompleteLayerUpload”,
        “ecr:DescribeRepositories”,
        “ecr:GetRepositoryPolicy”,
        “ecr:ListImages”,
        “ecr:DeleteRepository”,
        “ecr:BatchDeleteImage”,
        “ecr:SetRepositoryPolicy”,
        “ecr:DeleteRepositoryPolicy”,
        “ecr:GetAuthorizationToken”,
        “ecr:BatchCheckLayerAvailability”,
        “ecr:BatchGetImage”
      ]
    }
  ]
}
EOM

$ aws –profile admin ecr set-repository-policy –repository-name repo2 –policy-text file://usr2Policy.json

We should now be able to list images for repo2 using usr2 profile

<div>
  <pre class="lang:sh decode:true">$ aws --profile usr1 ecr list-images --repository-name=repo1

{ “imageIds”: [] }

Lastly, usr3 should have permissions to just pull images from repo 2. Create a new file usr3Policy.json and add following content

$ cat <<EOM > usr3Policy.json
{
  “Version”: “2008-10-17”,
  “Statement”: [
    {
      “Sid”: “new statement”,
      “Effect”: “Allow”,
      “Principal”: {
        “AWS”: “arn:aws:iam::291318889788:user/usr1”
      },
      “Action”: [
        “ecr:GetDownloadUrlForLayer”,
        “ecr:BatchCheckLayerAvailability”,
        “ecr:BatchGetImage”
      ]
    }
  ]
}
EOM
$ aws –profile admin ecr set-repository-policy –repository-name repo2 –policy-text file://usr2Policy.json

Step 5 Testing.
For pushing images to ECR we first need to enable the local docker daemon to authenticate with the registry.
$ aws --profile usr1 ecr get-login
 This return a “docker login ….” command with short lived credentials. Once we’ve run that command, we should be able to push the image.
Just pick any image and tag it as follows
$ docker tag <local image id> <aws account id>.dkr.ecr.<aws region>.amazonaws.com/repo1:latest

That’s about it. Once the tagging is done, the following command should push an image to ECR repo

$ docker push <aws account id>.dkr.ecr.<aws region>.amazonaws.com/repo1:latest

Lets push an image to repo1 with usr3 account

$ aws --profile usr3 ecr get-login
$ docker login ... 
$ docker push <aws account id>.dkr.ecr.<aws region>.amazonaws.com/repo1:latest
... some data ...
unknown: User: arn:aws:iam::<account id>:user/usr3 is not authorized to perform: ecr:PutImage on resource: arn:aws:ecr:<region>:<account id>:repository/repo1

now the pull.

$ aws --profile usr3 ecr get-login
$ docker login ... 
$ docker pull <aws account id>.dkr.ecr.<aws region>.amazonaws.com/repo1:latest
... some data ...
Status: Image is up to date for <account id>.dkr.ecr.<region>.amazonaws.com/repo1:latest

Works as expected !!!

Share Comments
comments powered by Disqus