Introduction to ECR Repository Policies Using CFN

TOC

Introduction to ECR Repository Policies Using CloudFormation

ECR repositories can be configured with resource-based policies.

This page aims to set repository policies to restrict image push/pull.

Environment

Diagram of introduction to ECR Repository Policies using CFN

Create an ECR.
Set an ECR repository policy to restrict image push/pull to the repository.

Create three EC2 instances in a private subnet.
The instances will be the latest version of Amazon Linux 2.
The three units will be configured similarly, but the repository policy will allow the following actions

  • EC2 instance 1: Allow image push
  • EC2 instance 2: Allow image pull
  • EC2 instance 3: Do not allow image push/pull

CloudFormation Template Files

The above configuration is built with CloudFormation.
The CloudFormation templates are located at the following URL

https://github.com/awstut-an-r/awstut-fa/tree/main/085

Point Explanation of Template Files

EC2

Resources:
  Instance1:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile1
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref InstanceSubnet
          GroupSet:
            - !Ref InstanceSecurityGroup
      UserData: !Ref UserData

  Instance2:
    Type: AWS::EC2::Instance
    Properties:
      ...

  Instance3:
    Type: AWS::EC2::Instance
    Properties:
      ...
Code language: YAML (yaml)

Create three EC2 instances.
Configure all of them in the same way.

When creating the instances, perform the initialization process using the user data.
This time, execute the following process.

#!/bin/bash -xe
yum update -y
amazon-linux-extras install docker
systemctl start docker
usermod -a -G docker ec2-user
Code language: Bash (bash)

After installing Docker, start it so that you can execute Docker commands with the privileges of ec2-user.

Here are the IAM roles for the instance

Resources:
  InstanceRole1:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess

  InstanceRole2:
    Type: AWS::IAM::Role
    Properties:
      ...

  InstanceRole3:
    Type: AWS::IAM::Role
    Properties:
      ...
Code language: YAML (yaml)

Create an IAM role for each instance.
Configure all the same settings.

The point is to attach the AWS management policy “AmazonEC2ContainerRegistryFullAccess”.
This means that by attaching these IAM roles, the three instances will be authorized to push/pull images to/from the ECR repository.

Resources:
  ECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Ref Prefix
      RepositoryPolicyText:
        Version: 2012-10-17
        Statement:
          - Effect: Deny
            Principal: "*"
            NotAction:
              - ecr:BatchCheckLayerAvailability
              - ecr:CompleteLayerUpload
              - ecr:InitiateLayerUpload
              - ecr:PutImage
              - ecr:UploadLayerPart
            Condition:
              ArnEquals:
                aws:PrincipalArn: !Ref InstanceRoleArn1
          - Effect: Deny
            Principal: "*"
            NotAction:
              - ecr:BatchGetImage
              - ecr:GetDownloadUrlForLayer
            Condition:
              ArnEquals:
                aws:PrincipalArn: !Ref InstanceRoleArn2
          - Effect: Deny
            Principal: "*"
            Action: "*"
            Condition:
              ArnNotEquals:
                aws:PrincipalArn:
                  - !Ref InstanceRoleArn1
                  - !Ref InstanceRoleArn2
Code language: YAML (yaml)

The RepositoryPolicyText property sets the repository policy.

The repository policy consists of three statements.

The first statement is for EC2 instance 1.
Use ArnEquals and aws:PrincipalArn in the Condition element to specify the ARN of the IAM role attached to EC2 instance 1.
By specifying “Deny” in the Effect element and then using the NotAction element, you are rejecting actions other than those specified in NotAction.
Since we specified the action required for image push in NotAction, it means that instance 1 will be denied any action other than push.

The second statement is for EC2 instance 2.
It uses the same notation as the first one to deny any action other than an image pull to EC2 instance 2.

The third statement is for access from resources other than those listed above.
Use ArnNotEquals and aws:PrincipalArn in the Condition element to specify the ARNs of the two IAM roles above and target resources other than these.
By specifying “Deny” for the Effect element and “*” for the Action, all actions will be denied.
This means that all accesses other than those to the two EC2 instances will be denied.

Architecting

Using CloudFormation, we will build this environment and check the actual behavior.

Create CloudFormation stacks and check resources in stacks

Create CloudFormation stacks.
For information on how to create stacks and check each stack, please refer to the following page

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

After checking the resources in each stack, information on the main resources created this time is as follows

  • ECR repository: fa-085
  • EC2 instance 1: i-0bde1cc6fc498a208
  • EC2 instance 2: i-0296e9a1b5f70b522
  • EC2 instance 3: i-0d0cc36a5186db23b

Confirm the created resource from the AWS Management Console.
Check the ECR.

Detail of ECR Repository 1.

The ECR repository has been successfully created.

Next, check the ECR repository policy.

Detail of ECR Repository Policy 1.

You can see that the repository policy has been created as defined in the CloudFormation template.

Check the command to push the image to the ECR.

Detail of ECR Image Push Command.

Execute this command on the three EC2 instances to try to push the image.

Check Action

EC2 instance 1

Now that everything is ready, access EC2 instance 1.
Use SSM Session Manager to access the instances.

% aws ssm start-session --target i-0bde1cc6fc498a208
Starting session with SessionId: root-0c908f28046ae77b1
sh-4.2$
Code language: Bash (bash)

For more information on SSM Session Manager, please refer to the following page.

あわせて読みたい
Accessing Linux instance via SSM Session Manager 【Configure Linux instances to be accessed via SSM Session Manager】 We will check a configuration in which an EC2 instance is accessed via SSM Session Manag...

Change the user to operate.

sh-4.2$ sudo su --login ec2-user
[ec2-user@ip-10-0-2-38 ~]$
Code language: Bash (bash)

We have switched from ssm-user, the default user for SSM Session Manager, to ec2-user.
Now you can execute Docker commands with the authority of ec2-user.

After creating the Dockerfile for verification, run the command to push the image to the ECR repository.

[ec2-user@ip-10-0-2-38 ~]$ echo "FROM amazonlinux" > Dockerfile

[ec2-user@ip-10-0-2-38 ~]$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [account-id].dkr.ecr.ap-northeast-1.amazonaws.com
...
Login Succeeded

[ec2-user@ip-10-0-2-38 ~]$ docker build -t fa-085 .
Sending build context to Docker daemon  11.26kB
Step 1/1 : FROM amazonlinux
latest: Pulling from library/amazonlinux
12df598bc31e: Pull complete
Digest: sha256:cb8a67164376ecca3b9993e6bb7d81dd868b7836d2631582becd140c8edf27bf
Status: Downloaded newer image for amazonlinux:latest
 ---> 06c59c262be8
Successfully built 06c59c262be8
Successfully tagged fa-085:latest

[ec2-user@ip-10-0-2-38 ~]$ docker tag fa-085:latest [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest

[ec2-user@ip-10-0-2-38 ~]$ docker push [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
The push refers to repository [[account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085]
bb99a8750875: Pushed
latest: digest: sha256:ab12022e1a7cd318058af138291d638b1024dcb9844799e8014e6e37d0b35831 size: 529
Code language: Bash (bash)

We were able to push the image.

Detail of ECR Repository 2.

You can see that the image has indeed been pushed.
As you can see, we were able to push the image from EC2 instance 1 according to the repository policy.

Next, try to pull the image.

[ec2-user@ip-10-0-2-38 ~]$ docker pull [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
Error response from daemon: pull access denied for [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085, repository does not exist or may require 'docker login': denied: User: arn:aws:sts::[account-id]:assumed-role/fa-085-EC2Stack-16BBODB5DWYO1-InstanceRole1-YILWRMUJ51EE/i-0bde1cc6fc498a208 is not authorized to perform: ecr:BatchGetImage on resource: arn:aws:ecr:ap-northeast-1:[account-id]:repository/fa-085 with an explicit deny in a resource-based policy
Code language: Bash (bash)

Image pull failed.
The IAM role attached to EC2 instance 1 allows full access to the ECR.
However, the repository policy means that actions other than push were denied.

EC2 instance 2

Checking the Action of instance 2 in the same way.
First, pull the image.

% aws ssm start-session --target i-0296e9a1b5f70b522
Starting session with SessionId: root-0ce11bf400c04ba6d
sh-4.2$

sh-4.2$ sudo su --login ec2-user
[ec2-user@ip-10-0-2-59 ~]$

[ec2-user@ip-10-0-2-59 ~]$ docker pull [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
latest: Pulling from fa-085
12df598bc31e: Pull complete
Digest: sha256:ab12022e1a7cd318058af138291d638b1024dcb9844799e8014e6e37d0b35831
Status: Downloaded newer image for [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
[account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest

[ec2-user@ip-10-0-2-59 ~]$ docker image ls
REPOSITORY                                                 TAG       IMAGE ID       CREATED       SIZE
[account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085   latest    06c59c262be8   3 weeks ago   194MB
Code language: Bash (bash)

We were able to pull the image.

Next, try to push the image.

[ec2-user@ip-10-0-2-59 ~]$ echo "FROM amazonlinux" > Dockerfile

[ec2-user@ip-10-0-2-59 ~]$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [account-id].dkr.ecr.ap-northeast-1.amazonaws.com
...
Login Succeeded

[ec2-user@ip-10-0-2-59 ~]$ docker build -t fa-085 .
Sending build context to Docker daemon  11.26kB
Step 1/1 : FROM amazonlinux
latest: Pulling from library/amazonlinux
Digest: sha256:cb8a67164376ecca3b9993e6bb7d81dd868b7836d2631582becd140c8edf27bf
Status: Downloaded newer image for amazonlinux:latest
 ---> 06c59c262be8
Successfully built 06c59c262be8
Successfully tagged fa-085:latest

[ec2-user@ip-10-0-2-59 ~]$ docker tag fa-085:latest [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest

[ec2-user@ip-10-0-2-59 ~]$ docker push [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
The push refers to repository [[account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085]
bb99a8750875: Retrying in 1 second
EOF
Code language: Bash (bash)

The command to push an image to the ECR repository failed because it timed out during the push.
The IAM role attached to EC2 instance 2 also allows full access to the ECR.
However, the repository policy means that actions other than pull were denied.

EC2 instance 3

Finally, instance 3 is also checked the Action.
First, try to push the image.

% aws ssm start-session --target i-0d0cc36a5186db23b
Starting session with SessionId: root-0dbc2ca03d6941d57
sh-4.2$

sh-4.2$ sudo su --login ec2-user
[ec2-user@ip-10-0-2-67 ~]$

[ec2-user@ip-10-0-2-67 ~]$ echo "FROM amazonlinux" > Dockerfile

[ec2-user@ip-10-0-2-67 ~]$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [account-id].dkr.ecr.ap-northeast-1.amazonaws.com
...
Login Succeeded

[ec2-user@ip-10-0-2-67 ~]$ docker build -t fa-085 .
Sending build context to Docker daemon  11.26kB
Step 1/1 : FROM amazonlinux
latest: Pulling from library/amazonlinux
12df598bc31e: Pull complete
Digest: sha256:cb8a67164376ecca3b9993e6bb7d81dd868b7836d2631582becd140c8edf27bf
Status: Downloaded newer image for amazonlinux:latest
 ---> 06c59c262be8
Successfully built 06c59c262be8
Successfully tagged fa-085:latest

[ec2-user@ip-10-0-2-67 ~]$ docker tag fa-085:latest [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest

[ec2-user@ip-10-0-2-67 ~]$ docker push [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
The push refers to repository [[account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085]
bb99a8750875: Retrying in 1 second
EOF
Code language: Bash (bash)

Push failed.

Then attempt to pull the image.

[ec2-user@ip-10-0-2-67 ~]$ docker pull [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085:latest
Error response from daemon: pull access denied for [account-id].dkr.ecr.ap-northeast-1.amazonaws.com/fa-085, repository does not exist or may require 'docker login': denied: User: arn:aws:sts::[account-id]:assumed-role/fa-085-EC2Stack-16BBODB5DWYO1-InstanceRole3-12LD37CD8F85G/i-0d0cc36a5186db23b is not authorized to perform: ecr:BatchGetImage on resource: arn:aws:ecr:ap-northeast-1:[account-id]:repository/fa-085 with an explicit deny in a resource-based policy
Code language: Bash (bash)

The pull also failed.
The IAM role attached to EC2 instance 3 also allows full access to the ECR.
However, the repository policy means that the push/pull action was denied.

Summary

We have reviewed how to configure the ECR repository policy.

TOC