CodePipeline - 빌드 오류 해결 (IAM 역할에 권한 정책 연결)
CodePipeline에서 겨우겨우 Build 단계에서 DOWNLOAD_SOURCE 에러를 해결했더니 이제 Build 단계에서 PRE_BUILD 관련 에러가 터졌다. 해당 에러를 해결하는 과적을 적어보겠다.
1. CodePipeline Build 단계 오류 발생 (PRE_BUILD 단계)
1-1. 이전 과정에서 에러를 해결하고 다시 파이프라인을 돌려보았다.
- S3 권한을 수정하고 [변경 사항 릴리스]를 클릭했다.
1-2. 빌드하는 곳으로 이동해서 하단의 [세부 정보]를 클릭한다.
1-3. 빌드의 “세부 정보”를 확인했더니 이번에는 기존에 발생했던 DOWNLOAD_SOURCE관련 에러는 사라졌다.
1-4. 대신 PRE_BUILD 단계에서 새로운 에러가 발생했다.
COMMAND_EXECUTION_ERROR: Error while executing command: aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin #$#$#$.ap-northeast-2.amazonaws.com/recipia-repository. Reason: exit status 1
1-5. 조금 더 정확히 보기 위해 빌드 로그를 확인했더니 아래와 같았다.
[Container] 2023/10/28 11:15:48.610669 Running command echo Logging in to Amazon ECR...
Logging in to Amazon ECR...
[Container] 2023/10/28 11:15:48.615475 Running command aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $%$%.ap-northeast-2.amazonaws.com/recipia-repository
An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation: User: arn:aws:sts::$%$%:assumed-role/codebuild-recipia-member-build-nvpc-service-role/AWSCodeBuild-a96f8b53-10e3-4bdb-a7f9-109378a51781 is not authorized to perform: ecr:GetAuthorizationToken on resource: * because no identity-based policy allows the ecr:GetAuthorizationToken action
Error: Cannot perform an interactive login from a non TTY device
[Container] 2023/10/28 11:16:03.103564 Command did not exit successfully aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $%$%.ap-northeast-2.amazonaws.com/recipia-repository exit status 1
[Container] 2023/10/28 11:16:03.107195 Phase complete: PRE_BUILD State: FAILED
[Container] 2023/10/28 11:16:03.107211 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $%$%.ap-northeast-2.amazonaws.com/recipia-repository. Reason: exit status 1
- 이 에러의 주요 내용은 사용자(또는 서비스 역할)가 'ecr:GetAuthorizationToken' 작업을 수행할 권한이 없다는 것이다.
- AWS에서는 권한을 부여하는 정책이 존재해야 이러한 작업을 할 수 있다.
- 다시말해, CodeBuild 작업을 수행하는데 사용되는 IAM 역할(role)인 'codebuild-recipia-member-build-nvpc-service-role' 역할에 'ecr:GetAuthorizationToken' 작업을 수행할 수 있는 권한이 부여되지 않았기 때문에 접근이 거부되었던 것이다.
- 해결 방법으로는 IAM 콘솔에서 해당 역할에 이 작업을 수행할 수 있는 권한을 추가해 주면 된다.
- 즉, AWS ECR에 접근하기 위한 정책을 역할에 부여해야 한다.
1-6. 최종적으로 IAM 콘솔에서 'codebuild-recipia-member-build-nvpc-service-role'로 들어가서 아래의 정책을 입력해야한다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCodeBuildAccess",
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:GetAuthorizationToken",
"ecr:DescribeRepositories",
"ecr:GetRepositoryPolicy",
"ecr:ListImages",
"ecr:DeleteRepository",
"ecr:BatchDeleteImage",
"ecr:SetRepositoryPolicy",
"ecr:DeleteRepositoryPolicy"
],
"Resource": "*"
}
]
}
2. CodeBuild에 ECR 접근 권한을 IAM 정책에 연결하기
2-1. IAM 콘솔에서 IAM에서 역할을 클릭해서 들어간다.
2-2. 스크롤 내려서 우측의 [권한 추가] 버튼을 클릭한다. 그리고 [인라인 정책 생성]을 클릭한다
2-3. 아래와 같이 권한을 지정하는 화면이 나올텐데 처음에는 JSON이 선택되어있지않아서 아무것도 안보일것이다. '시각적' 대신 'JSON'을 클릭한다.
2-4. 정책 편집기에 아래 정책 내용을 적고 [다음]을 클릭한다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCodeBuildAccess",
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:GetAuthorizationToken",
"ecr:DescribeRepositories",
"ecr:GetRepositoryPolicy",
"ecr:ListImages",
"ecr:DeleteRepository",
"ecr:BatchDeleteImage",
"ecr:SetRepositoryPolicy",
"ecr:DeleteRepositoryPolicy"
],
"Resource": "*"
}
]
}
2-5. 그럼 검토 및 생성 페이지가 나올것이다.
- 여기서 이제 식별할 정책 이름을 적고 [정책 생성]버튼을 누른다.
2-6. 그럼 아래와 같이 방금 넣은 권한 정책이 들어간것을 볼수가 있다.
3. PRE_BUILD 오류 해결, 그리고 BUILD, POST_BUILD 에러 발생
3-1. 위에서 해당 역할에 ECR 접근 권한 정책을 추가해주고 다시 빌드를 해보자.
- 이전의 PRE_BUILD에 접근하지 못했던 에러는 수정되었다.
- 왜냐하면 방금 정책에 ECR 접근 권한들을 전부 넣어주었기 때문이다.
- 이제 다른 에러가 나왔다.
#5 [2/2] ADD build/libs/member-0.0.1-SNAPSHOT.jar member-api.jar
#5 ERROR: failed to calculate checksum of ref moby::z5ufilzi940gpc8hp3lj0ypj8: failed to walk /var/lib/docker/tmp/buildkit-mount237631583/build/libs: lstat /var/lib/docker/tmp/buildkit-mount237631583/build/libs: no such file or directory
#6 [1/2] FROM docker.io/library/amazoncorretto:17-al2-jdk@sha256:e9d48fda62bb4266a7fe4fd524e96463615a6cb3176210676814efe20ececaaa
#6 resolve docker.io/library/amazoncorretto:17-al2-jdk@sha256:e9d48fda62bb4266a7fe4fd524e96463615a6cb3176210676814efe20ececaaa 0.0s done
#6 sha256:e9d48fda62bb4266a7fe4fd524e96463615a6cb3176210676814efe20ececaaa 547B / 547B done
#6 sha256:dfbfa19bccc9104bc5d39d2c4d5b3f2ec1e721e3af5f6af945bf4d2d2ef0a038 742B / 742B done
#6 sha256:ee544fb8d73106a928b4d785c2bf5a959fcf49c98acc0008349839348a461d4a 3.07kB / 3.07kB done
#6 CANCELED
------
> [2/2] ADD build/libs/member-0.0.1-SNAPSHOT.jar member-api.jar:
------
Dockerfile:9
--------------------
7 | # Specify the built JAR file path and add it to the container as member-api.jar
8 | ARG JAR_FILE=build/libs/member-0.0.1-SNAPSHOT.jar
9 | >>> ADD ${JAR_FILE} member-api.jar
10 |
11 | # Run the JAR file
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref moby::z5ufilzi940gpc8hp3lj0ypj8: failed to walk /var/lib/docker/tmp/buildkit-mount237631583/build/libs: lstat /var/lib/docker/tmp/buildkit-mount237631583/build/libs: no such file or directory
[Container] 2023/10/28 11:39:11.768023 Command did not exit successfully docker build -t $%$%.ap-northeast-2.amazonaws.com/recipia-repository:latest . exit status 1
[Container] 2023/10/28 11:39:11.771511 Phase complete: BUILD State: FAILED
[Container] 2023/10/28 11:39:11.771526 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker build -t $%$%.ap-northeast-2.amazonaws.com/recipia-repository:latest .. Reason: exit status 1
[Container] 2023/10/28 11:39:11.808032 Entering phase POST_BUILD
[Container] 2023/10/28 11:39:11.808812 Running command echo Pushing the Docker image...
Pushing the Docker image...
[Container] 2023/10/28 11:39:11.813458 Running command docker push $%$%.ap-northeast-2.amazonaws.com/recipia-repository:latest
The push refers to repository [$%$%.ap-northeast-2.amazonaws.com/recipia-repository]
An image does not exist locally with the tag: $%$%.ap-northeast-2.amazonaws.com/recipia-repository
[Container] 2023/10/28 11:39:11.829911 Command did not exit successfully docker push $%$%.ap-northeast-2.amazonaws.com/recipia-repository:latest exit status 1
[Container] 2023/10/28 11:39:11.832842 Phase complete: POST_BUILD State: FAILED
[Container] 2023/10/28 11:39:11.832856 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker push %$%$.ap-northeast-2.amazonaws.com/recipia-repository:latest. Reason: exit status 1
4. Build 에러 해결 완료, 그리고 Build 단계 최종 성공
4-1. 위에서 발생한 오류의 핵심 부분은 다음과 같다.
#5 ERROR: failed to calculate checksum of ref moby::z5ufilzi940gpc8hp3lj0ypj8: failed to walk /var/lib/docker/tmp/buildkit-mount237631583/build/libs: lstat /var/lib/docker/tmp/buildkit-mount237631583/build/libs: no such file or directory
- 이 메시지는 Docker 빌드 프로세스가 build/libs 디렉터리를 찾을 수 없다는 것을 나타낸다. 이 디렉터리는 Dockerfile의 9번 라인에서 참조된다.
ADD ${JAR_FILE} member-api.jar
4-2. 문제점 파악하기
- build/libs/member-0.0.1-SNAPSHOT.jar 파일의 경로가 올바르지 않거나, 빌드 컨텍스트 내에 존재하지 않는다.
- 이 파일이 현재 디렉터리의 build/libs 폴더에 있는지 확인해야한다.
4-3. 해결 방법
- 내가 생각한 것은 member-0.0.1-SNAPSHOT.jar가 깃허브 저장소에 없기 때문이 아닐까? 라는 생각이 들었다.
- 그래서 GPT에게 물어봤더니 대답은 이랬다.
build/libs/member-0.0.1-SNAPSHOT.jar 파일은 Gradle 빌드 프로세스를 통해 생성되어야 한다. 이 파일은 깃허브 저장소에 미리 존재하지 않아도 됩니다. 대신, AWS CodeBuild 프로젝트의 빌드 프로세스 중에 생성되어야 한다.
4-4. 그래서 다시 Buildspec을 수정하기 위해 편집에 들어간다.
- 여기서 ./gradlew build 명령어를 추가해 준다.
- 추가한 명령어 코드
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $%$%.ap-northeast-2.amazonaws.com/recipia-repository
- echo Building the Spring Boot application...
- ./gradlew build # Gradle 빌드 명령을 추가합니다.
build:
commands:
- echo Building the Docker image...
- docker build -t $%$%.ap-northeast-2.amazonaws.com/recipia-repository:latest .
post_build:
commands:
- echo Pushing the Docker image...
- docker push $%$%.ap-northeast-2.amazonaws.com/recipia-repository:latest
4-5. 다시 실행해보니 빌드 단계가 성공했다.
4-6. 실제로 이미지가 제대로 들어갔는지 확인했더니 시간과 용량이 일치했다. (성공)
5. 마무리
AWS CodePipeline을 이용하면서 깨달은 것 중 하나는 권한과 접근 관리가 IAM 정책과 역할을 통해 대부분 해결될 수 있다는 것이다. 초기에는 IAM을 사용자 그룹이나 사용자 레벨에서만 다루었지만, 이번 기회를 통해 역할과 정책에 대한 이해가 깊어진 것 같다.
아직 IAM에 대해서 완벽하게 이해했다고는 할 수 없지만, 특정 서비스를 퍼블릭으로 열기보다는 서비스가 실행될 때 필요한 권한을 해당 서비스의 실행 역할에 정책으로 부여하는 방식을 알게 된 것 같다. 이렇게 함으로써 보안 측면에서 더 안전하며, 필요한 권한만 특정 역할에 부여하여 접근을 제어할 수 있다.
이 과정을 통해 드디어 빌드 단계를 무사히 넘겼다. 이제 다음 포스팅에서 배포 단계도 완성해보겠다.
[AWS] CodePipeline을 이용한 CI/CD (2) - 빌드 오류 해결 (S3 접근 권한)
'AWS' 카테고리의 다른 글
[AWS] ECS와 RDS 연동하기 (1) - PostgreSQL 생성하기 (3) | 2023.11.03 |
---|---|
[AWS] CodePipeline을 이용한 CI/CD (4) - 배포 오류 해결 (S3 거치지 않고 ECR에서 이미지 가져오기) (2) | 2023.11.01 |
[AWS] CodePipeline을 이용한 CI/CD (2) - 빌드 오류 해결 (S3 접근 권한) (2) | 2023.10.31 |
[AWS] CodePipeline을 이용한 CI/CD (1) - 파이프 라인 생성 (0) | 2023.10.31 |
[AWS] ECS 생성5 - ECS 생성 및 설정 (w ALB) (0) | 2023.10.31 |