Menghilangkan long-lived secrets dari CI/CD: mengambil kredensial sementara melalui OIDC atau AppRole di GitHub Actions, serta integrasi native GitLab CI dengan keyword secrets di .gitlab-ci.yml.

Di episode 12 kalian menghubungkan OpenBao dengan Kubernetes lewat auth ServiceAccount dan sidecar injector. Episode 13 berpindah ke dunia pipeline: kalian akan melihat bagaimana OpenBao menjaga CI/CD tetap bersih dari API keys permanen, dengan mengambil kredensial sementara setiap kali pipeline berjalan. Dua platform yang dibahas adalah GitHub Actions dan GitLab CI/CD.
Sering kali repository menyimpan API keys di Repository Secrets atau variables — nilai itu bertahan lama, dibagikan ke semua job, dan cukup satu kali bocor dampaknya besar. Belum lagi rotasi yang menyebalkan: ganti satu key, semua konfigurasi harus ikut diganti.
Cara yang lebih baik adalah menghilangkan kredensial permanen itu sama sekali. Pipeline hanya menyimpan informasi cara mengambil kredensial, bukan kredensialnya. Pada saat job berjalan, pipeline meminta token sementara ke OpenBao, memakai token tersebut selama job berlangsung, lalu token kedaluwarsa sendiri.
| Aspek | Long-Lived Secrets | Dynamic Secrets |
|---|---|---|
| Umur kredensial | Berbulan-bulan sampai tahun | Menit sampai jam |
| Rotasi | Manual dan mudah terlewat | Otomatis lewat TTL |
| Dampak kebocoran | Sangat besar | Terbatas dan segera kedaluwarsa |
GitHub Actions punya dua cara memakai OpenBao: OIDC untuk autentikasi berbasis trust antara GitHub dan OpenBao, atau AppRole untuk pendekatan yang lebih klasik.
Dengan OIDC, GitHub mengeluarkan token yang berisi klaim tentang repository, environment, dan ref yang menjalankan job. OpenBao menerima token itu setelah memverifikasi signature-nya. Tidak ada secret yang perlu disimpan di repository sama sekali — identitas pipeline itu sendiri menjadi kredensialnya.
Jika OIDC belum memungkinkan, AppRole tetap pilihan yang sah. Job memakai role_id dan secret_id untuk login; secret_id sebaiknya bersifat one-time-use dan pendek umurnya, sehingga sekalipun bocor nilainya tidak berguna di luar pipeline itu.
Action hashicorp/vault-action dikenal sebagai vault-action dan kompatibel dengan OpenBao karena API-nya setara. Contoh workflow yang mengambil kredensial sebelum menjalankan job:
name: deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Ambil kredensial dari OpenBao
uses: hashicorp/vault-action@v6
with:
url: https://bao.internal.example.com
method: approle
roleId: ${{ secrets.OPENBAO_ROLE_ID }}
secretId: ${{ secrets.OPENBAO_SECRET_ID }}
exportToken: true
secrets: secret/data/app db_password | DB_PASSWORD
- name: Jalankan deploy
run: ./deploy.sh
env:
DB_PASSWORD: ${{ env.DB_PASSWORD }}Perhatikan bahwa yang tersimpan di repository hanyalah role_id dan secret_id, bukan database password asli. Nilai sebenarnya diambil saat job berjalan dan hanya hidup dalam lingkungan job itu. Untuk OIDC, ganti blok with dengan konfigurasi method: jwt serta jwt_oidc_audience yang cocok dengan role OpenBao.
GitLab menawarkan integrasi native lewat keyword secrets: pada .gitlab-ci.yml. GitLab Runner menghubungi server OpenBao, melakukan login sesuai role yang ditunjuk, mengambil nilai, lalu menyuntikkannya sebagai environment variable pada job.
vault:
variables:
VAULT_SERVER_URL: https://bao.internal.example.com
VAULT_AUTH_METHOD: approle
VAULT_ROLE_ID: $OPENBAO_ROLE_ID
VAULT_SECRET_ID: $OPENBAO_SECRET_ID
deploy:
stage: deploy
secrets:
DB_PASSWORD:
vault: secret/data/app/db_password@secret
script:
- ./deploy.shVariabel VAULT_SERVER_URL, VAULT_AUTH_METHOD, VAULT_ROLE_ID, dan VAULT_SECRET_ID memberitahu Runner ke mana dan bagaimana login. Keyword secrets: lalu memetakan nilai rahasia ke environment variable DB_PASSWORD sebelum skrip dijalankan.
Kelebihannya, integrasi terjadi di level Runner — secret disuntikkan sebelum skrip dijalankan, sehingga skrip itu sendiri tidak perlu tahu dari mana nilainya berasal. Ini juga berarti secret tidak terlihat di output log.
Note
Kredensial CI/CD paling baik diambil sebagai dynamic secret. Untuk database, gunakan engine database yang mengeluarkan user unik dengan TTL — bukan secret statis — sehingga role_id dan secret_id hanya menjadi pintu masuk, bukan isi rahasia itu sendiri.
| Aspek | GitHub Actions | GitLab CI/CD |
|---|---|---|
| Mekanisme | Action hashicorp/vault-action | Keyword native secrets: |
| Autentikasi | OIDC atau AppRole | OIDC, JWT, atau AppRole |
| Injeksi secret | Environment variable pada step | Environment variable sebelum skrip |
| Konfigurasi | Dilakukan per step action | Keyword di .gitlab-ci.yml |
| Server config | Lewat blok with pada action | Variabel VAULT_SERVER_URL |
Pilih platform yang sesuai dengan ekosistem kalian; prinsip yang sama berlaku: simpan hanya cara mengambil kredensial, biarkan OpenBao mengeluarkan nilainya saat dibutuhkan.
Pada episode 13 ini, kalian memahami bahaya long-lived secrets di CI/CD, integrasi GitHub Actions lewat action hashicorp/vault-action dengan OIDC atau AppRole, serta integrasi native GitLab CI memakai keyword secrets: di .gitlab-ci.yml.
Inti yang harus dibawa pulang:
secrets: menyuntikkan nilai sebelum skrip berjalan, tanpa menyentuh log.Di episode 14 berikutnya, kita mengotomasi infrastruktur: integrasi OpenBao dengan OpenTofu atau Terraform dan Ansible untuk mengambil dynamic database credentials serta PKI certificate saat provisioning.