
GitHub Actions에서 AWS 장기 키를 없애라…OIDC의 핵심은 sub 조건이다

GitHub Actions의 배포 job에서 AWS 장기 액세스 키를 제거하려면 AWS IAM에 GitHub OIDC 공급자를 등록하고, IAM 역할의 신뢰 정책에서 토큰의 aud와 sub를 배포 저장소의 실제 실행 맥락에 맞춰 제한한다. job에는 id-token: write를 주고 aws-actions/configure-aws-credentials로 그 역할의 임시 자격 증명을 받는다. GitHub의 AWS OIDC 설정 안내는 이 흐름으로 장기 AWS 자격 증명을 GitHub Secrets에 보관하지 않고 AWS 리소스에 접근하는 방법을 제시한다.
권한의 경계는 워크플로 트리거나 Secrets 설정만으로 정해지지 않는다. AWS가 역할 수임 요청을 허용할 때 비교하는 sub에 저장소와 브랜치 또는 환경이 들어가야 한다. 같은 저장소의 여러 워크플로가 같은 실행 맥락을 공유하면 기본 sub도 같을 수 있으므로, 특정 워크플로 파일까지 구분해야 하는 배포에는 별도의 주체 사용자 지정이 필요하다.
IAM 공급자와 배포 역할을 만든다
IAM의 자격 증명 공급자에서 OpenID Connect 공급자를 추가하고 공급자 URL을 https://token.actions.githubusercontent.com으로, 대상 값을 sts.amazonaws.com으로 지정한다. 같은 AWS 계정에 GitHub 공급자가 이미 등록되어 있으면 기존 공급자를 사용한다. 이어 IAM 역할을 만들 때 신뢰할 엔터티로 웹 자격 증명을 선택하고 해당 공급자를 연결한다. 상용 AWS 파티션에서 공식 자격 증명 액션을 사용하는 경우의 값이며, 다른 파티션이나 사용자 지정 audience를 쓴다면 토큰의 aud와 IAM 조건을 함께 바꿔야 한다.
AWS의 OIDC 역할 생성 안내는 역할의 신뢰 정책과 권한 정책을 구분한다. 신뢰 정책은 GitHub의 어떤 실행이 역할을 맡을지 정하고, 권한 정책은 역할을 맡은 뒤 어떤 AWS 작업과 리소스에 접근할지 정한다. 예를 들어 배포가 특정 버킷만 갱신한다면 필요한 S3 작업과 그 버킷의 ARN만 권한 정책에 넣어야 한다. sub를 좁혀도 역할 자체에 광범위한 관리 권한을 부여하면 허용된 작업이 갖는 권한까지 넓어진다.
IAM 콘솔에서 GitHub 조직은 지정하더라도 저장소나 브랜치 입력을 비우면 해당 범위가 와일드카드가 될 수 있다. 역할 생성 뒤 신뢰 관계의 JSON을 열어 의도한 범위가 그대로 들어갔는지 확인한다. GitHub OIDC 공급자를 신뢰하는 역할은 sub 조건이 빠졌거나 값이 와일드카드만으로 이뤄졌다면 IAM이 정책 생성 또는 갱신을 거부한다. 다만 형식상 허용되는 넓은 패턴도 배포와 무관한 실행을 받아들일 수 있다.
실제 sub 형식으로 신뢰 정책을 쓴다
다음은 새 형식의 주체를 쓰는 저장소에서 main 브랜치 실행만 허용하는 조건부 예시다. 계정 번호, 조직과 저장소 이름, 소유자·저장소 ID는 설명을 위한 값이다. 운영 환경에서는 자신의 계정과 저장소에 맞춰 전부 바꾸고, 앞에서 만든 공급자의 ARN을 Principal에 넣는다. StringEquals로 aud와 sub를 모두 정확하게 비교하므로 dev 브랜치의 토큰은 이 역할을 맡을 수 없다.
역할 신뢰 정책 예시: {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Federated":"arn:aws:iam::111122223333:oidc-provider/token.actions.githubusercontent.com"},"Action":"sts:AssumeRoleWithWebIdentity","Condition":{"StringEquals":{"token.actions.githubusercontent.com:aud":"sts.amazonaws.com","token.actions.githubusercontent.com:sub":"repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main"}}}]}
GitHub의 OIDC 주체 형식 안내에 따르면 2026년 7월 15일 이후 생성된 저장소의 기본 sub에는 소유자 ID와 저장소 ID가 이름 뒤에 붙는다. 그보다 먼저 생성된 저장소는 별도로 전환하지 않았다면 repo:octo-org/octo-repo:ref:refs/heads/main 같은 이름 기반 형식을 유지한다. 저장소 이름 변경이나 이전 뒤에도 새 형식으로 바뀌며, 이 기본 형식 변경은 GitHub Enterprise Server에는 적용되지 않는다.
따라서 예시의 @ 뒤 숫자를 자신의 저장소 ID로 바꾸는 것만큼, 실제 저장소가 어느 형식을 쓰는지 먼저 알아야 한다. 이름 기반 저장소에 ID 포함 조건을 넣거나 그 반대로 넣으면 토큰의 sub가 정책과 일치하지 않아 역할 수임이 거부된다. repo:OWNER/REPO:*처럼 저장소 뒤에 와일드카드를 붙이면 브랜치뿐 아니라 같은 저장소의 환경과 풀 리퀘스트 맥락까지 허용할 수 있으므로, 배포 역할에는 필요한 문맥만 명시한다.
환경 배포와 재사용 워크플로는 따로 제한한다
배포 job에 environment: prod를 지정하면 기본 sub에는 브랜치 참조 대신 environment:prod가 들어간다. ID 포함 형식을 쓰는 저장소라면 예시 주체는 repo:octo-org@123456/octo-repo@456789:environment:prod가 된다. 앞의 main 브랜치용 정책은 이 토큰과 일치하지 않으므로 환경 배포 역할의 sub를 해당 환경 형식으로 바꿔야 한다. 환경 이름에 콜론이 있다면 sub 값에는 그 문자가 %3A로 인코딩된다.
환경을 신뢰 조건에 넣을 때에는 GitHub 환경의 배포 브랜치·태그 제한과 필요한 승인 규칙도 구성한다. 환경 이름이 같다는 조건은 그 환경을 사용할 수 있는 job을 뜻하며, 특정 브랜치를 sub 안에 동시에 적었다는 뜻은 아니다. 브랜치 보호와 환경 보호를 함께 두면 브랜치 이벤트와 배포 승인이 각각 의도한 경로로 제한되는지 분명해진다.
기본 sub는 같은 저장소와 main 브랜치에서 실행되는 서로 다른 워크플로 파일을 식별하지 못한다. 특정 재사용 워크플로를 통해서만 AWS 역할을 받게 하려면 GitHub의 OIDC 주체 사용자 지정에서 repo, context, job_workflow_ref를 포함시키고 IAM 신뢰 정책도 새 전체 sub와 일치시켜야 한다. 사용자 지정은 기본 형식을 대체하며, ID 포함 형식을 쓰는 저장소에서는 주체를 사용자 지정해도 소유자·저장소 ID가 repo 부분에 남는다. 신뢰 정책을 먼저 준비한 뒤 주체 형식을 바꾸면 전환 중 역할 수임 실패를 줄일 수 있다.
배포 job에 토큰 권한과 역할 ARN을 연결한다
워크플로의 main 브랜치 push 트리거는 배포 실행 횟수를 좁히는 장치다. AWS 역할의 접근 경계는 IAM 신뢰 정책이 맡으므로 트리거만 설정하고 sub를 넓게 두면 다른 실행 맥락의 역할 수임 요청을 막지 못한다. 토큰 권한은 워크플로 전체보다 실제 배포 job의 permissions에 두고, 저장소 파일을 체크아웃한다면 contents: read를 함께 적는다. id-token: write는 OIDC 토큰 요청 권한이며 AWS 리소스 쓰기 권한을 직접 부여하지 않는다.
- 배포 job에 runs-on을 지정하고 permissions 아래 id-token: write를 명시한다. actions/checkout으로 소스를 가져오는 경우에는 contents: read도 같은 위치에 둔다. job에 환경을 쓰는 경우 environment: prod를 넣고, 그 값과 앞 절의 신뢰 조건을 맞춘다.
- 자격 증명 설정 단계에 uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502를 넣는다. 액션을 갱신할 때도 검토한 커밋으로 고정해 태그 이동에 따른 실행 코드 변경을 통제한다.
- 같은 단계의 with에 role-to-assume으로 배포용 IAM 역할 ARN을, aws-region으로 배포 대상 리전을 전달한다. 장기 액세스 키 ID와 비밀 키를 액션 입력, 환경 변수 또는 GitHub Secrets에 함께 남겨 두지 않는다. 남아 있는 정적 자격 증명이 있다면 의도한 OIDC 경로로 실행되는지 혼동을 일으킬 수 있다.
- 다음 단계에서 aws sts get-caller-identity를 실행해 예상한 AWS 계정과 역할 세션이 사용되는지 확인한 뒤 배포 명령을 실행한다. 배포 명령이 요구하는 S3, ECR 또는 다른 서비스 권한은 신뢰 정책이 아니라 역할의 권한 정책에 필요한 리소스 범위로 추가한다.
자격 증명 액션은 GitHub의 OIDC 토큰을 AWS STS에 전달해 역할을 맡고, 뒤따르는 AWS CLI나 SDK 단계가 사용할 임시 자격 증명을 설정한다. 액션의 버전 고정은 실행 코드를 통제하기 위한 조치이고, 누가 역할을 맡는지는 여전히 IAM의 aud·sub 조건이 결정한다. 역할 ARN은 워크플로에 넣을 수 있지만, 계정과 역할 이름을 공개 저장소에 표시할지 여부는 조직의 공개 정책에 맞춰 판단한다.
거부된 단계에 따라 오류를 찾는다
OIDC 토큰을 요청하지 못한다면 배포 job의 permissions에 id-token: write가 있는지 먼저 확인한다. sts:AssumeRoleWithWebIdentity 단계에서 거부되면 IAM 공급자 URL과 audience, role-to-assume의 ARN, 신뢰 정책의 aud·sub를 차례로 대조한다. 이때 실행한 브랜치가 main인지, job에 환경이 지정됐는지, 저장소가 ID 포함 주체 형식을 쓰는지 확인하면 흔한 문자열 불일치를 찾을 수 있다. 환경 이름의 대소문자나 인코딩도 정확히 일치해야 한다.
역할 수임까지 성공하고 실제 배포 명령만 실패하면 신뢰 정책보다는 역할의 권한 정책, 리소스 ARN, 대상 리전을 살핀다. 반대로 예상하지 않은 job이 역할을 맡는다면 sub의 와일드카드와 환경 보호 규칙, 같은 브랜치의 다른 워크플로를 점검한다. 허용한 job의 성공과 허용하지 않은 브랜치·저장소의 수임 거부를 함께 확인하면 신뢰 정책이 의도한 경계로 작동하는지 알 수 있다.
함께 읽기:
관련 기사
뉴스레터 구독
최신 Web3, AI, 암호화폐 뉴스를 이메일로 받아보세요.




