- Published on
GitHub Actions OIDC로 AWS 키 없이 배포 실패 해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버리스든 ECS든 S3 배포든, GitHub Actions에서 AWS ACCESS_KEY_ID/SECRET_ACCESS_KEY 없이 OIDC로 붙이면 보안은 좋아지지만 설정이 조금만 어긋나도 배포가 바로 실패합니다. 특히 AssumeRoleWithWebIdentity 단계에서 터지는 에러는 로그만 보고는 감이 안 오는 경우가 많습니다.
이 글은 GitHub Actions OIDC로 AWS 배포가 실패할 때, “어디가 잘못됐는지”를 빠르게 좁히는 실전 가이드입니다. 설정 예시(IAM OIDC Provider, Role trust policy, GitHub workflow)와 함께, 에러 메시지별 원인과 해결책을 체크리스트 형태로 정리합니다.
문맥상 함께 보면 좋은 글: GitHub Actions 캐시가 안 먹을 때 속도 3배 올린 실전
OIDC 배포 흐름 한 장 요약
OIDC 방식은 “GitHub가 짧은 수명의 ID 토큰을 발급하고, AWS STS가 그 토큰을 검증한 뒤 Role을 Assume해서 임시 자격 증명”을 발급하는 구조입니다.
- Workflow가
id-token: write권한으로 OIDC 토큰을 요청 - GitHub가 OIDC 토큰(JWT)을 발급
aws-actions/configure-aws-credentials가 STSAssumeRoleWithWebIdentity호출- AWS가 OIDC Provider 설정과 Role trust policy 조건을 검증
- 통과하면 임시 자격 증명 발급 후 배포 작업 수행
따라서 실패 지점은 크게 두 가지입니다.
- STS Assume 단계에서 실패(신뢰 정책, OIDC Provider, 조건 불일치)
- Assume은 성공했지만 실제 리소스 권한이 부족(권한 정책 문제)
가장 흔한 실패 1: No OpenIDConnect provider found
증상
로그에 보통 아래 같은 메시지가 나옵니다.
No OpenIDConnect provider found in your account for https://token.actions.githubusercontent.com
원인
AWS 계정에 GitHub OIDC Provider가 없거나, URL/Thumbprint/Audience가 잘못 등록된 경우입니다.
해결
IAM에 OIDC Provider를 추가합니다.
- Provider URL:
https://token.actions.githubusercontent.com - Audience: 보통
sts.amazonaws.com
CLI로 확인:
aws iam list-open-id-connect-providers
aws iam get-open-id-connect-provider --open-id-connect-provider-arn arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com
여기서 ClientIDList에 sts.amazonaws.com가 없으면 Role trust 조건에서 aud 검증이 실패할 수 있습니다.
가장 흔한 실패 2: Not authorized to perform sts:AssumeRoleWithWebIdentity
증상
Not authorized to perform sts:AssumeRoleWithWebIdentity- 또는
AccessDenied가 Assume 단계에서 발생
원인
Role의 Trust Policy가 OIDC 토큰의 sub/aud/iss 조건과 맞지 않거나, Principal Federated가 OIDC Provider ARN을 가리키지 않는 경우입니다.
해결: Trust Policy를 토큰 클레임에 맞게 구성
가장 안전하고 흔한 형태는 sub를 repo/branch 단위로 제한하는 것입니다.
예시 Trust Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:OWNER/REPO:ref:refs/heads/main"
}
}
}
]
}
여기서 가장 자주 틀리는 지점:
OWNER/REPO대소문자/오타ref가refs/heads/main이 아닌데 main으로 고정- PR 이벤트인데
refs/pull/...형태로 들어오는 경우 - 태그 배포인데
refs/tags/v1.2.3인데 heads로 제한
운영 팁:
- 브랜치 여러 개를 허용하려면
StringLike에 와일드카드 사용 - 태그 릴리즈를 허용하려면
refs/tags/*도 포함
예: main과 tag 배포 둘 다 허용
"StringLike": {
"token.actions.githubusercontent.com:sub": [
"repo:OWNER/REPO:ref:refs/heads/main",
"repo:OWNER/REPO:ref:refs/tags/*"
]
}
가장 흔한 실패 3: Could not load credentials from any providers
증상
aws CLI나 SDK 호출 시 자격 증명을 못 찾는다는 에러가 납니다.
원인
Workflow에서 OIDC 토큰 발급 권한이 없어서 configure-aws-credentials가 토큰을 요청하지 못하는 경우가 많습니다.
해결: permissions에 id-token: write 추가
name: deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
aws-region: ap-northeast-2
- name: Who am I
run: aws sts get-caller-identity
추가로 확인할 점:
- 조직(Org) 정책에서 GitHub Actions OIDC가 제한되어 있지 않은지
- Self-hosted runner에서 네트워크가 STS로 나갈 수 있는지
가장 흔한 실패 4: Assume은 성공했는데 배포 권한이 없음
증상
AccessDenied가 S3, ECR, ECS, CloudFormation, Lambda 등에서 발생aws sts get-caller-identity는 성공
원인
Trust Policy는 통과했지만, Role에 붙은 Permission Policy가 부족합니다.
해결: 최소 권한으로 필요한 액션만 추가
예를 들어 S3에 정적 파일 배포라면 대략 아래가 필요합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::my-bucket"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
CloudFront invalidation까지 한다면 cloudfront:CreateInvalidation도 추가해야 합니다.
OIDC 토큰 클레임 확인으로 원인 확정하기
Trust Policy 조건이 맞는지 감으로 맞추지 말고, 실제 토큰의 sub가 무엇인지 확인하면 진단이 빨라집니다.
GitHub Actions에서 OIDC 토큰을 직접 받아 디코딩(페이로드)하는 예시입니다.
- name: Debug OIDC token claims
run: |
echo "Requesting OIDC token"
resp=$(curl -sS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sts.amazonaws.com")
token=$(echo "$resp" | jq -r '.value')
echo "$token" | awk -F. '{print $2}' | base64 -d | jq
여기서 출력되는 JSON의 sub를 보고 Trust Policy의 token.actions.githubusercontent.com:sub 조건을 정확히 맞추면 됩니다.
주의:
- 토큰 전체를 로그에 그대로 찍지 말고 페이로드만 확인하세요.
- 조직 보안 정책에 따라 토큰 노출은 감사 이슈가 될 수 있습니다.
이벤트별 sub가 달라서 생기는 함정
같은 레포라도 어떤 트리거로 실행되느냐에 따라 sub 패턴이 달라질 수 있습니다.
pushto branch:repo:OWNER/REPO:ref:refs/heads/main- tag push:
repo:OWNER/REPO:ref:refs/tags/v1.0.0 - PR:
repo:OWNER/REPO:pull_request또는 PR 관련 ref
따라서 “배포는 push에서만” 같은 룰을 정하고, Trust Policy도 그에 맞게 제한하는 편이 운영이 단순합니다.
실전 권장:
- 배포 워크플로는
pushtomain또는workflow_dispatch로만 - PR 워크플로는 테스트만 수행
멀티 AWS 계정/환경에서 Role 설계 패턴
개발/스테이징/운영 계정이 분리되어 있다면, GitHub 환경(Environment)과 Role을 1:1로 매핑하는 방식이 깔끔합니다.
environment: prod는role-to-assume를 prod 계정 Role로environment: staging은 staging Role로
예시:
jobs:
deploy:
environment: prod
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::999999999999:role/gha-prod-deploy
aws-region: ap-northeast-2
- run: aws sts get-caller-identity
추가로 GitHub Environment protection rule(승인자, 브랜치 제한)을 걸면 OIDC + 승인 기반 배포가 됩니다.
빠른 복구용 체크리스트
배포가 깨졌을 때 아래 순서로 보면 대부분 10분 내로 원인이 좁혀집니다.
- Workflow에
permissions: id-token: write가 있는가 aws-actions/configure-aws-credentials@v4사용 중인가- AWS 계정에 OIDC Provider가 있고 URL이
https://token.actions.githubusercontent.com인가 - OIDC Provider의 Audience에
sts.amazonaws.com가 있는가 - Role Trust Policy의 Federated가 올바른 OIDC Provider ARN인가
- Trust Policy의
aud조건이sts.amazonaws.com로 맞는가 - Trust Policy의
sub조건이 실제 이벤트의sub와 일치하는가 aws sts get-caller-identity가 성공하는가- 이후 리소스 권한은 Permission Policy에서 허용되는가
마무리: OIDC는 “정확한 조건”이 전부다
GitHub Actions OIDC는 장기 키를 없애고, 유출 리스크를 크게 줄여주는 대신 “신뢰 정책 조건이 1글자만 달라도 배포가 실패”합니다. 하지만 반대로 말하면, 토큰 클레임을 확인하고 Trust Policy를 정확히 맞추는 순간 문제는 깔끔하게 끝납니다.
추가로 OIDC 설정 자체는 맞는데도 워크플로가 느려서 배포 피드백이 늦다면, 캐시 튜닝도 함께 보세요: GitHub Actions 캐시가 안 먹을 때 속도 3배 올린 실전
더 많은 OIDC 배포 오류 케이스를 에러 메시지별로 보고 싶다면 아래 글도 참고할 수 있습니다.