Setting up permissions for images on Docker Hub is pretty straightforward, given how it follows a simple GitHub-like model. Amazon EC2 Container Registry (or Amazon ECR) is a great service for storing 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 the AWS command line tool to set the permissions. Using the 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 Amazon 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
Let's get started.
Step 0: Configure the local environment
We have to configure the local system to enable the AWS
cli to talk to the account.
Download and install the AWS cli which should have the Amazon 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 will make it easier to test the changes by just switching user profiles before executing commands. Once the keys are in right place, this 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
It's ideal to have users permissions that are on a "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 this 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: Create 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: Create a repository
An image should be stored (ideally) in a different
Amazon 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 this 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
This 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 this 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:
$ 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: Time to test
For pushing images to Amazon ECR we first need to enable the local docker daemon to authenticate with the registry:
$ aws --profile usr1 ecr get-login
This returns 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 the Amazon ECR repo:
$ docker push <aws account id>.dkr.ecr.<aws region>.amazonaws.com/repo1:latest
Now let's 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
And, now for 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
ECR permissions works as expected !!!
