DevOps

CI/CD kulcsok nélkül: GitHub Actions OIDC-vel az AWS-be, Terraformmal beállítva

A hosszú életű AWS access key a CI-ben időzített bomba. Megmutatom, hogyan cseréld le rövid életű, OIDC-alapú tokenekre: OIDC provider, IAM-role bizalmi feltétellel és egy biztonságos deploy-workflow — végig Terraformmal.

Röviden: A hosszú életű AWS access key a CI-ben időzített bomba. Megmutatom, hogyan cseréld le rövid életű, OIDC-alapú tokenekre: OIDC provider, IAM-role bizalmi feltétellel és egy biztonságos deploy-workflow — végig Terraformmal.

Ha a CI/CD pipeline-od egy AWS_ACCESS_KEY_ID és AWS_SECRET_ACCESS_KEY párra épül a repo titkaiban, egy időzített bombán ülsz. Ezek hosszú életű kulcsok: ha kiszivárognak (log, fork, elgépelt secret), a támadó a lejáratig hozzáfér a fiókodhoz. A modern megoldás az OIDC: a GitHub Actions futásidőben, aláírt tokennel igazolja magát az AWS-nek, cserébe rövid életű, percekig élő credentialt kap. Nincs tárolt titok, nincs mit ellopni. Ebben a cikkben végigállítjuk ezt — Terraformmal.

Hogyan működik az OIDC bizalom?

Az AWS-ben létrehozol egy OIDC identity providert, ami megbízik a GitHub token-kibocsátójában. Amikor egy workflow fut, a GitHub kiállít egy JWT-t, amiben benne van, melyik repóból és melyik branchről/környezetből indult. Az AWS ezt ellenőrzi egy IAM-role bizalmi feltétele alapján, és csak akkor ad ideiglenes credentialt, ha a feltétel illeszkedik.

Miért jobb ez a hosszú életű kulcsnál?

A különbség nem árnyalatnyi, hanem kategóriabeli: nincs mit ellopni, és ha mégis, percekig ér valamit.

SzempontHosszú életű access keyOIDC + rövid token
Tárolt titokigen (repo secret)nincs
Élettartamamíg nem forgatod~1 óra
Szivárgás hatásateljes hozzáférés lejáratigpercekig, szűk scope
Hatókör szűkítésemanuálisrepo/branch/env szinten
Forgatáskézi / ütemezettnem kell

Az OIDC provider és a role Terraformban

Először az OIDC providert hozzuk létre, ami megbízik a GitHub kibocsátójában. A thumbprintet a modern AWS már maga is kezeli, de a client_id_list-ben a sts.amazonaws.com audience kell.

hcl
data "tls_certificate" "github" {
  url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration"
}

resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.github.certificates[0].sha1_fingerprint]
}

Most jön a lényeg: a role bizalmi feltétele. Ez pontosan megköti, hogy CSAK a te repód main ágáról indított futás veheti fel a role-t.

hcl
data "aws_iam_policy_document" "trust" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    effect  = "Allow"
    principal {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github.arn]
    }
    condition {
      test     = "StringEquals"
      variable = "token.actions.githubusercontent.com:aud"
      values   = ["sts.amazonaws.com"]
    }
    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = ["repo:${var.github_org}/${var.github_repo}:ref:refs/heads/main"]
    }
  }
}

resource "aws_iam_role" "deploy" {
  name               = "${var.project}-gha-deploy"
  assume_role_policy = data.aws_iam_policy_document.trust.json
  max_session_duration = 3600
  tags               = local.tags
}

A deploy-jogosultság szűkre szabása

A role csak azt tudja, amire a pipeline-nak valóban szüksége van. Példaként egy statikus site deployhoz S3-írás és CloudFront-invalidáció kell — semmi több. Ne csábulj el a kényelmes AdministratorAccess-hez.

hcl
data "aws_iam_policy_document" "deploy_perms" {
  statement {
    sid     = "S3Sync"
    actions = ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"]
    resources = [
      var.site_bucket_arn,
      "${var.site_bucket_arn}/*",
    ]
  }
  statement {
    sid       = "CloudFrontInvalidate"
    actions   = ["cloudfront:CreateInvalidation"]
    resources = [var.distribution_arn]
  }
}

resource "aws_iam_role_policy" "deploy_perms" {
  name   = "deploy-perms"
  role   = aws_iam_role.deploy.id
  policy = data.aws_iam_policy_document.deploy_perms.json
}

A GitHub Actions workflow

A workflow oldalán a kulcs a permissions: id-token: write (e nélkül a GitHub nem állít ki OIDC tokent) és a hivatalos aws-actions/configure-aws-credentials action, ami elvégzi az AssumeRoleWithWebIdentity hívást. Sehol egy tárolt kulcs.

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

permissions:
  id-token: write   # OIDC token kiállításához kötelező
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: AWS credential OIDC-vel
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/myproj-gha-deploy
          aws-region: eu-central-1

      - name: Build
        run: npm ci && npm run build

      - name: Deploy S3-ba
        run: aws s3 sync ./dist s3://my-site-bucket --delete

      - name: CloudFront invalidáció
        run: |
          aws cloudfront create-invalidation \
            --distribution-id E123ABC456DEF \
            --paths "/*"

Gyakori buktatók

  1. **Hiányzó id-token: write** — a leggyakoribb hiba; enélkül nincs OIDC token, és rejtélyes hitelesítési hibát kapsz.
  2. **Túl tág sub feltétel** — repo:org/* vagy hiányzó ref: bárki felveheti a role-t.
  3. Régió-eltérés — a configure-aws-credentials régiója és a deploy-célok régiója nem stimmel.
  4. **AdministratorAccess a role-on** — kényelmes, de pontosan az a széles hatókör, amit az OIDC-vel el akartál kerülni.

Mit jelent ez neked?

Az OIDC-alapú deploy megszünteti a CI/CD legnagyobb, csendes kockázatát: a repóban heverő hosszú életű AWS-kulcsot. Cserébe rövid életű, szűk hatókörű, repóhoz és branchhez kötött tokent kapsz — nincs mit forgatni, nincs mit ellopni. A beállítás egyszeri munka Terraformban: OIDC provider, egy pontos bizalmi feltétel, és a valódi igényre szabott jogosultság. Ha ma egyetlen dolgot változtatsz a pipeline-odon, ez legyen az. A régi access key-eket pedig — miután az OIDC működik — töröld, ne csak hagyd ott „biztos, ami biztos” alapon.