Belajar DevSecOps Engineer - Identity & Access for Pipelines
Episode 19 of 28

Belajar DevSecOps Engineer - Identity & Access for Pipelines

Password statis adalah beban yang selalu bocor; di episode ini kalian membangun identitas tanpa secret untuk pipeline dan workload — OIDC federation dari GitHub Actions ke cloud, workload identity Kubernetes via service account annotation, SPIFFE/SPIRE untuk identitas in-cluster, serta least privilege sampai permission boundary

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Episode 9 sudah menyentuh OIDC sebagai cara deploy; episode ini membahasnya secara utuh karena identitas adalah fondasi yang mengikat semua episode sebelumnya. Pikirkan sejenak: network policy (ep 18) mengontrol berdasarkan label, Kyverno (ep 13) memverifikasi signature berdasarkan issuer — semuanya pada akhirnya menjawab satu pertanyaan: "siapa kamu, dan bagaimana aku memastikannya?"

Masalah klasiknya adalah jawaban lama: password, API key, access token statis. Semua bentuk secret punya masalah sama — bisa dicuri, harus dirotasi, dan tidak membuktikan proses pemanggilnya, hanya pemegang kredensialnya. Episode ini membangun identitas modern: terverifikasi kriptografis, pendek umur, terikat pada konteks (repo/workload), tanpa secret untuk dijaga.

Tiga Lapis Identitas

Peta lengkapnya sebelum masuk detail:

LapisanMekanismeContoh
Pipeline → CloudOIDC federationGitHub Actions assume AWS role
Workload → CloudIRSA / Workload IdentityPod K8s akses S3
Workload → WorkloadSPIFFE/SPIRE atau meshapi ↔ database client

Prinsip yang identik di ketiganya: bukti kriptografis pendek-umur ditukar dengan token scoped — bukan credential panjang yang disimpan.

OIDC Federation Pipeline → Cloud (Pendalaman)

Konfigurasi inti sudah dibahas di episode 9. Yang sering terlewat adalah disiplin claim binding:

Trust policy: binding berlapis
{
  "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",
        "token.actions.githubusercontent.com:sub": [
          "repo:org/myapp:environment:production",
          "repo:org/myapp:ref:refs/heads/main"
        ]
      },
      "StringLike": {
        "token.actions.githubusercontent.com:job_workflow_ref":
          "org/myapp/.github/workflows/deploy.yml@*"
      }
    }
  }]
}

Semakin spesifik binding, semakin sempit jalur penyalahgunaan:

  1. Repo + environment — workflow dari repo lain tidak bisa.
  2. Branch/environment protection — butuh approval manusia sebelum token diterbitkan.
  3. job_workflow_ref — hanya workflow file tertentu; PR jahat yang menambahkan workflow baru tidak otomatis dapat akses.

Audit berkala penting di sini — daftar semua role federated dan cek apakah masih relevan:

Audit trust policy yang ada
aws iam list-roles --query 'Roles[?AssumeRolePolicyDocument.Statement[?Action==`sts:AssumeRoleWithWebIdentity`]].RoleName'

Workload → Cloud: IRSA / Workload Identity

Pod Kubernetes yang perlu akses S3 tidak perlu static key juga. Di EKS pola ini disebut IRSA (IAM Roles for Service Accounts): service account K8s dipetakan ke IAM role via annotation:

Kubernetessa-app.yaml — service account dengan IAM role
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: prod
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/app-s3-reader
automountServiceAccountToken: true   # token K8s dibutuhkan untuk exchange

Alur internalnya: pod menukar token service account (JWT bertanda cluster OIDC provider) dengan STS untuk mendapat kredensial AWS sementara. IAM role memvalidasi bahwa JWT berasal dari kombinasi cluster+namespace+SA tertentu — pod dari namespace lain atau SA lain ditolak.

GCP menyebut padanannya Workload Identity Federation for GKE; Azure punya konsep mirip via Microsoft Entra Workload ID. Konsepnya identik, sintaksnya beda.

SPIFFE/SPIRE: Identitas In-Cluster Universal

Untuk percakapan antar-workload (dan lintas runtime), standar terbukanya adalah SPIFFE — identitas berformat URI (spiffe://trust-domain/ns/prod/sa/app) yang dibuktikan lewat sertifikat SVID pendek-masa-hidup. SPIRE adalah implementasinya:

Alur SPIRE singkat
Workload start -> attestasi (node/pod identity) -> SPIRE server terbitkan SVID
             -> sertifikat X.509 pendek umur -> dipakai mTLS antar-service

Manfaat praktis: aplikasi tidak lagi memakai shared API key untuk saling autentikasi — mTLS dengan SVID memberi identitas per-workload yang bisa diaudit, dan rotasi terjadi otomatis tiap beberapa jam. Istio/Linkerd bisa memakai SPIRE sebagai backend identitasnya.

Tip

Jangan adopsi SPIRE hanya karena hype. Aturannya: kalau stack kalian satu mesh, identitas mesh cukup. SPIRE bernilai saat kalian butuh identitas konsisten lintas runtime — VM, cluster berbeda, serverless, bahkan bare metal.

Least Privilege yang Sungguhan

Identitas modern tanpa least privilege hanya mengganti nama masalah. Tiga teknik wajib:

1. Permission Boundary

Batasi apa pun yang bisa dilakukan role, meski policy-nya keliru over-permissive:

Permission boundary: tolak semua kecuali read S3
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "NotAction": ["s3:GetObject", "s3:ListBucket"],
    "Resource": "*"
  }]
}

2. Satu Role per Fungsi

Anti-pattern: deploy-role dengan akses ECR+EKS+S3+SQS dipakai semua job. Pisahkan: build-push-role, deploy-role, migration-role. Blast radius insiden satu token menjadi satu fungsi.

3. Umur Token Minimal

Selalu set role-duration-seconds: 900 (15 menit) untuk CI. Kalau job deploy rata-rata 5 menit, tidak ada alasan sesi hidup 1 jam.

Pitfall Umum

  • Wildcard di trust policy (sub: repo:org/*) — membuka federation untuk semua repo termasuk yang baru dibuat developer mana pun.
  • Lupa revoke federation saat repo dihapus — jalankan audit berkala; repo mati dengan role aktif adalah pintu terlupakan.
  • Token di-cache melewati TTL — SDK umumnya handle refresh otomatis; hindari cache manual kredensial di script.
  • Break-glass tanpa jejak — akses darurat statis boleh ada, tapi harus alarm-triggered dan review otomatis.

Penutup

Inti yang harus dibawa pulang:

  • Secret statis = liability; identitas modern = bukti kriptografis pendek-umur terikat konteks.
  • OIDC pipeline→cloud wajib binding spesifik: repo + branch/environment + workflow file.
  • Pod→cloud via IRSA/Workload Identity; pod↔pod via mesh atau SPIRE untuk multi-runtime.
  • Least privilege riil = permission boundary + role per fungsi + TTL minimal + audit berkala.

Di episode 20 selanjutnya kita membahas Audit & Incident Automation — mengaktifkan audit log Kubernetes dengan policy selektif, membangun incident response automation dari alert hingga containment otomatis, dan runbook as code yang dieksekusi mesin bukan sekadar dokumen wiki. Sampai jumpa!

Belajar DevSecOps Engineer - Identity & Access for Pipelines | Belajar DevSecOps Engineer