본문 바로가기
DevOps

GitHub Actions · AWS OIDC · Reusable Workflow · Terraform IaC 정리

by Rainbound-IT 2025. 9. 4.
반응형

여러 서비스 리포에서 공통으로 사용하는 Reusable Workflow를 구축하고, AWS OIDC 인증을 통해 ECR에 이미지를 푸시하도록 구성했습니다.
처음에는 workflow not found / id-token: none 오류 등 삽질이 있었는데, 최종적으로 Access 설정 + Permissions + IAM Role 신뢰 정책을 Terraform으로 관리하면서 안정화했습니다.

이번 글에서는 문제 원인 → 해결 방법 → Terraform 코드까지 정리합니다.


1. workflow not found 오류

원인

  • 서비스 레포에서 아래와 같이 호출했지만:
uses: orgname/repository-ci-templates/.github/workflows/aws-ecr-deploy.yml@main
 
  • GitHub에서 해당 워크플로를 찾지 못함 → 템플릿 리포 설정 문제.

해결

  • 템플릿 리포(repository-ci-templates) → Settings → Actions → General → Access
  • “Allow reuse of workflows from this repository” 활성화
  • 호출할 서비스 리포를 허용 목록에 추가

2. id-token: write 권한 오류

원인

  • 템플릿 워크플로 안에서 id-token: write를 요구했지만, 호출자 워크플로는 기본값(none)이라 거부됨.

해결

서비스 레포 워크플로(deploy.yaml)에 권한 선언 추가:

permissions:
  contents: read
  id-token: write
 
 

3. AWS OIDC + IAM Role 신뢰 정책

OIDC 기반 인증을 사용하면 GitHub Actions Runner에 AWS 키를 직접 저장할 필요가 없습니다.
IAM Role에 GitHub OIDC Provider를 연결하고, 특정 repo/branch만 권한을 가질 수 있도록 제한합니다.

신뢰 정책(JSON)

 
{
  "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",
          "token.actions.githubusercontent.com:sub": "repo:orgname/service-repo:ref:refs/heads/main"
        }
      }
    }
  ]
}
 
 
  • aud → 항상 sts.amazonaws.com
  • sub → repo와 브랜치 단위로 제한 (예: main 브랜치만 허용)

4. Terraform으로 OIDC + IAM Role 관리

Terraform으로 위 구성을 자동화하면 여러 레포/브랜치를 쉽게 관리할 수 있습니다.

OIDC Provider

 
resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}
 

IAM Role

 
resource "aws_iam_role" "github_oidc_role" {
  name = "github-oidc-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Federated = aws_iam_openid_connect_provider.github.arn
        }
        Action = "sts:AssumeRoleWithWebIdentity"
        Condition = {
          StringEquals = {
            "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
            # 특정 repo + main 브랜치만 허용
            "token.actions.githubusercontent.com:sub" = "repo:orgname/service-repo:ref:refs/heads/main"
          }
        }
      }
    ]
  })
}
 
 

IAM Policy (ECR 예시)

 

resource "aws_iam_role_policy_attachment" "ecr_push" {
  role       = aws_iam_role.github_oidc_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser"
}
 

5. 최종 워크플로 구조 예시

서비스 레포 (deploy.yaml)

 
name: Deploy (call reusable)

permissions:
  contents: read
  id-token: write

on:
  push:
    branches: [ "main" ]

jobs:
  call-shared:
    uses: orgname/repository-ci-templates/.github/workflows/aws-ecr-deploy.yml@main
    with:
      ecr-repository: my-service-ecr
      aws-region: ap-northeast-2
      role-arn: arn:aws:iam::123456789012:role/github-oidc-role
 
 

템플릿 리포 (aws-ecr-deploy.yml)

name: AWS ECR Deploy (Reusable)

on:
  workflow_call:
    inputs:
      ecr-repository:
        required: true
        type: string

jobs:
  deploy:
    permissions:
      id-token: write
      contents: read
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ inputs.role-arn }}
          aws-region: ${{ inputs.aws-region }}
      - name: Build & Push to ECR
        run: echo "docker build & push..."
 

마무리

  • workflow not found → 템플릿 리포 Access 설정
  • id-token 오류 → caller permissions 추가
  • AWS 인증 → GitHub OIDC + IAM Role 신뢰 정책
  • 운영 안정화 → Terraform으로 IaC 관리

이 과정을 적용하면, 새로운 서비스 레포에도 손쉽게 안전한 AWS 인증 기반 CI/CD 파이프라인을 확장할 수 있습니다.

반응형

댓글