Kredensial cloud yang disimpan permanen di CI/CD variables adalah bom waktu yang menunggu meledak. Episode ini menjelaskan cara menggantinya dengan OpenID Connect — pipeline meminta token berumur pendek langsung dari GitLab untuk mengotentikasi diri ke AWS, GCP, dan Azure tanpa menyimpan satu pun secret jangka panjang.

Di episode 12 sebelumnya kita membahas DevSecOps native — termasuk Secret Detection yang menangkap kredensial yang bocor ke repository. Tapi ada satu sumber kredensial yang tidak terlihat di repository: variabel CI/CD yang menyimpan access key cloud secara permanen. Di episode 5 kita membahas cara menyimpan variable dengan flag Masked dan Protected — namun itu hanya memperlambat pencurian, bukan mencegahnya.
Pola lama untuk autentikasi ke cloud dari pipeline selalu berakhir seperti ini: seseorang membuat user IAM khusus, membiarkan access key-nya terpasang di pengaturan CI/CD, dan key itu hidup selama berbulan-bulan. Satu key seperti itu cukup untuk diinginkan oleh penyerang — dan ketika bocor, seluruh akun cloud jadi taruhannya. Ini persis seperti memberikan satu kunci rumah yang berlaku seumur hidup kepada semua orang yang lewat: nyaman, tapi sekali hilang, semua pintu terbuka.
Episode ini memperkenalkan pendekatan yang jauh lebih aman: passwordless cloud authentication menggunakan OIDC (OpenID Connect). Pipeline tidak lagi menyimpan kredensial permanen — ia meminta token berumur pendek langsung dari GitLab untuk setiap pipeline, dan token itu hanya valid dalam hitungan menit. Mari kita bedah.
Sebelum membahas solusi, mari jujur soal masalahnya. Menyimpan AWS_ACCESS_KEY_ID dan AWS_SECRET_ACCESS_KEY sebagai variabel CI/CD permanen membawa tiga risiko utama:
Warning
Jangan pernah menyimpan long-lived cloud credentials — terutama AWS Secret Access Key — sebagai variabel CI/CD permanen. Masking hanya menyembunyikan nilai di log; ia tidak mencegah pencurian dari dalam runner atau dari akses yang sudah terlanjur bocor. OIDC menghapus kebutuhan akan kredensial permanen tersebut sepenuhnya.
OIDC adalah protokol yang sudah ada di mana-mana — kalian menggunakannya setiap kali login ke sebuah situs dengan "Sign in with Google". Dalam konteks CI/CD, alurnya seperti ini:
id_tokens di sebuah job.aud yang kalian set.aud dan project path.Kuncinya ada pada JWT: token ini berumur pendek, terikat pada konteks pipeline tertentu, dan tidak pernah disimpan di mana pun. GitLab bertindak sebagai identity provider — sama seperti Google atau Okta, tapi khusus untuk pipeline.
id_tokens di .gitlab-ci.ymlKonfigurasinya cukup dengan blok id_tokens pada level job, pipeline, atau default. Nilai yang penting adalah aud — audience yang harus cocok dengan yang dikonfigurasi di cloud provider.
deploy-to-aws:
stage: deploy
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
script:
- echo "JWT tersedia di GITLAB_OIDC_TOKEN"
- echo "${#GITLAB_OIDC_TOKEN} karakter token"Setelah didefinisikan, JWT bisa diakses sebagai variabel shell GITLAB_OIDC_TOKEN di dalam job — tersedia hanya untuk job yang mendefinisikannya. Inilah yang dikirim ke cloud provider untuk ditukar dengan kredensial sementara. Catatan: jika nama variabel diakhiri _FILE (misal GITLAB_OIDC_TOKEN_FILE), GitLab menulis token ke file dan variabel tersebut memuat path-nya — berguna untuk alat yang butuh token berbentuk file.
Tip
Nilai aud bersifat bebas, tapi pastikan konsisten antara GitLab dan cloud provider. Banyak tim memakai https://gitlab.com untuk GitLab.com atau URL instance self-hosted mereka. Beberapa provider menggunakan aud untuk membedakan pipeline mana yang boleh memakai role mana.
Di AWS, alurnya memakai IAM Role + layanan Security Token Service (STS). Kalian membuat role IAM, mengonfigurasi GitLab sebagai web identity provider di IAM, lalu pipeline menukar JWT dengan kredensial role tersebut.
Trust policy role di AWS (disarikan) memastikan hanya token dari project GitLab yang benar yang bisa memakai role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/gitlab.com"
},
"Action": "sts:TagSession",
"Condition": {
"StringEquals": {
"gitlab.com:aud": "https://gitlab.com"
}
}
}
]
}Di dalam job, pipeline menukar JWT dengan kredensial role menggunakan AWS CLI:
deploy:
image: amazon/aws-cli:latest
stage: deploy
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
script:
- aws sts assume-role-with-web-identity \
--role-arn arn:aws:iam::123456789012:role/gitlab-deployer \
--role-session-name gitlab-pipeline \
--web-identity-token "$GITLAB_OIDC_TOKEN" \
--duration-seconds 3600Kredensial sementara hasil assume-role ini bisa di-export ke environment dan dipakai perintah AWS berikutnya, lalu mati sendiri setelah 1 jam. Tidak ada access key permanen yang tersimpan di GitLab.
Google Cloud menggunakan Workload Identity Federation untuk tujuan yang sama. Konsepnya: kalian membuat workload identity pool dan provider yang mempercayai GitLab sebagai identity provider, lalu menghubungkannya dengan sebuah service account. Karena GCP membutuhkan token dalam bentuk file, job-nya memakai konvensi variabel id_tokens yang diakhiri _FILE — GitLab menulis JWT ke sebuah file, dan variabelnya memuat path file tersebut.
gcloud iam workload-identity-pools create-cred-config \
projects/123456789/locations/global/workloadIdentityPools/ci-pool/providers/gitlab-provider \
--service-account=gitlab-deployer@my-project.iam.gserviceaccount.com \
--subject-token-type=urn:ietf:params:oauth:token-type:jwt \
--credential-source-file="$GITLAB_OIDC_TOKEN_FILE" \
--output-file="$CI_PROJECT_DIR/gcp-credential.json"
gcloud auth login --cred-file="$CI_PROJECT_DIR/gcp-credential.json"Alur yang umum: gcloud ... create-cred-config menghasilkan file kredensial sementara dari JWT, lalu gcloud auth login --cred-file memakainya. Hasilnya — akses ke GCP tanpa ada service account key yang tersimpan.
Azure memakai federated identity credentials di Azure AD. Kalian membuat app registration atau user-assigned managed identity, menambahkan credential federasi yang mempercayai GitLab, lalu pipeline login dengan token JWT tersebut:
az login \
--service-principal \
--username "$AZURE_CLIENT_ID" \
--tenant "$AZURE_TENANT_ID" \
--federated-token "$GITLAB_OIDC_TOKEN"| Provider | Mekanisme | Kredensial yang disimpan |
|---|---|---|
| AWS | IAM Role + STS AssumeRoleWithWebIdentity | Tidak ada |
| GCP | Workload Identity Federation | Tidak ada |
| Azure | Federated Identity Credentials | Tidak ada |
Pola yang sama, bahasa yang berbeda: definisikan id_tokens di GitLab, lalu tukar JWT-nya dengan kredensial sementara dari provider masing-masing.
| Kesalahan | Gejala | Solusi |
|---|---|---|
| Lupa membatasi klaim di trust policy | Project lain bisa memakai role | Perketat aud, project path, dan branch di condition |
Menggunakan $CI_JOB_JWT yang deprecated | Token kedaluwarsa tak terduga | Gunakan id_tokens dengan aud eksplisit |
| Masih menyimpan access key sebagai fallback | Long-lived key tetap ada | Hapus key dan gunakan OIDC penuh |
| Token terlalu permisif | Akses lebih luas dari yang dibutuhkan | Gunakan role/scope minimal sesuai job |
| Tidak menguji rotasi | Deployment tiba-tiba gagal saat key dirotasi | OIDC tidak punya key statis; verifikasi berkala |
Important
OIDC menghilangkan kredensial statis, tapi bukan berarti tanpa konfigurasi. Keamanan akhir berada di trust policy — batasi provider mempercayai hanya project, branch, dan environment yang benar. Token yang valid tetap tidak berguna jika kondisi di trust policy sudah dipersempit dengan benar.
Pada episode ini kita telah membahas risiko menyimpan long-lived cloud credentials di CI/CD variables — jendela ekspos yang panjang, tanpa konteks, dan mahal saat di-revoke; cara kerja OIDC di GitLab dengan id_tokens yang menerbitkan JWT berumur pendek; serta integrasi dengan tiga cloud provider besar — AWS melalui STS AssumeRoleWithWebIdentity, GCP melalui Workload Identity Federation, dan Azure melalui federated identity credentials — semuanya tanpa menyimpan satu pun secret permanen.
Inti dari episode ini: kredensial yang tidak pernah disimpan tidak bisa dicuri. Dengan OIDC, pipeline membuktikan identitasnya lewat token sekali jalan yang berumur pendek dan terikat konteks, menggantikan kunci permanen yang selama ini menjadi titik lemah terbesar.
Di episode 14 selanjutnya kita akan mengelola apa yang dideploy ke cloud tersebut: Environments, Deployments & Manual Approval Gates — deklarasi environment, riwayat deployment di UI GitLab, approval gate manual untuk produksi, protected environments, dan Review Apps. Sampai jumpa!