Jangan pernah commit secret mentah ke Git: bandingkan Sealed Secrets, External Secrets Operator, dan SOPS, lalu praktikkan enkripsi, rotasi, dan RBAC untuk secret.

Di episode 11 sebelumnya kita mengotomasi pembuatan Application dengan ApplicationSet. Semua manifest itu — Application, Deployment, ConfigMap — berani kita simpan di Git karena aman dibaca publik. Tapi ada satu jenis resource yang tidak boleh: Secret. Database password, token API, kunci TLS, credential cloud — jika disimpan mentah di Git, satu repository bocor berarti seluruh infrastruktur terbuka. Pada episode ini kita membahas cara menyimpan secret dengan aman dalam GitOps, dari yang sederhana hingga enterprise.
Mengapa ini penting? "Jangan commit secret" adalah aturan nomor satu GitOps, tapi praktiknya banyak tim melanggarnya karena tidak tahu alternatifnya. Padahal solusinya matang dan beragam: Sealed Secrets untuk enkripsi di Git, External Secrets Operator untuk sinkronisasi dari penyimpanan eksternal, dan SOPS untuk enkripsi file. Memahami kapan memakai yang mana adalah keterampilan wajib engineer platform.
GitOps menuntut segala sesuatu ada di Git — tapi secret justru paling berbahaya jika ada di Git. Tiga masalah mendasar:
Prinsip dasarnya: jangan pernah menyimpan secret mentah, hanya representasi terenkripsi atau referensi ke sumber lain.
| Solusi | Cara kerja | Git menyimpan | Sumber secret |
|---|---|---|---|
| Sealed Secrets | Enkripsi asymmetric, hanya controller yang bisa decrypt | SealedSecret terenkripsi | Git |
| External Secrets Operator | Sinkronisasi dari backend eksternal | ExternalSecret (referensi) | Vault, cloud managers |
| SOPS | Enkripsi file YAML/JSON dengan GPG/age | File terenkripsi | Git + kunci |
| Vault (native) | Template + akses langsung | Tidak ada (atau referensi) | Vault |
Pendekatan paling populer untuk memulai: secret dienkripsi sebelum masuk Git, dan hanya controller di dalam cluster yang memegang kunci privat untuk mendekripsinya.
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets -n kube-system \
--set-string fullnameOverride=sealed-secrets-controller \
sealed-secrets/sealed-secrets
kubeseal --versionController menciptakan pasangan kunci: kunci privat disimpan sebagai Secret di cluster (jangan pernah keluar), kunci publik di-export untuk proses sealing.
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: billing-prod
type: Opaque
stringData:
DB_PASSWORD: s3cr3t-rahasiakubeseal --format yaml < secret.yaml > sealed-secret.yaml
kubectl apply -f sealed-secret.yaml
cat sealed-secret.yamlFile sealed-secret.yaml yang dihasilkan aman untuk di-commit ke Git — isinya terenkripsi dan hanya bisa dibuka oleh controller di cluster pemilik kunci privat. Controller mendekripsi dan membuat Secret db-credentials asli di namespace tujuan.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: billing-secrets
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/devnull/billing-repo.git
path: secrets
destination:
server: https://kubernetes.default.svc
namespace: billing-prodTip
Karena proses sealing butuh kunci publik, export sertifikatnya untuk dipakai di CI: kubeseal --fetch-cert > pub-cert.pem. Pipeline CI yang membangun manifest bisa men-seal secret dari CI variables tanpa akses ke cluster. Kunci privat tidak pernah meninggalkan cluster.
Sebaliknya, ESO tidak menyimpan secret di Git sama sekali — Git hanya berisi referensi berupa ExternalSecret, dan operator menyinkronkan nilai sebenarnya dari penyimpanan eksternal.
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets -n external-secrets \
external-secrets/external-secrets --create-namespaceSecretStore mendefinisikan koneksi ke backend — Vault, AWS Secrets Manager, GCP Secret Manager, dan puluhan provider lain:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: billing-prod
spec:
provider:
vault:
server: https://vault.example.com
path: secret/data/billing
auth:
kubernetes:
mountPath: kubernetes
role: billing-roleapiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: billing-prod
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-credentials
data:
- secretKey: DB_PASSWORD
remoteRef:
key: billing/db
property: passwordESO membaca nilai dari Vault dan membuat Secret db-credentials di cluster. Yang di-commit ke Git hanyalah SecretStore dan ExternalSecret — tidak ada nilai rahasia. Bonus: rotasi cukup dilakukan di Vault, dan ESO menyinkronkan otomatis sesuai refreshInterval.
SOPS mengenkripsi file (YAML, JSON, env) langsung di Git menggunakan kunci GPG atau age:
sops -e -i secrets/values.prod.yaml
sops -d secrets/values.prod.yaml
git add secrets/ && git commit -m "chore: encrypt prod values"File yang terenkripsi tetap berbentuk YAML sehingga diff antar commit tetap terbaca. Integrasi dengan ArgoCD umumnya lewat plugin (SOPS encrypt/decrypt pada repository server) atau dengan memakai kustomize + generator. SOPS adalah pilihan bagus ketika tim ingin nilai tetap "di Git" namun aman.
Untuk skala enterprise, secret ditaruh di penyimpanan terpusat: HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault. Nilainya tidak pernah menyentuh Git — Git hanya menyimpan referensi, dan ESO (atau template engine Vault) yang menghubungkan keduanya. Model ini memberi single source of truth untuk secret dan audit yang jelas.
Warning
Semua solusi di atas mengamankan secret saat disimpan, bukan saat runtime. Pastikan Secret di cluster tetap dibatasi RBAC, dan hindari menampilkan secret di log atau environment variable yang mudah bocor dari aplikasi.
target.name dan namespace sesuai dengan yang dibutuhkan Deployment.refreshInterval tidak pernah aktif, Secret di cluster basi.Episode ini menjawab dilema klasik GitOps: cara menyimpan secret tanpa membocorkannya ke Git. Kita membandingkan Sealed Secrets (enkripsi di Git), External Secrets Operator (referensi + sinkronisasi dari backend), SOPS (enkripsi file), serta Vault dan cloud secret managers sebagai sumber terpusat, ditutup dengan praktik terbaik dan jebakan umum.
Poin yang harus kalian bawa:
Deployment kini aman dan berisi secret yang tersimpan benar. Namun ada satu dimensi yang belum kita kendalikan: urutan dan efek samping saat sync. Di episode 13 selanjutnya kita membahas Resource Hooks & Lifecycle: hook PreSync, Sync, PostSync, dan SyncFail untuk migrasi database, smoke test, dan rollback — plus pengaturan urutan eksekusinya dengan sync wave. Sampai jumpa di episode 13!