ECRリポジトリを特定のAWSアカウントのみアクセス可能にする

# 背景

AWSでコンテナイメージを提供するための要素の一つとして、
ECRの特定のリポジトリを特定のAWSアカウントのみアクセス可能にしたい

# 実現したいこと

アカウント１のECRでコンテナイメージを提供し、アカウント２からのみアクセス可能にする

# 方針

## 特定のECRリポジトリのみアクセス可能にする

ECRリポジトリにタグを設定し、ポリシーで特定のタグがついたリポジトリにのみアクセスできるよう設定する
※アクセスさせたいリポジトリが複数ある場合に設定が楽になると思われる

https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr-supported-iam-actions-tagging.html

## 特定のAWSアカウントのみアクセス可能にする

上で作成したポリシーをアタッチしたロールを作成し、ロールを使用できるアカウントを指定することで、特定のAWSアカウントのみアクセスできるようにする

https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html

https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html

# 実現方法

アカウント１のECRに「release」と「develop」の２つのリポジトリを用意し、releaseリポジトリにのみアクセスできることを確認する


![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/2a3158ab-2299-4399-7225-1ad3a651b3d4.png)

前提として、両方のリポジトリにイメージタグv.1.0のイメージを準備してある

```
$ aws ecr list-images --repository-name release
{
    "imageIds": [
        {
            "imageTag": "v1.0",
            "imageDigest": "sha256:255d71ecc31ed42351dbc809905360aec3421a6544759315988d26ea114363b3"
        }
    ]
}

$ aws ecr list-images --repository-name develop
{
    "imageIds": [
        {
            "imageTag": "v1.0",
            "imageDigest": "sha256:255d71ecc31ed42351dbc809905360aec3421a6544759315988d26ea114363b3"
        }
    ]
}
```

## ECRリポジトリのタグ付け（アカウント１）

アクセス可能にしたいコンテナリポジトリにタグを設定する
今回は、releaseリポジトリのみアクセス可能にさせるため、releaseリポジトリにのみタグを設定する
タグは、「キー：environment、値：release」とする

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/1c65d760-8840-1201-4c07-4499590e2e8e.png)


## IAMの設定（アカウント１）

### ポリシー作成

ECRのアクセスレベルは、「リスト」と「読み込み」を指定したタグにのみ実行可能なように設定した
また、認証トークンの取得に関しては、リポジトリに設定したタグに紐付かないので、制限をかけない形で別途設定した

Jsonで表示したポリシーは以下

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecr:GetRegistryPolicy",
                "ecr:DescribeImageScanFindings",
                "ecr:GetLifecyclePolicyPreview",
                "ecr:DescribeRegistry",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetRepositoryPolicy",
                "ecr:GetLifecyclePolicy"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "ecr:ResourceTag/environment": "release"
                }
            }
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ecr:GetAuthorizationToken",
            "Resource": "*"
        }
    ]
}
```

### ロール作成

今回は別のAWSアカウントで使用するロールを作成する
※サードパーティーにロールを使用させる場合は`外部ID`を使用するのがベストプラクティスとのこと
　後で使うのでメモっておく
 
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/72d1b60e-b5d6-1634-f859-f20597167409.png)


ポリシーは上で作成した「allow_ecr_release」を選択する


![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/23882d2a-0e64-1261-ec95-fd6153592126.png)

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/446d52a0-e070-9507-8c33-5d9ab879419b.png)



作成したロールの信頼関係を確認するとアカウント２のrootアカウントが対象になっている
特定のユーザを対象にしたい場合は「root」を「user/XXXXX」に書き換える


![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/61fe399a-db80-92a2-bf85-0112019eddfb.png)

変更前

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/dddf4732-6c5b-9927-dc8e-aa1472aeacaf.png)

変更後

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401168/8e06dfe6-5caf-a590-c76a-09ac141378c6.png)

## ECRからイメージのプル（アカウント２）

今回はEC2でイメージをプルするとこまで実施する。
※前提として、EC2にはAWS CLIとDockerがインストールしてある

### ロールの認証情報取得

現在のアカウント情報を確認し、アカウント２であることがわかる

```
$ aws sts get-caller-identity
{
    "Account": "{アカウント２_aws_account_id}",
    "UserId": "XXXXX",
    "Arn": "arn:aws:iam::{アカウント２_aws_account_id}:user/XXXXXX"
}
```

アカウント２でアカウント１のロールの認証情報を取得する
※ロール作成時に設定した`外部ID`はここで使用する

```
$ aws sts assume-role --role-arn "arn:aws:iam::{アカウント１_aws_account_id}:role/allow_ecr_release" --role-session-name allow_ecr_release --external-id test
{
    "AssumedRoleUser": {
        "AssumedRoleId": "XXXXX:allow_ecr_release",
        "Arn": "arn:aws:sts::{アカウント１_aws_account_id}:assumed-role/allow_ecr_release/allow_ecr_release"
    },
    "Credentials": {
        "SecretAccessKey": "XXXXX",
        "SessionToken": "XXXXX",
        "Expiration": "2021-04-07T16:37:46Z",
        "AccessKeyId": "XXXXX"
    }
}
```

取得した認証情報を環境変数に設定する

```
$ export AWS_ACCESS_KEY_ID=XXXXX
$ export AWS_SECRET_ACCESS_KEY=XXXXX
$ export AWS_SESSION_TOKEN=XXXXX
```

現在のアカウント情報を確認し、アカウント１のallow_ecr_releaseロールになっていることがわかる

```
$ aws sts get-caller-identity
{
    "Account": "{アカウント１_aws_account_id}",
    "UserId": "XXXXX:allow_ecr_release",
    "Arn": "arn:aws:sts::{アカウント１_aws_account_id}:assumed-role/allow_ecr_release/allow_ecr_release"
}
```

### ECRへのアクセス確認

releaseリポジトリの情報のみ取得できている事がわかる

```
$ aws ecr describe-images --repository-name release
{
    "imageDetails": [
        {
            "artifactMediaType": "application/vnd.docker.container.image.v1+json",
            "imageSizeInBytes": 83920901,
            "imageDigest": "sha256:255d71ecc31ed42351dbc809905360aec3421a6544759315988d26ea114363b3",
            "imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "imageTags": [
                "v1.0"
            ],
            "registryId": "{アカウント１_aws_account_id}",
            "repositoryName": "release",
            "imagePushedAt": 1617543739.0
        }
    ]
}
```

```
$ aws ecr describe-images --repository-name develop

An error occurred (AccessDeniedException) when calling the DescribeImages operation: User: arn:aws:sts::{アカウント１_aws_account_id}:assumed-role/allow_ecr_release/allow_ecr_release is not authorized to perform: ecr:DescribeImages on resource: arn:aws:ecr:{region}:{アカウント１_aws_account_id}:repository/develop
```

### 認証

ECRプライベートレジストリに対してDockerを認証させる

```
$ aws ecr get-login-password --region {region} | docker login --username AWS --password-stdin {アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com
```

### コンテナイメージのプル

releaseリポジトリのコンテナイメージのみプルできている事がわかる

```
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
```

```
$ docker pull {アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com/release:v1.0
v1.0: Pulling from release
6e0aa5e7af40: Pull complete
d47239a868b3: Pull complete
49cbb10cca85: Pull complete
2e8c0debf4c7: Pull complete
0f33714d40be: Pull complete
1290c8a7c595: Pull complete
Digest: sha256:255d71ecc31ed42351dbc809905360aec3421a6544759315988d26ea114363b3
Status: Downloaded newer image for {アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com/release:v1.0
{アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com/release:v1.0
```

```
$ docker pull {アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com/develop:v1.0
Error response from daemon: pull access denied for {アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com/develop, repository does not exist or may require 'docker login': denied: User: arn:aws:sts::{アカウント１_aws_account_id}:assumed-role/allow_ecr_release/allow_ecr_release is not authorized to perform: ecr:BatchGetImage on resource: arn:aws:ecr:{region}:{アカウント１_aws_account_id}:repository/develop
```

```
$ docker images
REPOSITORY                                                  TAG                 IMAGE ID            CREATED             SIZE
{アカウント１_aws_account_id}.dkr.ecr.{region}.amazonaws.com/release   v1.0                935e47d46598        5 days ago          196MB
```

# 最後に

検証した後にクロスアカウントレプリケーションができることを知った。。。

https://aws.amazon.com/jp/blogs/news/cross-region-replication-in-amazon-ecr-has-landed-jp/