CFNを使用してECRリポジトリポリシー入門

目次

CloudFormationを使用してECRリポジトリポリシー入門

ECRリポジトリはリソースベースのポリシーを設定することができます。

本ページでは、リポジトリポリシーを設定し、イメージのプッシュ/プルを制限することを目指します。

構築する環境

Diagram of introduction to ECR Repository Policies using CFN

ECRを作成します。
ECRリポジトリポリシーを設定し、リポジトリに対するイメージのプッシュ/プルを制限します。

プライベートサブネット内にEC2インスタンスを3つ作成します。
インスタンスは最新版のAmazon Linux 2とします。
3台は同様の設定を行いますが、リポジトリポリシーによって、以下の動作を実現します。

  • EC2インスタンス1:イメージのプッシュを許可する
  • EC2インスタンス2:イメージのプルを許可する
  • EC2インスタンス3:イメージのプッシュ/プルを許可しない

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

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

テンプレートファイルのポイント解説

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)

3台のEC2インスタンスを作成します。
全て同様の設定を行います。

インスタンス作成時に、ユーザデータを使用して、初期化処理を行います。
今回は以下の処理を実行します。

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

Dockerをインストール後、これを起動し、ec2-userの権限でDockerコマンドを実行できるようにします。

以下がインスタンス用のIAMロールです。

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)

各インスタンス用にIAMロールを作成します。
全て同様の設定を行います。

ポイントはAWS管理ポリシー「AmazonEC2ContainerRegistryFullAccess」をアタッチする点です。
つまりこれらのIAMロールをアタッチすることによって、3台のインスタンスはECRリポジトリにイメージをプッシュ/プルする権限が付与されるということです。

ECR

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)

RepositoryPolicyTextプロパティでリポジトリポリシーを設定します。

リポジトリポリシーは3つのステートメントで構成されています。

1つ目のステートメントはEC2インスタンス1用です。
Condition要素でArnEqualsおよびaws:PrincipalArnを使用して、EC2インスタンス1にアタッチしたIAMロールのARNを指定します。
Effect要素に「Deny」を指定した上で、NotAction要素を使用することによって、NotActionで指定されたアクション以外を拒否することになります。
NotActionにはイメージプッシュに必要なアクションを指定しましたので、インスタンス1はプッシュ以外のアクションが拒否されるということです。

2つ目のステートメントはEC2インスタンス2用です。
1つ目と同様の記法で、EC2インスタンス2にイメージプル以外のアクションを拒否します。

3つ目のステートメントは上記以外のリソースからアクセス用です。
Condition要素でArnNotEqualsおよびaws:PrincipalArnを使用して、上述の2つのIAMロールのARNを指定し、これら以外のリソースを対象とします。
Effect要素に「Deny」を、Actionに「*」を指定することによって、全てのアクションを拒否することになります。
つまり2つのEC2インスタンス以外のアクセスの場合は、全て拒否されるということです。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • ECRリポジトリ:fa-085
  • EC2インスタンス1:i-0bde1cc6fc498a208
  • EC2インスタンス2:i-0296e9a1b5f70b522
  • EC2インスタンス3:i-0d0cc36a5186db23b

作成されたリソースをAWS Management Consoleから確認します。
ECRを確認します。

Detail of ECR Repository 1.

正常にECRリポジトリが作成されています。

続いてECRのリポジトリポリシーを確認します。

Detail of ECR Repository Policy 1.

CloudFormationテンプレートで定義した通りに、リポジトリポリシーが作成されていることがわかります。

ECRにイメージをプッシュするためのコマンドを確認します。

Detail of ECR Image Push Command.

このコマンドを3つのEC2インスタンスで実行して、イメージのプッシュを試みます。

動作確認

EC2インスタンス1

準備が整いましたので、EC2インスタンス1にアクセスします。
インスタンスへのアクセスはSSM Session Managerを使用します。

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

SSM Session Managerの詳細につきましては、以下のページをご確認ください。

あわせて読みたい
LinuxインスタンスにSSM Session Manager経由でアクセスする 【LinuxインスタンスにSSM Session Manager経由でアクセスする】 EC2インスタンスにSSM Session Manager経由でアクセスする構成を確認します。 Session Manager は完全...

操作するユーザを変更します。

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

SSM Session Managerのデフォルトユーザであるssm-userから、ec2-userに切り替えました。
これでec2-userの権限で、Dockerコマンドを実行することができます。

検証用のDockerfileを作成後、ECRリポジトリにイメージをプッシュするコマンドを実行します。

[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)

イメージをプッシュすることができました。

Detail of ECR Repository 2.

確かにイメージがプッシュされていることがわかります。
このようにリポジトリポリシーに従って、EC2インスタンス1からイメージをプッシュすることができました。

続いてイメージのプルを試みます。

[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)

イメージプルに失敗しました。
EC2インスタンス1にアタッチしたIAMロールでは、ECRへのフルアクセスを許可しています。
しかしリポジトリポリシーによって、プッシュ以外のアクションは拒否されたということです。

EC2インスタンス2

同様の方法でインスタンス2も動作確認を行います。
まずイメージをプルします。

% 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)

イメージをプルすることができました。

次にイメージのプッシュを試みます。

[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)

ECRリポジトリにイメージをプッシュするコマンドを実行した結果、プッシュ時にタイムアウトして失敗しました。
EC2インスタンス2にアタッチしたIAMロールでも、ECRへのフルアクセスを許可しています。
しかしリポジトリポリシーによって、プル以外のアクションは拒否されたということです。

EC2インスタンス3

最後にインスタンス3も動作確認を行います。
まずイメージのプッシュを試みます。

% 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)

プッシュに失敗しました。

続いてイメージのプルを試みます。

[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)

プルも失敗しました。
EC2インスタンス3にアタッチしたIAMロールでも、ECRへのフルアクセスを許可しています。
しかしリポジトリポリシーによって、プッシュ/プルのアクションは拒否されたということです。

まとめ

ECRリポジトリポリシーの設定方法を確認しました。

目次