
GitHub Actions에서 AWS 키를 없애도 안전하지 않다…sub를 잠가라

GitHub Actions에서 장기 AWS 액세스 키 없이 배포하려면 공식 AWS 자격 증명 action의 OIDC 구성에 따라 IAM 공급자와 배포 역할을 만들고, 워크플로가 그 역할의 임시 자격 증명을 받게 설정한다. 이때 역할의 신뢰 정책에서 aud와 sub를 제한해야 한다. 장기 키를 삭제했더라도 sub가 넓으면 의도하지 않은 GitHub 실행이 같은 역할을 요청할 수 있다.
설정은 공급자 등록, 역할 생성과 권한 부여, 저장소에 맞는 신뢰 조건 작성, 워크플로 변경, 실행 결과 확인 순서로 진행한다. 브랜치에서 실행하는 작업과 GitHub 환경을 사용하는 작업은 기본 sub 형식이 다르다. 따라서 정책 예제를 복사하기 전에 배포 작업이 실제로 어느 저장소, 브랜치, 환경에서 실행되는지 먼저 정해야 한다.
IAM에 OIDC 공급자와 배포 역할 만들기
AWS IAM의 자격 증명 공급자 메뉴에서 OpenID Connect 공급자를 추가한다. 공급자 URL에는 https://token.actions.githubusercontent.com을 입력하고, 일반 AWS 파티션에서 공식 action을 쓴다면 대상 고객(audience)에 sts.amazonaws.com을 입력한다. 공급자 URL의 대소문자를 바꾸거나 저장소 주소를 대신 넣어서는 안 된다. 생성한 공급자의 ARN은 다음 단계의 역할 신뢰 정책에 사용한다.
이 공급자를 신뢰하는 IAM 역할을 만들고, 신뢰 정책의 Principal.Federated에 공급자 ARN을 지정한다. Action은 sts:AssumeRoleWithWebIdentity다. 이는 GitHub가 발급한 OIDC 토큰으로 AWS STS에 역할 맡기를 요청하는 경로다. 어느 실행을 받아들일지는 뒤에 추가할 Condition이 결정하므로 역할 생성 화면에서 공급자를 선택한 것만으로 설정이 끝나지 않는다.
신뢰 정책은 누가 역할을 맡을 수 있는지, 역할에 연결한 권한 정책은 맡은 뒤 무엇을 할 수 있는지 정한다. 예컨대 특정 S3 버킷에 결과물을 올리는 배포라면 그 작업에 필요한 S3 작업과 대상 리소스만 권한 정책에 넣는다. 계정 전체에 광범위한 관리 권한을 주면 sub를 좁혀도 허용된 배포 작업이 가진 권한은 과도하다. 개발과 운영 배포에 필요한 리소스가 다르다면 역할도 나눠 각각의 신뢰 범위와 권한을 정하는 편이 명확하다.
aud·sub로 저장소와 브랜치 제한하기
역할 신뢰 정책의 Condition.StringEquals에는 token.actions.githubusercontent.com:aud와 token.actions.githubusercontent.com:sub를 함께 둔다. 일반 AWS 파티션에서 공식 action을 쓰는 경우 aud 값은 sts.amazonaws.com이다. sub에는 허용할 저장소와 실행 맥락을 정확히 적는다. 두 조건이 모두 일치해야 역할 맡기가 허용되도록 구성하는 것이다.
다음은 이름만 포함하는 기존 sub 형식의 조건부 예시다. ORG와 REPO를 실제 조직명과 저장소명으로 바꾸고, 자신의 저장소가 불변 ID 형식을 쓰는지는 별도로 확인해야 한다.
- main 브랜치 작업: repo:ORG/REPO:ref:refs/heads/main
- release 브랜치 작업: repo:ORG/REPO:ref:refs/heads/release
- prod 환경을 지정한 작업: repo:ORG/REPO:environment:prod
브랜치 배포라면 허용할 ref 전체를 StringEquals로 지정한다. repo:ORG/REPO:*를 StringLike로 허용하면 같은 저장소의 다른 브랜치뿐 아니라 풀 리퀘스트나 환경 작업도 범위에 들어올 수 있다. repo:ORG/*처럼 저장소 이름을 넓히면 조직의 다른 저장소까지 포함된다. 특정 배포 작업만 신뢰하려는 역할에는 실제 sub 전체를 쓰는 편이 의도를 분명히 드러낸다.
워크플로의 push 트리거를 main으로 제한하는 것과 AWS 역할의 신뢰 조건은 서로 다른 경계다. 트리거는 해당 워크플로가 언제 시작되는지를 정하고, IAM 조건은 제시된 토큰이 역할을 맡을 수 있는지를 판단한다. 여러 배포 작업에 같은 역할을 쓰려면 각 작업의 sub를 확인해 허용 범위를 정해야 한다. 단지 워크플로 트리거가 좁다는 이유로 역할의 sub를 와일드카드로 열어 둘 필요는 없다.
환경 배포와 불변 저장소 ID 반영하기
작업에 environment: prod를 지정하면 기본 sub에는 브랜치 ref 대신 환경 이름이 들어간다. 따라서 main 브랜치용 sub를 그대로 둔 채 YAML에 환경을 추가하면 역할 맡기가 거부될 수 있다. prod 역할에는 환경 형식의 sub를 적용하고, GitHub의 prod 환경에는 배포 가능한 브랜치·태그 제한을 설정한다. 환경 이름만 담은 기본 sub로는 브랜치가 구별되지 않으므로 브랜치 제한이 필요하다면 환경 보호 규칙이 그 경계를 맡아야 한다.
GitHub의 AWS OIDC 안내는 2026년 7월 도입된 불변 sub 형식에 조직 소유자 ID와 저장소 ID가 이름 뒤에 붙는다고 설명한다. 예를 들어 해당 형식을 사용하는 저장소의 main 작업은 repo:ORG@OWNER_ID/REPO@REPO_ID:ref:refs/heads/main 형태가 된다. 이름만 적은 기존 신뢰 정책은 이런 토큰과 일치하지 않으므로 저장소가 발급하는 형식에 맞춰 갱신해야 한다.
기존 저장소가 모두 불변 형식으로 바뀐 것은 아니다. 적용 여부는 저장소의 생성 시점과 설정에 따라 다르며, GitHub Enterprise Server에는 이 불변 ID 형식이 적용되지 않는다. 환경 배포라면 저장소 부분의 ID 형식과 뒤따르는 environment:prod를 함께 반영한다. 실제 sub가 불확실할 때 토큰 클레임을 살펴볼 수 있지만, 클레임 값이 공개 로그에 남지 않도록 비공개 저장소에서 확인하는 것이 적절하다.
워크플로가 임시 자격 증명을 요청하게 바꾸기
배포 작업의 permissions에 id-token: write를 지정한다. 저장소 파일을 가져오는 작업이 있다면 contents: read도 추가한다. id-token: write는 AWS 리소스를 수정할 권한이 아니라 GitHub OIDC 토큰을 요청할 권한이다. AWS에서 수행할 수 있는 작업은 앞서 역할에 연결한 IAM 권한 정책이 결정한다.
자격 증명 단계에서는 aws-actions/configure-aws-credentials를 사용하고 role-to-assume에 배포 역할 ARN, aws-region에 사용할 리전을 지정한다. 일반 AWS 파티션에서 이 action의 기본 audience는 sts.amazonaws.com이다. 장기 키를 없애려는 구성이라면 같은 단계에 aws-access-key-id와 aws-secret-access-key를 함께 전달하지 않는다. 기존 자격 증명이 러너에 남아 있는 환경이라면 실행에 사용된 신원을 확인해 의도한 역할을 맡았는지도 살펴야 한다.
조건부 예로 main 브랜치 배포는 push 트리거의 브랜치를 main으로 제한하고, 해당 작업에 id-token: write와 필요한 저장소 읽기 권한을 부여한 뒤 역할 ARN을 전달한다. prod 환경 배포라면 작업에 environment: prod를 추가하고 IAM 신뢰 정책도 환경 형식의 sub로 바꾼다. 재사용 워크플로나 여러 배포 작업이 있으면 역할을 요청하는 실제 작업에 토큰 권한이 있는지 각각 확인한다.
OIDC 경로로 배포가 성공한 뒤에는 저장소 비밀값에 남은 장기 키와 이를 참조하는 이전 워크플로를 찾아 정리한다. 먼저 사용하지 않는 키를 비활성화하고 배포가 계속 정상적으로 실행되는지 확인한 다음 제거하면, 전환 중 남아 있던 참조를 발견하기 쉽다. 키를 삭제한 뒤에도 IAM 역할의 신뢰 조건과 권한 정책은 배포 경계로 계속 유지해야 한다.
실제 역할 신원과 CloudTrail 기록 확인하기
자격 증명 단계 다음에 aws sts get-caller-identity를 실행하면 반환된 계정 ID와 ARN으로 워크플로가 사용 중인 신원을 확인할 수 있다. 예상한 계정이나 역할이 아니라면 배포를 진행하기 전에 role-to-assume 값, 작업의 환경, 러너의 기존 자격 증명을 점검한다. 신원 확인 명령의 성공은 역할을 맡았다는 확인이지, 배포 대상 리소스에 필요한 권한이 모두 있다는 증거는 아니다.
AWS의 CloudTrail 점검 절차는 이벤트 기록에서 이벤트 소스 sts.amazonaws.com을 조회해 AssumeRoleWithWebIdentity와 GetCallerIdentity를 확인하도록 안내한다. 앞의 이벤트는 웹 자격 증명 토큰으로 역할을 맡은 호출이고, 뒤의 이벤트는 워크플로에서 신원 확인 명령을 실행했을 때의 호출이다. 실행 시각과 역할 정보를 대조하면 YAML에 적힌 ARN뿐 아니라 실제 인증 경로를 확인할 수 있다.
역할 맡기가 거부되면 aud, 공급자 ARN, 실제 sub가 신뢰 정책과 일치하는지 확인한다. 특히 브랜치 작업을 환경 작업으로 바꾸었거나 저장소가 불변 ID 형식의 sub를 발급한다면 정책 문자열도 그 형식에 맞아야 한다. 인증은 성공했지만 배포 명령이 거부된다면 신뢰 조건을 넓히기 전에 역할의 권한 정책에 필요한 작업과 대상 리소스가 포함됐는지 확인한다.
함께 읽기:
관련 기사
뉴스레터 구독
최신 Web3, AI, 암호화폐 뉴스를 이메일로 받아보세요.




