https://github.com/lhoju0158

개발 끄적끄적

[GitHub Actions + AWS] IAM role 접근 권한에 따른 오류 해결 + GitHub Actions 성공 기준

lhoju0158 2025. 7. 15. 01:17

CICD용 .yml 파일을 작성 중 생긴 오류를 정리한 글이다.

 

지난 글에 이어서 작성된 글이다.

 

1. 문제 상황

 

https://lhoju0158.tistory.com/47

 

[Github actions] 엑세스 키 없을 때 S3, Cloudfront 배포 자동화

좋은 기회로 AWS 자원을 지원받는 일이 있었다. 근데.. S3와 Cloudfront에 대한 엑세스 권한을 주지 않아, 배포 자동화가 힘들었다. 그래서 생각해 낸 편법이 EC2에 접근해서, S3와 Cloudfront에 배포하는

lhoju0158.tistory.com

 

사전 정보를 주자면, S3 + EC2를 가지고 있는 계정과 Cloudfront 계정은 서로 다르다. 

 

PR 이후 팀원이 다음 코멘트를 남겨줬다. 

 

 

정리를 하면 내 기존 코드는

EC2에서 S3 업로드, Cloudfront 캐시 초기화 모두를 담당한다.

팀원분의 조언은

EC2에서 S3 업로드, github action이 캐시 초기화를 담당하는 것이 어떤가 이다.

 

맞는 말이라 코드를 수정했다. 

 

name: PROD용 S3에 업로드 및 CLOUDFRONT 초기화

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: GitHub 코드 체크아웃
        uses: actions/checkout@v4

      - name: EC2에 SSH 접속 후 배포
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USER }}
          key: ${{ secrets.EC2_SSH_KEY }}
          port: 22
          script: |
            cd ~/client
            git pull origin main
            npm install
            npm run build

            # S3 업로드
            aws s3 sync ./dist ${{ secrets.S3_URL }} --delete

            # CloudFront 초기화
            mkdir -p ~/.aws
            cat > ~/.aws/credentials <<EOL
            [default]
            aws_access_key_id=${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
            aws_secret_access_key=${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
            region=${{ secrets.AWS_REGION_PROD }}
            EOL

            aws cloudfront create-invalidation \
              --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID_PROD }} \
              --paths "/*"

 

위 코드를

 

name: PROD용 S3에 업로드 및 CLOUDFRONT 초기화

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: EC2에 SSH 접속 후 배포
        uses: appleboy/ssh-action@v1.0.0
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USER }}
          key: ${{ secrets.EC2_SSH_KEY }}
          port: 22
          script: |
            cd ~/client
            git pull origin main
            npm install
            npm run build
            # S3 업로드
            aws s3 sync ./dist ${{ secrets.S3_URL }} --delete
      
      - name: AWS 로그인
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
          aws-region: ${{ secrets.AWS_REGION_PROD }}

      - name: CloudFront 캐시 무효화
        run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID_PROD }} --paths "/*"

 

다음과 같이 정리하면 가독성도 좋고, 접근 권한 분리 측면에서도 나아 보인다. (역시 멋진 팀원분..)

 

아무튼 해당 .yml을 push했는데..

 

 

다음과 같은 오류가 생긴다.. 해당 오류 로그는 다음과 같다.

 

err: fatal error: An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

 

즉, S3 업로드를 하고 싶은데 접근이 거절된다는 오류다.

 

바꾼건 Cloudfront 주체인데, 왜 S3업로드가 안될까?

 

2. 해결

원인은 EC2에 저장된 키 때문이었다. 

 

기존 코드 중

 

mkdir -p ~/.aws
cat > ~/.aws/credentials <<EOL
[default]
aws_access_key_id=${{ secrets.AWS_ACCESS_KEY_ID_PROD }}
aws_secret_access_key=${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }}
region=${{ secrets.AWS_REGION_PROD }}
EOL

 

을 이용해 EC2에 Cloudfront 계정에 대한 키를 저장했는데 이후 .yml 코드 수정 사이에 EC2에 저장된 키를 초기화 하지 않았다. 이 상황에서 수정된 .yml을 가지고 액션을 하니, EC2는 S3 업로드 시 기존 IAM role이 아닌 Cloudfront 계정 키로 S3 업로드를 진행한다. Cloudfront 계정은 S3 업로드에 대한 접근 권한이 없으므로 접근이 거절되는 것이다. 

 

그래서 EC2에 직접 키를 초기화 한다. 

 

rm -rf ~/.aws
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

 

이후 업로드를 진행하면 정상적으로 된다.

 

 

 

사진을 보면 기존에는 S3 업로드가 거절되지만, 키 초기화 이후, S3 업로드가 가능함을 알 수 있다. 

 

 

동일한 코드에도 불구하고, Github Actions이 성공함을 볼 수 있다. 

 

그럼 여기서 생긴 의문이 하나 있다.

 

기존 파일 (EC2가 Cloudfront 초기화도 담당하는 경우)는 왜 S3 업로드 오류가 안생겼는가?

 

외부적으로는 성공한 듯 보이지만,

 

 

자세히 보면 S3업로드 시 오류가 발생함을 알 수 있다. Step 단위 결과에 따라 성공 여부를 결정 지어 S3 업로드는 실패했지만, Cloudfront 초기화는 성공해 중간 실패에 대해 전달받지 못한 것으로 추측된다. 

 

3. 후기

GitHub Actions를 위한 .yml 파일 작성 시 기능에 따라 Step을 나눠 위와 같이 실패를 인식하지 못한 경우를 방지해야겠다. 또한 단순 액션 결과만을 보고 넘기지 말고 로그를 면밀히 파악해야겠다.