Published on

GitHub Actions OIDC STS 실패 - InvalidIdentityToken

Authors

서버리스 CI/CD 파이프라인에서 GitHub Actions → AWS STS(OIDC) 연동은 이제 사실상 표준입니다. 액세스 키를 저장하지 않아도 되고, 짧은 수명의 세션 자격 증명을 발급받아 배포할 수 있기 때문입니다.

그런데 설정이 조금만 어긋나도 STS 호출에서 아래와 같은 오류로 막힙니다.

  • InvalidIdentityToken: ...
  • The web identity token that was passed could not be validated
  • No OpenIDConnect provider found in your account for https://token.actions.githubusercontent.com

이 글에서는 GitHub Actions OIDC 토큰 → AWS STS AssumeRoleWithWebIdentity 흐름을 기준으로, InvalidIdentityToken이 나는 대표 원인을 신뢰 정책(Trust Policy), OIDC Provider, audience/subject 조건, 권한, 시간/네트워크 관점에서 빠르게 좁히는 방법을 정리합니다.

1) GitHub Actions OIDC → STS 인증 흐름 요약

GitHub Actions는 런너에서 OIDC ID 토큰(JWT)을 발급합니다.

  1. 워크플로에서 permissions: id-token: write 필요
  2. aws-actions/configure-aws-credentialstoken.actions.githubusercontent.com에서 OIDC 토큰을 받아옴
  3. AWS STS AssumeRoleWithWebIdentity 호출
  4. IAM Role의 Trust Policy가 토큰의 클레임(issuer/aud/sub 등)을 조건으로 검증

InvalidIdentityToken은 대부분 다음 중 하나입니다.

  • AWS 계정에 OIDC Provider가 없거나 issuer URL이 불일치
  • Trust Policy 조건이 토큰 클레임과 불일치 (aud, sub 등)
  • GitHub에서 토큰 발급 자체가 안 됨(permissions 누락)
  • 토큰이 만료/시간 문제/네트워크 문제로 검증 실패

2) 가장 흔한 원인: OIDC Provider 미등록 또는 URL 불일치

에러 예:

  • No OpenIDConnect provider found in your account for https://token.actions.githubusercontent.com

AWS IAM에 아래 Provider가 있어야 합니다.

  • Provider URL: https://token.actions.githubusercontent.com
  • Audience: 보통 sts.amazonaws.com

OIDC Provider 존재 여부 확인

aws iam list-open-id-connect-providers

ARN이 나오면 상세를 확인합니다.

aws iam get-open-id-connect-provider \
  --open-id-connect-provider-arn arn:aws:iam::<ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com

Url, ClientIDListsts.amazonaws.com가 포함되어야 합니다.

Terraform 예시(OIDC Provider)

resource "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = [
    "sts.amazonaws.com"
  ]

  # GitHub OIDC thumbprint는 AWS 문서/공식 가이드를 따르는 것이 안전합니다.
  # thumbprint_list는 환경에 따라 갱신 이슈가 있을 수 있어 운영 정책에 맞게 관리하세요.
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

> thumbprint 관련 이슈는 간헐적으로 인증 실패를 유발할 수 있습니다. 다만 GitHub OIDC의 경우 AWS 공식 가이드대로 구성하면 대부분 해결됩니다.

3) Trust Policy의 aud/sub 조건 불일치

InvalidIdentityToken의 핵심은 토큰은 왔는데, Role이 신뢰하지 않는 토큰이라는 점입니다. 이때는 Role의 신뢰 정책이 가장 유력합니다.

3.1 GitHub OIDC 토큰 클레임 확인(디버그)

가장 확실한 방법은 실제로 Actions에서 발급된 JWT를 디코딩해 보는 것입니다.

아래는 런너에서 OIDC 토큰을 받아(표준 환경변수 이용) payload를 확인하는 예시입니다.

name: oidc-debug
on:
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  debug:
    runs-on: ubuntu-latest
    steps:
      - name: Print OIDC token claims
        shell: bash
        run: |
          set -euo pipefail
          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" | python3 -c 'import sys,json; print(json.load(sys.stdin)["value"])')
          echo "$token" | awk -F. '{print $2}' | base64 -d 2>/dev/null | jq

여기서 확인해야 할 대표 클레임:

  • iss: https://token.actions.githubusercontent.com
  • aud: sts.amazonaws.com (또는 워크플로에서 지정한 audience)
  • sub: 보통 repo:<OWNER>/<REPO>:ref:refs/heads/<BRANCH> 혹은 repo:<OWNER>/<REPO>:environment:<ENV>

3.2 올바른 Trust Policy 예시

가장 많이 쓰는 패턴은 audsts.amazonaws.com로 고정하고, sub로 레포/브랜치/환경을 제한하는 방식입니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<ACCOUNT_ID>: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"
        }
      }
    }
  ]
}

흔한 실수

  • StringEqualssub를 박아두고 브랜치/태그/PR에서 실행되며 불일치
  • sub 패턴을 repo:owner/repo:*로 하려다 StringEquals를 사용
  • audsts.amazonaws.com가 아닌 다른 값으로 조건을 걸어놓고, 워크플로에서 audience를 지정하지 않음

PR 이벤트에서의 sub

PR에서 실행하면 subref:refs/pull/... 형태가 될 수 있습니다. 배포용 Role이라면 PR을 막는 게 일반적이므로, 배포 워크플로는 push/workflow_dispatch로 제한하고 sub도 main 브랜치만 허용하는 것이 안전합니다.

4) 워크플로 권한 누락: id-token: write

aws-actions/configure-aws-credentials를 쓰는데도 InvalidIdentityToken/토큰 발급 실패가 난다면 워크플로 상단 권한을 확인하세요.

permissions:
  id-token: write
  contents: read

조직/레포 설정에서 Actions의 기본 권한이 제한되어 있으면, 명시하지 않으면 토큰 발급이 되지 않습니다.

5) aws-actions/configure-aws-credentials 올바른 사용 예

아래 예시는 OIDC로 Role을 Assume한 뒤 STS Caller Identity를 확인합니다.

name: deploy
on:
  push:
    branches: ["main"]

permissions:
  id-token: write
  contents: read

jobs:
  aws:
    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::<ACCOUNT_ID>:role/<ROLE_NAME>
          aws-region: ap-northeast-2

      - name: Verify identity
        run: aws sts get-caller-identity

여기서도 실패한다면, 문제는 거의 항상 Role Trust Policy 또는 OIDC Provider입니다.

6) 시간/만료/네트워크 이슈: 토큰 검증 실패로 이어지는 케이스

OIDC 토큰은 짧은 유효기간을 갖고, STS는 JWT의 iat/exp 등을 검증합니다. 다음 상황에서 드물게 InvalidIdentityToken이 발생할 수 있습니다.

  • 자체 호스티드 러너에서 시스템 시간이 크게 틀어짐(NTP 미동기화)
  • 프록시/방화벽이 token.actions.githubusercontent.com 또는 AWS STS 엔드포인트 통신을 방해
  • 재시도 로직 없이 오래 대기한 뒤 만료된 토큰으로 STS 호출

자체 호스티드 러너 시간 동기화 점검

timedatectl status

NTP가 꺼져 있거나 시간이 드리프트되면 OIDC 검증이 실패할 수 있습니다.

7) 케이스별 빠른 체크리스트

문제 재현/진단을 빨리 끝내려면 아래 순서가 효율적입니다.

  1. 워크플로 권한: permissions: id-token: write 있는가?
  2. OIDC Provider: token.actions.githubusercontent.com가 IAM에 등록되어 있는가?
  3. Trust Policy:
    • Principal Federated ARN이 올바른가?
    • aud 조건이 sts.amazonaws.com와 일치하는가?
    • sub 조건이 실제 실행 컨텍스트(브랜치/태그/환경)와 일치하는가?
  4. 토큰 클레임 디코딩: Actions에서 실제 sub/aud/iss 확인
  5. 자체 호스티드 러너라면 시간 동기화/네트워크 확인

8) 보안적으로 안전한 Trust Policy 설계 팁

sub를 너무 넓게 열면(예: repo:owner/repo:*) 레포 내 어떤 워크플로든 Role을 Assume할 수 있어 위험합니다. 최소한 아래 중 하나로 제한하세요.

  • 특정 브랜치만: ref:refs/heads/main
  • GitHub Environment 기반 배포라면: environment:prod (실제 sub 형태 확인 필수)
  • 워크플로 파일 경로/리포지토리 소유자 제한(조직 정책과 함께)

또한 EKS나 Kubernetes 배포 파이프라인이라면, 인증 실패가 401/403으로 이어져 디버깅이 더 어려워집니다. Kubernetes 권한 문제와 섞여 보일 때는 원인을 분리해서 보는 것이 좋습니다. 관련해서는 Kubernetes 401 Unauthorized 원인별 해결 가이드도 함께 참고하면 진단 속도가 빨라집니다.

EKS 배포 과정에서 ECR 권한/토큰 문제(403/401)로 오해하는 경우도 많습니다. OIDC 단계에서 이미 실패하면 이후 단계는 전부 연쇄 실패하므로, 이미지 풀 권한 이슈와 구분해 보세요: EKS ImagePullBackOff 403 - ECR 권한·토큰 만료 해결, EKS Pod ImagePullBackOff 401 해결 가이드.

9) 결론: InvalidIdentityToken은 “토큰-신뢰정책 불일치”로 접근하자

InvalidIdentityToken을 해결하는 가장 확실한 방법은 감으로 설정을 바꾸는 것이 아니라,

  • 실제 발급된 JWT 클레임을 확인하고
  • 그 값에 맞춰 IAM OIDC ProviderRole Trust Policy를 정합시키는 것

입니다.

특히 sub 조건은 이벤트/브랜치/환경에 따라 쉽게 달라지므로, 배포 워크플로의 트리거를 단순화하고(push main, workflow_dispatch) Trust Policy도 그에 맞게 최소 권한으로 좁히면 재발을 크게 줄일 수 있습니다.