Cách cũ: IAM user → access key → GitHub Secrets. Vấn đề: key không expire. Nếu lộ (Uber 2016 — $148M settlement), attacker có full access vô hạn. Cách mới: OIDC federation — GitHub Actions nhận STS token từ AWS, không lưu access key, token expire 1h.


  flowchart LR
    GHA["GitHub Actions"] -->|"1. OIDC JWT"| OIDC["token.actions.githubusercontent.com"]
    OIDC -->|"2. JWT"| GHA
    GHA -->|"3. AssumeRoleWithWebIdentity"| STS["AWS STS"]
    STS -->|"4. Temp credential (1h)"| GHA

Setup

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

Trust policy — scope càng hẹp càng an toàn:

{
  "Effect": "Allow",
  "Principal": {
    "Federated": "arn:aws:iam::...: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:myorg/myapp:ref:refs/heads/main"
    }
  }
}
# .github/workflows/deploy.yml
permissions:
  id-token: write
  contents: read
steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
      aws-region: ap-southeast-1
  - run: npm ci && npm run build && npx cdk deploy --require-approval never

Multi-environment + Protection

jobs:
  deploy:
    strategy:
      matrix:
        environment: [staging, production]
    environment:
      name: ${{ matrix.environment }}
      # Production: required reviewers (2), wait timer (5 min)

OIDC > IAM user access key: token expire 1h, không lưu credential. Trust policy scope hẹp: repo + branch + environment. Deploy role least privilege: chỉ quyền cần, không AdministratorAccess. Environment protection: required reviewers cho production.

Bài sau: Phần 25: SQS — Standard, FIFO, DLQ, visibility timeout