Search

AWS ECR 교차 계정 복제

다른 AWS 계정 사이에 ECR 레포지토리 복제(replication)를 구성하는 방법에 대한 설명이다:
기본적으론 위 블로그 글들과 유사하지만, CloudTrail에서 디버깅 방법 그리고 조금 특수한 상황에서 겪은 정보를 추가했다.

개요

계정 A(111122223333)의 ECR에서 특정 패턴(접두사)의 레포지토리의 새 이미지 태그가 푸시되면 계정B(444455556666)로 복제한다(그림의 pusher는 새 이미지 태그를 푸시하는 곳으로 구성되어 있지만 설명은 생략한다).

복제 구성

{ "destinations": [ { "registryId": "444455556666", "region": "us-west-2" }, { "registryId": "444455556666", "region": "ap-northeast-2" } ], "repositoryFilters": [ { "filter": "prefix/pattern", "filterType": "PREFIX_MATCH" } ] }
JSON
복사
먼저 A계정의 ECR Private registry의 Settings > Replication을 고른다:
1.
대상 유형 선택: 교차 계정에 대해서만 활성화.
2.
교차 계정 복제: 대상이 되는 Destination Account ID를 써준다(B, 444455556666). 나는 대상 리전을 두 군데를 했다.
위 팝업에 나오는 레지스트리 정책이 중요하다. 후술
3.
필터: 모든 레포지토리를 복제하지 않으려면, 복제 대상이 될 레포지토리의 이름 접두사를 써준다.
4.
검토 및 제출: destinations[].registryId444455556666(B)여야 한다.

대상 레지스트리 정책

앞서 복제 구성 2번의 팝업에 대한 내용이다. 대상 ECR 레지스트리에 복제가 가능하도록 권한 구성을 해야한다(처음엔 이 부분을 놓쳐서 진행이 안됐다).
B 계정 ECR의 Settings > Permissions에서 권한을 구성한다.
{ "Sid": "replication from A", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111122223333:root" }, "Action": [ "ecr:CreateRepository", "ecr:ReplicateImage" ], "Resource": "arn:aws:ecr:us-west-2:444455556666:repository/*" }
JSON
복사
정책 타입은 Cross account replication policy를 쓴다(지금보니 이 계정은 언어 설정이 영어로 되어 있네 ). 그럼 자동으로 Action에 ecr:CreateRepositoryecr:ReplicateImage 로 채워준다. 권한을 줄(grant) 계정엔 A의 id를 써준다.
JSON으로도 쓸 수 있어서 IaC로 관리한다면 복사 또는 참고하여 사용하면 된다:
source에 해당하는 A의 계정 id는 Principal
dest에 해당하는 B의 계정 id는 Resource에 있다.

안된다?

구성을 다 했으니 스블렁스블렁한 마음으로 A 계정 ECR에 이미지를 푸시해봤다.
하지만 복제가 이루어지지 않았다(지금은 해결했지만, 당시엔 No repository … 이런 식으로 레지스트리가 비어 있었다). 앞선 과정에서 어떤 구성의 오류일까? 단순히 오타 문젠 아니었다. 문제 상황을 보기 위해 CloudTrail 로그를 확인했다.
이벤트를 발생시키는 A 계정의 CloudTrail > 이벤트 기록(Event History)에서 ecr.amazonaws.com 으로 이벤트 소스를 필터하고 날짜 범위를 좁혀 검색한다. 이미지가 푸시 된 시간대(2023-12-28T19:06:32KST~)에 꽤 많은 ReplicateImage 이벤트가 있다(수상하다. 왜 여러개가?)
{ "eventVersion": "1.08", "userIdentity": { ... }, "eventTime": "2023-12-28T10:06:33Z", "eventSource": "ecr.amazonaws.com", "eventName": "ReplicateImage", "awsRegion": "us-west-2", ... "resources": [ { "accountId": "111122223333", "ARN": "arn:aws:ecr:us-west-2:111122223333:repository/prefix/pattern/repo" } ], "eventType": "AwsApiCall", "managementEvent": true, "recipientAccountId": "111122223333", "eventCategory": "Management" }
JSON
복사
1초 직후(2023-12-28T10:06:33Z)에 실행된 이벤트를 살펴보면, resources[0].accountId 가 자기 자신, A로 되어 있다. ??? 음 자세히 살펴보니 리전은 us-west-2이다. 생각해보니 나는 이미지를 A ap-northeast-2에 푸시했는데, 복제 규칙 구성은 A us-west-2에 하였다. 알고 보니 A 계정에선 apne2 → uswe2로 교차 리전 복제 구성이 이미 되어 있었다.
복제된 이미지에 대해선 다시 복제가 되지 않는다는 것인데, 문서에도 그런 제약조건이 써 있다:
A replication action only occurs once per image push. For example, if you configured cross-Region replication from us-west-2 to us-east-1 and from us-east-1 to us-east-2, an image pushed to us-west-2 replicates to only us-east-1, it doesn't replicate again to us-east-2. This behavior applies to both cross-Region and cross-account replication.
즉, A → B → C 처럼 cascading 복제는 안된다는 것이다.
그도 그럴 것이 ECR 레포지토리 복제 시 이름을 같게 쓸 수 밖에 없도록 제한해놨다. 만약 A, B 서로가 양방향 복제를 한다면 끝이 나지 않을 것이다.
세상에 요런건 없습니다!
따라서 같은 교차 계정 복제 규칙 구성은 A 계정 ap-northeast-2에 해주었다. 대상 계정의 리전도 두 곳을 했는데, 정책 역시 각각 만들어 주어야 한다.

된다

{ "eventVersion": "1.08", "userIdentity": { .. }, "eventTime": "2023-12-28T14:24:29Z", "eventSource": "ecr.amazonaws.com", "eventName": "ReplicateImage", "awsRegion": "us-west-2", ... "resources": [ { "accountId": "444455556666", "ARN": "arn:aws:ecr:us-west-2:444455556666:repository/zeroth/whisper-server" } ], "eventType": "AwsApiCall", "managementEvent": true, "recipientAccountId": "111122223333", "sharedEventID": "<redacted>", "eventCategory": "Management" }
JSON
복사
이번엔 성공했다(해결에 오래 걸리지 않았다. 밥먹고 운동하고 와서 확인하여 시차가 좀 있다 ㅎㅎ ). A 계정 ECR 레포에 이미지 푸시가 된 순간, CreateRepository 이벤트가 먼저 발생한다. B 계정 ECR엔 해당 레포가 없기 때문. 그리고 ReplicateImage를 하는데, JSON 페이로드를 확인하면 이번엔 resources가 확실히 B의 ID로 쓰여 있다.

습득 교훈

역시 클라우드(AWS)는 보안이 알파이자 오메가이다. 각 계정, 서비스끼리 연결될 수 있도록 권한/정책을 잘 구성해야 한다.
로그(CloudTrail)를 보고 확인하자. (한석봉 어머니가 아닌 이상) 볼 수 있다면 더 잘 해결할 수 있다.
복제 시간이 오래 걸릴 수도 있다는 제약도 있었지만, 내 경우, 8G 정도의 크기의 이미지, 는 해당되지 않았다(1초만에 됨).
The majority of images replicate in less than 30 minutes, but in rare cases the replication might take longer.
대상 리소스가 크다면 리소스 할당량도 살펴봐야 할 것이다.