lhywk 님의 블로그

IAM Federation + OIDC 본문

AWS

IAM Federation + OIDC

lhywk 2026. 5. 2. 12:31

페더레이션이라는 단어가 낯설 수 있지만, 개념 자체는 간단합니다.

"AWS 외부에 이미 존재하는 자격 증명 시스템을 AWS에서도 그대로 신뢰해 사용하는 것"

 

여러분이 이미 경험한 사례가 있습니다. 어떤 사이트에 "Google 계정으로 로그인"하면, 그 사이트는 여러분의 Google 비밀번호를 모릅니다. Google이 "이 사람 진짜 맞아요"라고 보증해주는 것입니다. AWS Federation도 동일한 원리입니다.

이 글에서 다루는 내용:

  • OIDC Federation: GitHub Actions → AWS 배포를 Access Key 없이 구현
  • SAML 2.0 Federation: 기업 Active Directory 계정으로 AWS 콘솔 로그인
  • 두 방식의 동작 원리와 신뢰 정책 구조

특히 "GitHub Actions에서 AWS 배포할 때 Access Key를 GitHub Secrets에 저장하는 것" 은 매우 흔하지만 보안상 좋지 않은 방법입니다. OIDC로 이를 완전히 없애는 방법을 학습합니다.

 

1. Federation이란?

1-1. 왜 Federation이 필요한가?

조직이 커지면 다음과 같은 문제가 생깁니다.

문제 1: IAM User 관리 폭발 100명 직원이 있다면 100개의 IAM User가 필요합니다. 직원이 퇴사하면 즉시 삭제해야 하고, 비밀번호 정책도 따로 관리해야 합니다. 이미 Active Directory나 Google Workspace 같은 Identity Provider(IdP)가 있는 기업은 이 작업이 이중 관리입니다.

문제 2: CI/CD 파이프라인의 Access Key 관리 GitHub Actions, GitLab CI, Jenkins 등에서 AWS를 배포할 때 Access Key를 저장해두게 됩니다. 이 키가 유출되면 재앙입니다. 키 로테이션도 번거롭고, 여러 파이프라인에 퍼져 있으면 어디에 저장했는지도 파악하기 어렵습니다.

해결책: Federation

외부 자격 증명 시스템(GitHub, Google, Active Directory 등)과 AWS 사이에 신뢰 관계를 맺어, 외부에서 인증된 사용자/시스템이 임시 자격 증명으로 AWS에 접근하게 합니다.

1-2. AWS가 지원하는 Federation 방식

방식 사용 프로토콜 주요 사용 사례
OIDC Federation OpenID Connect (JWT 기반) GitHub Actions, Kubernetes, 모바일 앱
SAML 2.0 Federation SAML (XML 기반) 기업 AD, Okta, Azure AD, Google Workspace
Web Identity OIDC의 하위 개념 Amazon/Facebook/Google 소셜 로그인

AWS는 이 두 프로토콜을 모두 지원하며, 공통적으로 STS AssumeRole을 통해 임시 자격 증명을 발급합니다.

 

2. OIDC Federation

2-1. OpenID Connect란?

OpenID Connect(OIDC)는 OAuth 2.0 위에 만들어진 인증 레이어입니다.

OIDC의 핵심은 JWT입니다. IdP가 발급하는 JWT에는 누가 인증받았는지, 언제, 어느 앱을 위해 발급됐는지 등의 정보가 암호화되어 담겨 있습니다.

JWT의 구조:

Header.Payload.Signature

Header: 알고리즘 정보 ({"alg": "RS256"})
Payload: 클레임 정보 ({
  "sub": "repo:my-org/my-repo:ref:refs/heads/main",
  "aud": "sts.amazonaws.com",
  "iss": "https://token.actions.githubusercontent.com",
  "exp": 1711234567
})
Signature: Header + Payload를 IdP의 개인 키로 서명

AWS STS는 이 JWT를 IdP의 공개 키로 검증한 뒤, 신뢰 정책 조건을 확인하고 임시 자격 증명을 발급합니다.

2-2. OIDC Federation 동작 원리

핵심 흐름은 이렇습니다:

1. 외부 시스템이 IdP에 인증 요청
2. IdP가 JWT 토큰 발급
3. JWT를 AWS STS에 제출 (AssumeRoleWithWebIdentity)
4. STS가 JWT 서명 검증 + 신뢰 정책 확인
5. STS가 임시 자격 증명 반환
6. 임시 자격 증명으로 AWS 리소스 접근

 

2-3. IAM OIDC Identity Provider 등록

OIDC Federation을 사용하기 전에, AWS 계정에 IdP를 등록해야 합니다. 이것이 "이 OIDC 발급자를 신뢰하겠다"는 선언입니다.

# GitHub Actions OIDC Provider 등록 (CLI)
aws iam create-open-id-connect-provider \
  --url "https://token.actions.githubusercontent.com" \
  --client-id-list "sts.amazonaws.com" \
  --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"


참고: Google, Facebook, Amazon Cognito는 AWS에 이미 내장된 OIDC Provider이므로 별도 등록이 필요 없습니다. 그 외의 Provider(GitHub, Kubernetes 등)는 위처럼 직접 등록해야 합니다.

 

3. GitHub Actions + OIDC - 실무 핵심 사례

3-1. 왜 OIDC가 Access Key보다 좋은가?

기존 방식 (Access Key 사용):

# .github/workflows/deploy.yml (나쁜 예)
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    aws-region: ap-northeast-2

문제점:

  • Access Key가 GitHub Secrets에 영구 저장됨
  • 키 유출 시 즉시 AWS 전체 위험
  • 키 로테이션이 번거로움 (여러 레포지토리에 분산됐다면 더더욱)
  • 직원 퇴사 시 어느 곳에 키가 쓰이는지 파악 어려움

OIDC 방식:

# .github/workflows/deploy.yml (올바른 예)
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
    aws-region: ap-northeast-2

장점:

  • Access Key 자체가 없음 — 저장할 키가 없으니 유출될 키도 없음
  • 각 Job 실행마다 새 임시 토큰 발급, Job 종료 시 자동 만료
  • 특정 레포지토리/브랜치/환경에만 허용하도록 세밀하게 제어 가능
  • 키 로테이션 불필요

3-2. GitHub Actions OIDC 설정 방법

Step 1: IAM에 GitHub OIDC Provider 등록

콘솔:

IAM → Identity providers → Add provider
→ Provider type: OpenID Connect
→ Provider URL: https://token.actions.githubusercontent.com
→ Audience: sts.amazonaws.com
→ Add provider

CLI:

aws iam create-open-id-connect-provider \
  --url "https://token.actions.githubusercontent.com" \
  --client-id-list "sts.amazonaws.com" \
  --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"

 

Step 2: IAM Role 생성 (신뢰 정책 설정)

특정 레포지토리 + 특정 브랜치만 허용하는 신뢰 정책:

{
  "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:my-org/my-repo:ref:refs/heads/main"
        }
      }
    }
  ]
}

Condition 설명:

  • aud: 이 토큰이 sts.amazonaws.com을 위해 발급됐는지 확인 (필수)
  • sub: 어느 레포지토리/브랜치/환경에서 발급된 토큰인지 제한

보안 경고: sub 조건을 반드시 설정하세요. 없으면 GitHub의 모든 레포지토리에서 이 Role을 수임할 수 있어 심각한 보안 위험이 됩니다.

 

sub 클레임 패턴 예시:

목적 sub 패턴
main 브랜치만 repo:org/repo:ref:refs/heads/main
모든 브랜치 repo:org/repo:*
특정 환경(Environment) repo:org/repo:environment:production
PR만 repo:org/repo:pull_request
특정 태그 repo:org/repo:ref:refs/tags/v*

 

Step 3: Role에 배포에 필요한 권한 추가

aws iam attach-role-policy \
  --role-name GitHubActionsDeployRole \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

최소 권한 원칙에 따라 실제로 필요한 서비스와 액션만 부여하세요.

 

Step 4: GitHub Actions Workflow 설정

# .github/workflows/deploy.yml
name: Deploy to AWS

on:
  push:
    branches: [main]

permissions:
  id-token: write   # OIDC 토큰 요청 권한 필수
  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/GitHubActionsDeployRole
          aws-region: ap-northeast-2

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

      - name: Deploy to S3
        run: |
          aws s3 sync ./dist s3://my-app-bucket --delete

      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id EDFDVBD6EXAMPLE \
            --paths "/*"

 

3-3. 환경(Environment)별 Role 분리 전략

프로덕션과 스테이징을 분리하려면, GitHub Environments와 OIDC를 조합합니다.

# 스테이징 배포 job
deploy-staging:
  environment: staging
  steps:
    - uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::111111111:role/GitHubActions-Staging
        # sub: "repo:org/repo:environment:staging"

# 프로덕션 배포 job (승인 필요)
deploy-production:
  environment: production   # GitHub에서 승인자 지정 가능
  steps:
    - uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: arn:aws:iam::999999999:role/GitHubActions-Production
        # sub: "repo:org/repo:environment:production"

신뢰 정책에서 각 환경마다 다른 sub 조건:

"StringEquals": {
  "token.actions.githubusercontent.com:sub":
    "repo:my-org/my-repo:environment:production"
}

 

4. SAML 2.0 Federation

4-1. SAML이란?

SAML(Security Assertion Markup Language)은 기업 환경에서 오랫동안 사용해온 XML 기반 SSO 표준입니다. 주로 기업 IdP(Active Directory, Okta, Azure AD 등)와 연동할 때 사용합니다.

OIDC가 JWT를 사용한다면, SAML은 XML Assertion을 사용합니다. 내용은 비슷하지만 포맷이 다릅니다.

주요 SAML IdP:

  • Microsoft Active Directory Federation Services (ADFS)
  • Azure Active Directory (Azure AD / Entra ID)
  • Okta
  • Google Workspace
  • Shibboleth

4-2. SAML Federation 동작 원리

SAML Federation으로 AWS 콘솔에 로그인하는 흐름:

1. 직원이 회사 포털/IdP 접속
2. IdP가 Active Directory 등으로 사용자 인증
3. IdP가 SAML Assertion(XML) 생성
   - 누가 인증받았는지
   - 어떤 AWS Role을 허용하는지
4. SAML Assertion을 AWS Sign-In 엔드포인트로 전달
5. AWS가 Assertion 검증 + STS AssumeRoleWithSAML 호출
6. 임시 자격 증명으로 AWS 콘솔 세션 생성
7. 직원이 바로 AWS 콘솔에 로그인 완료

 

직원 입장에서는 회사 계정 하나로 AWS 콘솔에 바로 들어갑니다. IAM User 비밀번호를 따로 기억할 필요가 없습니다.

4-3. SAML Federation 핵심 구성 요소

① IAM SAML Identity Provider 등록

# IdP 메타데이터 XML 파일로 등록
aws iam create-saml-provider \
  --name "CompanyActiveDirectory" \
  --saml-metadata-document file://idp-metadata.xml

② IAM Role의 신뢰 정책

SAML Federation용 신뢰 정책은 OIDC와 구조가 유사하지만, Action이 sts:AssumeRoleWithSAML이고 Principal이 SAML Provider ARN을 가리킵니다:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:saml-provider/CompanyActiveDirectory"
      },
      "Action": "sts:AssumeRoleWithSAML",
      "Condition": {
        "StringEquals": {
          "SAML:aud": "https://signin.aws.amazon.com/saml"
        }
      }
    }
  ]
}

③ SAML Assertion의 역할 매핑

IdP는 SAML Assertion 안에 사용자가 어떤 AWS Role을 사용해야 하는지를 포함시켜 전달합니다. 여러 Role이 있다면 사용자가 로그인 시 Role을 선택할 수 있습니다.


  
    arn:aws:iam::123456789012:role/SAML-Admin,
    arn:aws:iam::123456789012:saml-provider/CompanyAD
  

④ 역할 그룹 매핑 전략

실무에서는 AD 그룹을 AWS Role에 매핑합니다:

Active Directory 그룹 AWS IAM Role 권한 수준

AWS-Admins SAML-Admin AdministratorAccess
AWS-Developers SAML-Developer PowerUserAccess
AWS-ReadOnly SAML-ReadOnly ReadOnlyAccess
AWS-Finance SAML-Finance Billing 접근만

 

5. OIDC vs SAML 비교

비교 항목 OIDC SAML 2.0

비교 항목  OIDC SAML 2.0
토큰 형식 JWT (JSON) XML Assertion
주요 사용처 CI/CD, 모바일, 웹앱 기업 SSO, AD 연동
설정 복잡도 상대적으로 간단 다소 복잡 (XML 기반)
STS API AssumeRoleWithWebIdentity AssumeRoleWithSAML
세션 유효 기간 기본 1시간 최대 12시간
대표 IdP GitHub, Google, Cognito Okta, ADFS, Azure AD

 

언제 뭘 쓰나:

  • 기업 직원이 AWS 콘솔/CLI에 접근 → SAML (또는 IAM Identity Center)
  • GitHub Actions / GitLab CI 등 CI/CD → OIDC
  • Kubernetes 파드가 AWS 접근 → OIDC (EKS IRSA)
  • 모바일/웹 앱 사용자가 AWS 접근 → OIDC + Cognito

 

6. 실습: GitHub Actions OIDC 설정

이 실습은 Access Key 없이 GitHub Actions에서 AWS S3에 파일을 업로드하는 것을 구현합니다.

실습 준비

  • GitHub 계정과 레포지토리
  • AWS 계정 (IAM 관리 권한)

Step 1: AWS에 GitHub OIDC Provider 등록

콘솔:

IAM → Identity providers → Add provider
Provider type: OpenID Connect
Provider URL: https://token.actions.githubusercontent.com
→ [Get thumbprint] 클릭
Audience: sts.amazonaws.com
→ Add provider

CLI:

aws iam create-open-id-connect-provider \
  --url "https://token.actions.githubusercontent.com" \
  --client-id-list "sts.amazonaws.com" \
  --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1"

Step 2: IAM Role 생성

# 신뢰 정책 파일 생성
cat > github-trust-policy.json << 'EOF'
{
  "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:YOUR_ORG/YOUR_REPO:*"
        }
      }
    }
  ]
}
EOF

# ACCOUNT_ID와 레포지토리 정보 교체
sed -i 's/ACCOUNT_ID/실제계정ID/g' github-trust-policy.json
sed -i 's/YOUR_ORG\/YOUR_REPO/실제조직\/실제레포/g' github-trust-policy.json

# Role 생성
aws iam create-role \
  --role-name GitHubActionsDeployRole \
  --assume-role-policy-document file://github-trust-policy.json

# S3 권한 부여 (테스트용)
aws iam attach-role-policy \
  --role-name GitHubActionsDeployRole \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Step 3: GitHub Workflow 파일 작성

레포지토리에 .github/workflows/aws-oidc-test.yml 파일 생성:

name: AWS OIDC Test

on:
  push:
    branches: [main]
  workflow_dispatch:   # 수동 실행도 허용

permissions:
  id-token: write   # OIDC 토큰 발급에 필수
  contents: read

jobs:
  test-aws-access:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::ACCOUNT_ID:role/GitHubActionsDeployRole
          aws-region: ap-northeast-2

      - name: Verify AWS Identity
        run: |
          echo "=== 현재 자격 증명 확인 ==="
          aws sts get-caller-identity

      - name: List S3 Buckets
        run: |
          echo "=== S3 버킷 목록 ==="
          aws s3 ls

      - name: Try EC2 (should fail - no permission)
        run: |
          echo "=== EC2 접근 시도 (실패 예상) ==="
          aws ec2 describe-instances || echo "EC2 접근 거부됨 (예상된 결과)"

Step 4: 실행 및 결과 확인

GitHub에서 Actions 탭 → 워크플로우 실행

 

결과:

=== 현재 자격 증명 확인 ===
{
    "UserId": "AROA...:GitHubActionsDeployRole",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/GitHubActionsDeployRole/..."
}
=== S3 버킷 목록 ===
2025-01-15 10:30:00 my-app-bucket
...
=== EC2 접근 시도 (실패 예상) ===
EC2 접근 거부됨 (예상된 결과)

get-caller-identity 결과에서 Role 이름이 보이면 OIDC 인증 성공입니다. Access Key를 한 번도 사용하지 않았습니다.

 

Step 5: sub 클레임 제한 확인

보안 확인을 위해, 다른 브랜치에서의 접근이 차단되는지 테스트합니다.

신뢰 정책의 sub를 main 브랜치만으로 수정:

"StringEquals": {
  "token.actions.githubusercontent.com:sub":
    "repo:YOUR_ORG/YOUR_REPO:ref:refs/heads/main"
}

다른 브랜치에서 동일 workflow를 실행하면:

Error: Not authorized to perform sts:AssumeRoleWithWebIdentity

이처럼 특정 브랜치/환경만 허용할 수 있습니다.

 

7. EKS IRSA — Kubernetes에서의 OIDC

AWS EKS(Elastic Kubernetes Service)에서도 동일한 OIDC 원리를 활용합니다. 이것을 IRSA(IAM Roles for Service Accounts)라고 부릅니다.

쿠버네티스 파드가 S3나 DynamoDB에 접근할 때, Access Key를 환경변수에 넣는 대신 Service Account에 IAM Role을 연결합니다.

# Kubernetes Service Account에 IAM Role 연결
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app-sa
  namespace: default
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/MyPodRole

IAM Role의 신뢰 정책:

{
  "Effect": "Allow",
  "Principal": {
    "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/CLUSTER_ID"
  },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "oidc.eks.ap-northeast-2.amazonaws.com/id/CLUSTER_ID:sub":
        "system:serviceaccount:default:my-app-sa"
    }
  }
}

이렇게 설정하면 파드 내 애플리케이션은 SDK가 자동으로 OIDC 토큰을 교환해 IAM Role 자격 증명을 받아옵니다. EC2 Instance Profile과 동일한 개발자 경험을 Kubernetes에서도 구현합니다.

 

 

9. Federation 설계 모범 사례

원칙 1: Condition은 항상 최대한 좁게

// 나쁜 예: 너무 넓음
"StringLike": {"token.actions.githubusercontent.com:sub": "*"}

// 좋은 예: 특정 레포지토리, 특정 환경만
"StringEquals": {
  "token.actions.githubusercontent.com:sub":
    "repo:my-org/my-repo:environment:production"
}

원칙 2: 환경별 Role 분리

GitHubActions-Dev-Role    → 개발 계정
GitHubActions-Staging-Role → 스테이징 계정
GitHubActions-Prod-Role   → 프로덕션 계정 (승인 필요)

원칙 3: 최소 권한

배포 Role에는 실제 배포에 필요한 서비스(S3, ECR, ECS 등)만
읽기 전용 Role과 배포 Role을 분리

원칙 4: CloudTrail로 Federation 로그인 모니터링

# SAML Federation 로그인 이벤트 확인
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithSAML

# OIDC 이벤트 확인
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity

 

10. 마치며

 

Federation의 핵심:

  • AWS 외부의 자격 증명 시스템을 AWS에서 신뢰하는 것
  • 외부 인증 후 STS가 임시 자격 증명을 발급
  • IAM User를 만들지 않아도 됨

OIDC:

  • JWT 기반, GitHub Actions/K8s/모바일 앱에 적합
  • AssumeRoleWithWebIdentity 사용
  • 신뢰 정책 Condition에 반드시 aud + sub 모두 설정

SAML:

  • XML 기반, 기업 AD/Okta/Azure AD 연동에 적합
  • AssumeRoleWithSAML 사용
  • AD 그룹 → IAM Role 매핑으로 대규모 조직 관리

가장 중요한 실천 사항: GitHub Actions에서 AWS_ACCESS_KEY_ID를 Secrets에 저장하는 방식을 즉시 OIDC로 교체하세요. 설정은 30분이면 충분하고, 보안은 크게 향상됩니다.

 

 

참고 자료

'AWS' 카테고리의 다른 글

IAM Identity Center  (0) 2026.05.02
Directory Service  (0) 2026.05.02
Bybit / Safe{Wallet} 사고 사례 분석  (1) 2026.04.29
OLX Europe의 봇 방어 아키텍처 분석  (0) 2026.04.23
Twilio TaskRouter JS SDK 사고 사례 분석  (1) 2026.04.17