AWS ECR (Elastic Container Registry) is a managed Docker hub with customizable permissions. It's easy to setup with a single account and AWS's documentation is pretty good enough even if you have no experience with Docker, at all. This blogpost focuses on using a central ECR with multiple accounts with complex IAM permissions.

First thing is first

First thing to accomplish is locating ECR in Services. It's not there. The new autocomplete UI is pretty but nothing shows up when you enter ECR. If you type container, you'll see only EC2 Container Service (and elastic beanstalk but who cares). Choose EC2 Container Service, if you have used this service before then you can click on Repositories directly. If you haven't, click Get Started and following screen will welcome you:

After entering a valid repository name, you are all set to start.

Pulling/Pushing images

The ECR repository page helps you with the executing basic. To try it out, you can launch an instance from EC2, install Docker, and then authenticate, push, and pull images. The last link also mentions Permissions, where you can specify which roles will have which access rights. It's easy to do if there is only one account. Unfortunately ECR Permissions user interface is not friendly if you want to specify permissions for other accounts, you can do it only for root user of other accounts from the UI.

Configuring ECR to allow access from multiple accounts with complex IAM policies

This guide gives instructions to allow root users of other accounts to have access to the central registry. We will use set-repository-policy of aws cli.
At this point, I assume you have configured ECR in Account1 and launched an instance in Account1, IAM roles role2-1 and role2-2 in Account2. Let's allow role2-1 to have push/pull access and allow role2-2 to have just pull access. Let's set it up:

Update security policy

Login to an instance in Account1 and execute below command to get authentication token:

~ $(aws ecr get-login --region us-west-2 --registry-ids $CENTRAL_ACCOUNT_ID)

If you use docker with sudo, put sudo in the beginning: sudo $(aws ecr... Also please replace $CENTRAL_ACCOUNT_ID with proper 12 digit id.

You can find the account id in Profile -> My Security Credentials -> Account identifiers (Remove dashes, it should be a 12 digit number).
You can learn account id of Account2 the same way as we'll need it for permissions.
Now run following command to set registry policy:

#!/bin/bash
CENTRAL_ACCOUNT_ID=<account-1-id>
REPOSITORY_NAME=<repo-name>
aws ecr set-repository-policy --registry-id $CENTRAL_ACCOUNT_ID --repository-name $REPOSITORY_NAME --policy-text '
{"Version":"2008-10-17","Statement":[{"Sid":"pull and push","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::<account-2-id>:role/role2-1"},"Action":["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability","ecr:PutImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload"]},{"Sid":"pull only","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::<account-2-id>:user/role2-2"},"Action":["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]}'

This is a bash file and you can either save it to an .sh file or replace the variables with actual values and run just the last line. You should replace <account-1-id>, <account-2-id>, <repo-name>, and role names with proper values. You should see following policy in the Permissions tab:

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "pull and push",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<account-2-id>:role/role2-1"
            },
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload"
            ]
        },
        {
            "Sid": "pull only",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<account-2-id>:user/role2-2"
            },
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability"
            ]
        }
    ]
}

This command will update the permissions of the repository, you can observe the result in Permissions tab of the repository. The permissions of role2-1 are the same as Push/Pull actions in adding new policy window and permissions of role2-2 are the same as Pull only actions.

Conclusion

In the end, the users with role role2-1 are able to push and pull images and users with role role2-2 are able to only pull images. You can try by launching instances for each role type.