GitHub Actions OIDC: Autentikasi Cloud Tanpa Kunci untuk CI/CD

Foto oleh Yu. Samoilov on flickr
GitHub Actions OIDC memungkinkan workflow meminta token identitas bertanda tangan yang berumur pendek dari GitHub saat runtime dan menukarnya dengan kredensial sementara dari AWS atau Google Cloud, alih-alih mengandalkan access key jangka panjang yang tersimpan sebagai repository secret. Ini menghilangkan kebutuhan untuk menyimpan, merotasi, atau mengkhawatirkan kebocoran kredensial cloud statis, dan setiap kredensial yang diterbitkan otomatis kedaluwarsa dalam satu jam atau kurang.
Anda mendaftarkan issuer OIDC milik GitHub sebagai identity provider di AWS IAM, lalu membuat IAM role dengan trust policy yang memeriksa claim audience terhadap sts.amazonaws.com dan subject claim terhadap repository, branch, atau environment spesifik Anda. Action aws-actions/configure-aws-credentials kemudian meminta token OIDC tersebut dan menukarnya dengan kredensial sementara yang dibatasi pada role tersebut.
Ini terjadi ketika attribute condition pada Workload Identity Provider Anda tidak ada atau terlalu luas. Issuer OIDC milik GitHub dibagikan ke seluruh organisasi di platform tersebut, sehingga Google Cloud mengharuskan Anda menambahkan attribute condition eksplisit, biasanya memeriksa apakah atribut pemilik repository cocok dengan nama organisasi Anda, jika tidak, repository GitHub mana pun secara teoretis bisa mencoba federasi ke pool Anda.
Secara default, tidak. GitHub secara sengaja membatasi izin token, termasuk kemampuan meminta token OIDC, untuk run workflow yang dipicu oleh pull request dari repository fork, karena kode workflow itu sendiri tidak dipercaya dalam konteks tersebut. Ini disengaja dan sebaiknya tidak diakali tanpa alasan yang sangat dipertimbangkan.
Kesalahan paling umum adalah membatasi subject claim terlalu luas, misalnya mencocokkan seluruh organisasi atau semua branch dalam sebuah repository alih-alih repository, branch, tag, atau environment terlindungi tertentu. Kesalahan lain yang sering terjadi adalah melupakan kondisi audience sepenuhnya, yang melemahkan verifikasi bahwa token tersebut benar-benar diterbitkan untuk penyedia cloud spesifik Anda.

Foto oleh Yu. Samoilov on flickr
Setiap kredensial cloud jangka panjang yang disimpan sebagai repository secret adalah bom waktu. Kredensial itu tidak kedaluwarsa sendiri, memberikan izin yang sama persis baik saat workflow benar-benar membutuhkannya maupun saat dependency yang disusupi sedang mencuri datanya, dan begitu bocor, seseorang harus menyadarinya, merotasinya, lalu berharap tidak ada kejadian buruk di antaranya. OpenID Connect, atau OIDC, menghilangkan seluruh kategori risiko ini dengan membiarkan workflow GitHub Actions meminta kredensial berumur pendek dan terbatas langsung dari AWS atau Google Cloud saat runtime, tanpa ada secret yang tersimpan sama sekali.
Tulisan ini membahas cara kerja federasi ini secara mendalam, cara menghubungkan AWS IAM dan GCP Workload Identity Federation dari awal, cara membaca dan membatasi subject claim yang disematkan GitHub pada setiap token, serta kesalahan konfigurasi spesifik yang diam-diam mengubah setup tanpa kunci menjadi lebih berbahaya daripada kunci statis yang digantikannya.
Kebanyakan tim yang belum mengadopsi OIDC menyimpan pasangan access key AWS atau file JSON service account GCP sebagai secret terenkripsi di GitHub, lalu mereferensikannya di setiap workflow yang perlu mengakses cloud. Cara ini memang berfungsi, tetapi menumpuk risiko dengan cara yang mudah diremehkan sampai sebuah insiden memaksa masalah ini terungkap.
Saat workflow memintanya, penyedia OIDC milik GitHub akan menerbitkan JSON Web Token yang ditandatangani dan menjelaskan secara persis siapa yang meminta: repository mana, branch atau tag mana, environment mana, event apa yang memicu run tersebut, dan jendela validitas singkat yang diukur dalam menit. Token ini bukan secret jangka panjang. Token ini dibuat baru untuk job spesifik tersebut dan kedaluwarsa hampir seketika setelahnya.
Penyedia cloud tidak pernah harus mempercayai GitHub secara membabi buta. Sebaliknya, Anda mengonfigurasi AWS atau GCP terlebih dahulu untuk mempercayai penerbit OIDC GitHub sebagai identity provider, lalu menulis trust policy atau attribute condition yang hanya menerima token dengan claim tertentu, terutama subject claim. Saat workflow berjalan, SDK atau action cloud akan menyerahkan token tersebut, penyedia memverifikasi tanda tangannya terhadap kunci publik yang dipublikasikan GitHub, memeriksa claim terhadap trust policy Anda, dan jika semuanya sesuai, mengembalikan kredensial sementara dan terbatas yang kedaluwarsa dalam satu jam atau kurang.
Perlakukan subject claim seperti aturan firewall. Batasi hanya pada repository, branch, atau environment deployment tertentu yang seharusnya diizinkan mengasumsikan sebuah role, jangan mempercayai seluruh organisasi atau semua branch dalam sebuah repository.
Menyiapkan AWS dimulai dengan mendaftarkan penerbit OIDC GitHub sebagai identity provider di IAM, menggunakan issuer URL dan thumbprint atau provider GitHub bawaan yang kini otomatis dikenali AWS. Setelah provider tersebut ada, Anda membuat IAM role yang mempercayainya, dan trust policy itulah tempat batas keamanan sesungguhnya berada.
Contoh di bawah membatasi role hanya untuk satu repository dan satu environment deployment bernama production, artinya build pull request dari fork, atau bahkan push ke feature branch di repository yang sama, tidak bisa mengasumsikan role ini. Kondisi audience juga memastikan token benar-benar diterbitkan untuk AWS dan bukan hasil replay dari token yang dibuat untuk provider lain.
{
"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:environment:production"
}
}
}
]
}Lampirkan trust policy ini ke sebuah IAM role, lalu referensikan ARN role tersebut sebagai role-to-assume pada langkah aws-actions/configure-aws-credentials di workflow Anda, bersama izin id-token write di level job atau workflow. Tidak ada access key, secret key, atau kredensial jangka panjang apa pun yang pernah menyentuh repository secrets Anda.
Google Cloud menggunakan Workload Identity Federation, yang secara konsep serupa tetapi terbagi menjadi tiga bagian: Workload Identity Pool yang berfungsi sebagai wadah untuk identitas eksternal, Workload Identity Provider di dalam pool tersebut yang dikonfigurasi dengan issuer GitHub dan attribute mapping, serta service account yang diizinkan untuk diimpersonasi oleh identitas terfederasi tersebut.
Langkah attribute mapping adalah tempat sebagian besar pekerjaan keamanan berlangsung. Penerbit OIDC GitHub dibagikan ke seluruh organisasi GitHub yang ada, sehingga Google Cloud mewajibkan attribute condition yang menyaring token masuk agar hanya berasal dari organisasi atau repository Anda, jika tidak, repository GitHub mana pun secara teoretis bisa mencoba melakukan federasi ke pool Anda. Kondisi umum memeriksa apakah atribut pemilik repository cocok tepat dengan nama organisasi Anda.
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/gh-pool/providers/gh-provider
service_account: [email protected]
- uses: google-github-actions/setup-gcloud@v2
- run: gcloud run deploy my-service --region us-central1Berikan service account role roles/iam.workloadIdentityUser yang dibatasi pada provider spesifik tersebut, lalu referensikan jalur resource provider lengkap dan alamat email service account pada langkah google-github-actions/auth seperti ditunjukkan di atas. Sama seperti AWS, ini menghilangkan kebutuhan untuk pernah membuat, menyimpan, atau merotasi file kunci service account.
GitHub memformat subject claim secara berbeda tergantung apa yang memicu workflow tersebut, dan salah memformat ini adalah alasan paling umum sebuah trust policy diam-diam gagal cocok. Tabel di bawah mencakup format yang paling sering Anda pakai saat membatasi role atau provider pada jenis pemicu tertentu.
| Lingkup pemicu | Format subject claim |
|---|---|
| Push ke branch tertentu | repo:org/repo:ref:refs/heads/nama-branch |
| Push tag versi | repo:org/repo:ref:refs/tags/nama-tag |
| Deployment ke environment bernama | repo:org/repo:environment:nama-environment |
| Event pull request | repo:org/repo:pull_request |
Federasi OIDC menghilangkan risiko kunci statis yang bocor, tetapi trust policy yang ceroboh bisa diam-diam menciptakan kembali dampak kerusakan yang sama, atau bahkan lebih buruk, dalam bentuk yang berbeda. Berikut kesalahan yang paling sering muncul dalam audit nyata.
Jangan pernah membatasi trust policy hanya menggunakan nama repository tanpa juga membatasi ref, environment, atau actor. Issuer milik GitHub dibagikan ke jutaan repository, dan subject claim yang hanya memeriksa nama repository tanpa prefix organisasi atau suffix ref bisa cocok dengan jauh lebih banyak workflow daripada yang dimaksudkan.
Memindahkan pipeline yang sudah ada dari kunci statis ke OIDC adalah proses mekanis begitu identity provider dan trust policy sudah siap. Ikuti urutan ini untuk menghindari deployment yang gagal di tengah proses migrasi.
Autentikasi tanpa kunci bukan hanya peningkatan keamanan, tetapi juga mengurangi beban operasional dalam jangka panjang: tidak ada lagi pengingat rotasi kunci setiap kuartal, tidak ada lagi kebingungan tentang pipeline mana yang memiliki access key tertentu, dan trust policy yang mendokumentasikan secara jelas workflow mana saja yang diizinkan menyentuh resource cloud tertentu.