Menggabungkan OpenBao dengan Kubernetes: otentikasi ServiceAccount lewat auth/kubernetes, injeksi sidecar otomatis melalui mutation webhook, serta sinkronisasi rahasia menjadi native Kubernetes Secrets.

Di episode 11 kalian berkenalan dengan OpenBao Agent dan template-nya untuk merender file konfigurasi berisi rahasia. Episode 12 membawa Agent ke lingkungan yang paling sering menghuninya, yaitu Kubernetes. Kita membahas tiga hal: bagaimana Pod mengautentikasi dirinya ke OpenBao lewat auth/kubernetes, bagaimana mutation webhook menginjeksi sidecar Agent secara otomatis, dan bagaimana rahasia disinkronkan menjadi native Kubernetes Secrets.
Pada dasarnya, auth/kubernetes adalah metode yang memungkinkan sebuah Pod membuktikan identitasnya tanpa password manusia. Identitas itu diambil dari ServiceAccount yang melekat pada Pod.
Setiap ServiceAccount di Kubernetes memiliki JWT yang dipasang di dalam Pod pada /var/run/secrets/kubernetes.io/serviceaccount/token. Alur otentikasinya seperti ini:
Karena validasi dilakukan oleh API server, OpenBao perlu tahu bagaimana menghubungi API server dan otoritas yang dipercaya. Informasi inilah yang dikonfigurasi pada mount auth method.
Pertama, aktifkan metode autentikasi:
bao auth enable kubernetesKemudian hubungkan metode ini dengan klaster:
bao write auth/kubernetes/config \
kubernetes_host=https://kubernetes.default.svc \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/tokenkubernetes_host adalah alamat API server klaster, kubernetes_ca_cert adalah sertifikat CA untuk memverifikasi koneksi TLS, dan token_reviewer_jwt adalah JWT milik ServiceAccount yang memiliki izin untuk melakukan TokenReview.
Role menjadi jembatan antara identitas Pod dan policy. Perintah berikut membuat role yang mengikat ServiceAccount bernama app di namespace default ke policy app-readonly:
bao write auth/kubernetes/role/app \
bound_service_account_names=app \
bound_service_account_namespaces=default \
policies=app-readonly \
ttl=1hTip
Semua perintah di atas cukup dijalankan sekali oleh administrator. Saat Pod login, OpenBao hanya perlu menerima JWT ServiceAccount — misalnya bao login -method=kubernetes — dan token aplikasi keluar secara otomatis. Tidak ada kredensial permanen yang disimpan di gambar container.
Menjalankan Agent secara manual di tiap Pod itu merepotkan dan mudah terlewat. Sidecar Injector mengotomatiskan seluruh proses melalui mutation webhook: cukup tambahkan beberapa annotation, dan webhook menyisipkan container Agent saat Pod diciptakan.
Injector memasang mutating webhook yang mendengarkan peristiwa pembuatan Pod. Saat menemukan annotation openbao.org/agent-inject: "true", webhook memodifikasi spec Pod secara transparan: menambahkan container Agent, menambahkan volume bersama, lalu memasang init container yang mengambil token. Dari sudut pandang aplikasi, tidak ada yang berubah — aplikasi hanya melihat file rahasia muncul di direktori yang disepakati.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
metadata:
annotations:
openbao.org/agent-inject: "true"
openbao.org/agent-inject-secret-config: "secret/data/app"
openbao.org/role: "app"
openbao.org/agent-inject-template-config: |
{{- with secret "secret/data/app" -}}
DB_PASSWORD={{ .Data.data.db_password }}
{{- end }}Annotation pertama menyalakan injeksi, openbao.org/agent-inject-secret-config menunjuk path rahasia yang dimuat, dan template ditulis lewat annotation yang nama akhiran -template-config. Untuk role, tulis nama role auth Kubernetes yang sudah dibuat sebelumnya.
Hasil render disimpan di shared volume berbasis emptyDir dengan medium Memory. Pathnya mengikuti nama annotation rahasia, yaitu /bao/secrets/config. Karena volume ini berada di memori, rahasia tidak pernah ditulis ke disk dan otomatis hilang saat Pod berhenti. Saat rahasia di OpenBao berubah, Agent memperbarui file dan memberi tanda; aplikasi yang membaca file cukup menunggu pembaruan berikutnya.
Important
Pastikan token ServiceAccount yang dipakai aplikasi hanya memiliki policy seperlunya. Sidecar in-memory memang aman dari sisi disk, tetapi policy yang terlalu longgar tetap membuka pintu bagi Pod lain yang diretas. Prinsip least privilege berlaku di lapisan mana pun, termasuk di sini.
| Aspek | Sidecar Injector | Native Kubernetes Secrets Sync |
|---|---|---|
| Mekanisme | Mutation webhook menambahkan container Agent | Komponen sink menulis objek Secret |
| Media rahasia | Volume in-memory /bao/secrets/config | Objek Secret yang disimpan di etcd |
| Siklus hidup | Hilang otomatis saat Pod mati | Tetap ada sampai dihapus |
| Rotasi | File di-update langsung oleh Agent | Secret perlu di-update dan Pod perlu reload |
| Kebutuhan ekstra | Webhook injector terpasang di klaster | Kontroller sink berjalan di klaster |
Keduanya sah, tetapi untuk kasus di mana aplikasi tidak bisa diubah, sidecar in-memory lebih unggul karena aplikasi tetap membaca file biasa. Sinkronisasi native dipilih saat ekosistem di sekitar kalian bergantung pada objek Secret standar Kubernetes, misalnya Helm chart atau operator lain.
Jika sebagian komponen hanya memahami objek Secret standar, sinkronisasi menjadi jalan keluarnya. Rahasia dibaca dari OpenBao lalu ditulis sebagai objek Secret:
apiVersion: v1
kind: Secret
metadata:
name: app-db
type: Opaque
stringData:
db_password: "nilai-rahasia-dari-openbao"Perhatikan trade-off-nya: begitu rahasia masuk ke objek Secret, ia disimpan di etcd dan tidak lagi "hidup" mengikuti rotasi di OpenBao, kecuali sink terus memperbaruinya. Untuk keamanan paling ketat, utamakan sidecar in-memory; gunakan sink native hanya ketika memang diperlukan oleh ekosistem.
Pada episode 12 ini, kalian memahami otentikasi ServiceAccount JWT lewat auth/kubernetes, konfigurasi kubernetes_host dan token_reviewer_jwt, penyusunan role yang menghubungkan Pod dengan policy, injeksi sidecar Agent via mutation webhook dengan annotation openbao.org/agent-inject, rahasia pada volume in-memory /bao/secrets/config, serta sinkronisasi ke native Kubernetes Secrets.
Inti yang harus dibawa pulang:
Di episode 13 berikutnya, kita keluar dari klaster dan masuk ke dunia pipeline: integrasi OpenBao dengan GitHub Actions dan GitLab CI untuk menghapus long-lived secrets dari repository.