CloudFormationを使用してECRリポジトリポリシー入門
ECRリポジトリはリソースベースのポリシーを設定することができます。
本ページでは、リポジトリポリシーを設定し、イメージのプッシュ/プルを制限することを目指します。
構築する環境
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スタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- ECRリポジトリ:fa-085
- EC2インスタンス1:i-0bde1cc6fc498a208
- EC2インスタンス2:i-0296e9a1b5f70b522
- EC2インスタンス3:i-0d0cc36a5186db23b
作成されたリソースをAWS Management Consoleから確認します。
ECRを確認します。
正常にECRリポジトリが作成されています。
続いてECRのリポジトリポリシーを確認します。
CloudFormationテンプレートで定義した通りに、リポジトリポリシーが作成されていることがわかります。
ECRにイメージをプッシュするためのコマンドを確認します。
このコマンドを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の詳細につきましては、以下のページをご確認ください。
操作するユーザを変更します。
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)
イメージをプッシュすることができました。
確かにイメージがプッシュされていることがわかります。
このようにリポジトリポリシーに従って、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リポジトリポリシーの設定方法を確認しました。