Belajar Kubernetes - Episode 41 - Pengenalan dan Penjelasan External Secret Manager

Belajar Kubernetes - Episode 41 - Pengenalan dan Penjelasan External Secret Manager

Di episode ini kita akan coba bahas External Secret Manager seperti HashiCorp Vault untuk manage secret di Kubernetes. Kita akan mempelajari bagaimana store, retrieve, dan rotate secret securely, dan best practice untuk secret management.

Arman Dwi Pangestu
Arman Dwi PangestuApril 16, 2026
0 views
6 min read

Pendahuluan

Catatan

Untuk kalian yang ingin membaca episode sebelumnya, bisa click thumbnail episode 40 di bawah ini

Episode 40Episode 40

Di episode sebelumnya, kita menjelajahi GitOps, yang menggunakan Git sebagai source of truth untuk Kubernetes deployment. Sekarang kita akan mendalami External Secret Manager, yang menyediakan secure secret management untuk Kubernetes application.

Catatan: Disini saya akan menggunakan Kubernetes Cluster yang di install melalui K3s.

Storing secret di Kubernetes Secret atau Git tidak aman. External Secret Manager seperti HashiCorp Vault menyediakan centralized, secure way untuk manage secret. Pikirkan Vault seperti secure vault untuk secret Anda - ini encrypt, audit, dan control access ke sensitive data. Dengan External Secrets Operator, Anda dapat automatically sync secret dari Vault ke Kubernetes.

Memahami External Secret Manager

External Secret Manager adalah centralized system untuk manage, store, dan rotate secret. Ini menyediakan encryption, audit logging, dan fine-grained access control.

Mengapa External Secret Manager Penting

1. Centralized Management

Semua secret di satu secure location.

2. Encryption

Secret encrypted at rest dan in transit.

3. Audit Logging

Track siapa access apa dan kapan.

4. Access Control

Fine-grained permission untuk secret access.

5. Secret Rotation

Automatically rotate secret tanpa downtime.

6. Compliance

Meet security compliance requirement.

7. Multi-Environment

Manage secret di dev, staging, production.

HashiCorp Vault

Vault adalah popular open-source secret management tool.

Vault Architecture

plaintext
┌─────────────────────────────────────┐
│      Vault Server                   │
│  ┌─────────────────────────────┐   │
│  │  Secret Storage             │   │
│  │  - Database credential      │   │
│  │  - API key                  │   │
│  │  - Certificate              │   │
│  └─────────────────────────────┘   │
│  ┌─────────────────────────────┐   │
│  │  Authentication             │   │
│  │  - Kubernetes auth          │   │
│  │  - JWT auth                 │   │
│  │  - AppRole                  │   │
│  └─────────────────────────────┘   │
│  ┌─────────────────────────────┐   │
│  │  Audit Logging              │   │
│  │  - Access log               │   │
│  │  - Change history           │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘

Installing Vault

Kubernetesbash
# Download Vault
wget https://releases.hashicorp.com/vault/1.15.0/vault_1.15.0_linux_amd64.zip
unzip vault_1.15.0_linux_amd64.zip
 
# Start Vault di dev mode
vault server -dev

Vault Configuration

Kubernetesvault-config.hcl
storage "file" {
  path = "/vault/data"
}
 
listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_disable   = false
  tls_cert_file = "/vault/tls/vault.crt"
  tls_key_file  = "/vault/tls/vault.key"
}
 
ui = true

External Secrets Operator

External Secrets Operator sync secret dari external system ke Kubernetes.

Installation

Kubernetesbash
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets \
  external-secrets/external-secrets \
  -n external-secrets-system \
  --create-namespace

SecretStore

SecretStore define bagaimana connect ke Vault:

Kubernetessecretstore.yaml
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: "https://vault.example.com:8200"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "my-app"

ExternalSecret

ExternalSecret define secret mana yang di-sync:

Kubernetesexternalsecret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secret
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: app-secret
    creationPolicy: Owner
  data:
  - secretKey: database-password
    remoteRef:
      key: database
      property: password
  - secretKey: api-key
    remoteRef:
      key: api
      property: key

Vault Secret Engine

KV Secret Engine

Store key-value secret:

Kubernetesbash
# Enable KV v2 secret engine
vault secrets enable -version=2 kv
 
# Store secret
vault kv put kv/database \
  username=admin \
  password=secret123
 
# Retrieve secret
vault kv get kv/database

Database Secret Engine

Generate dynamic database credential:

Kubernetesbash
# Enable database secret engine
vault secrets enable database
 
# Configure database connection
vault write database/config/my-db \
  plugin_name=mysql-database-plugin \
  allowed_roles="readonly" \
  connection_url="{{username}}:{{password}}@tcp(db.example.com:3306)/" \
  username="vault" \
  password="vault-password"
 
# Create role
vault write database/roles/readonly \
  db_name=my-db \
  creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; GRANT SELECT ON *.* TO '{{name}}'@'%';" \
  default_ttl="1h" \
  max_ttl="24h"
 
# Generate credential
vault read database/creds/readonly

PKI Secret Engine

Generate certificate:

Kubernetesbash
# Enable PKI secret engine
vault secrets enable pki
 
# Generate root certificate
vault write -field=certificate pki/root/generate/internal \
  common_name="example.com" \
  ttl=87600h > CA_cert.crt
 
# Create role
vault write pki/roles/example-dot-com \
  allowed_domains="example.com" \
  allow_subdomains=true \
  max_ttl="72h"
 
# Issue certificate
vault write pki/issue/example-dot-com \
  common_name="app.example.com"

Vault Authentication Method

Kubernetes Authentication

Kubernetesbash
# Enable Kubernetes auth
vault auth enable kubernetes
 
# Configure Kubernetes auth
vault write auth/kubernetes/config \
  token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token \
  kubernetes_host=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
 
# Create role
vault write auth/kubernetes/role/my-app \
  bound_service_account_names=my-app \
  bound_service_account_namespaces=default \
  policies=my-app-policy \
  ttl=24h

AppRole Authentication

Kubernetesbash
# Enable AppRole auth
vault auth enable approle
 
# Create role
vault write auth/approle/role/my-app \
  token_ttl=1h \
  token_max_ttl=4h \
  policies="my-app-policy"
 
# Get role ID
vault read auth/approle/role/my-app/role-id
 
# Generate secret ID
vault write -f auth/approle/role/my-app/secret-id

Contoh Praktis

Database Credential

Kubernetesdatabase-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
  - secretKey: username
    remoteRef:
      key: database
      property: username
  - secretKey: password
    remoteRef:
      key: database
      property: password
---
apiVersion: v1
kind: Pod
metadata:
  name: app-with-db
spec:
  containers:
  - name: app
    image: myapp:latest
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password

API Key

Kubernetesapi-keys-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: api-keys
spec:
  refreshInterval: 30m
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: api-keys
    creationPolicy: Owner
  dataFrom:
  - extract:
      key: api-keys

TLS Certificate

Kubernetestls-certificate-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: tls-cert
spec:
  refreshInterval: 24h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: tls-cert
    template:
      type: kubernetes.io/tls
      data:
        tls.crt: "{{ .certificate }}"
        tls.key: "{{ .private_key }}"
  data:
  - secretKey: certificate
    remoteRef:
      key: certificates/app
      property: cert
  - secretKey: private_key
    remoteRef:
      key: certificates/app
      property: key

Secret Rotation

Automatic Rotation

Kubernetesauto-rotation.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: rotating-secret
spec:
  refreshInterval: 1h  # Refresh setiap jam
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: rotating-secret
    creationPolicy: Owner
  data:
  - secretKey: api-key
    remoteRef:
      key: api-keys/rotating
      property: key

Manual Rotation

Kubernetesbash
# Rotate secret di Vault
vault kv put kv/api-keys/rotating \
  key=new-api-key-value
 
# External Secrets akan automatically sync
# dalam refreshInterval

Kesalahan dan Jebakan Umum

Kesalahan 1: Storing Secret di Git

Problem: Secret exposed di Git history.

KubernetesKesalahan: Secret di Git
# JANGAN LAKUKAN INI - Secret di Git
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
data:
  password: c2VjcmV0MTIz

Solusi: Gunakan External Secret Manager:

KubernetesCorrect: External Secret Manager
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-secret
spec:
  secretStoreRef:
    name: vault-backend
  target:
    name: db-secret

Kesalahan 2: Not Rotating Secret

Problem: Compromised secret tetap active.

Solusi: Enable automatic rotation:

Kubernetesyaml
spec:
  refreshInterval: 1h  # Rotate setiap jam

Kesalahan 3: Weak Access Control

Problem: Siapa pun dapat access semua secret.

Solusi: Implement fine-grained policy:

Kubernetesvault-policy.hcl
path "kv/data/database" {
  capabilities = ["read"]
}
 
path "kv/data/api-keys" {
  capabilities = ["read"]
}
 
path "kv/data/admin/*" {
  capabilities = []  # No access
}

Kesalahan 4: Not Auditing Secret Access

Problem: No visibility ke siapa access secret.

Solusi: Enable audit logging:

Kubernetesbash
vault audit enable file file_path=/vault/logs/audit.log

Kesalahan 5: Hardcoding Secret di Code

Problem: Secret exposed di source code.

Solusi: Selalu gunakan secret management:

KubernetesKesalahan: Hardcoded
# JANGAN LAKUKAN INI
export DB_PASSWORD="secret123"
KubernetesCorrect: From Secret
export DB_PASSWORD=$(kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d)

Praktik Terbaik

1. Gunakan Kubernetes Authentication

Kubernetesyaml
auth:
  kubernetes:
    mountPath: "kubernetes"
    role: "my-app"

2. Set Appropriate TTL

Kubernetesbash
vault write auth/kubernetes/role/my-app \
  ttl=24h \
  max_ttl=7d

3. Implement Least Privilege

Kuberneteshcl
# Hanya grant necessary permission
path "kv/data/my-app/*" {
  capabilities = ["read"]
}

4. Enable Audit Logging

Kubernetesbash
vault audit enable file file_path=/vault/logs/audit.log

5. Rotate Secret Regularly

Kubernetesyaml
spec:
  refreshInterval: 1h

6. Gunakan Separate Vault untuk Environment

plaintext
Vault Dev
Vault Staging
Vault Production

7. Backup Vault Data

Kubernetesbash
vault operator raft snapshot save vault-backup.snap

8. Monitor Secret Access

Kubernetesbash
# Review audit log
vault audit list
tail -f /vault/logs/audit.log

Vault vs Kubernetes Secret

AspekVaultKubernetes Secret
EncryptionYaOptional
Audit LoggingYaLimited
Access ControlFine-grainedRBAC only
Secret RotationAutomaticManual
CentralizedYaPer-cluster
ComplianceYaLimited
CostSelf-hosted atau managedFree

Monitoring dan Troubleshooting

Check Secret Sync Status

Kubernetesbash
kubectl describe externalsecret app-secret
kubectl get externalsecret -o wide

View Vault Audit Log

Kubernetesbash
vault audit list
tail -f /vault/logs/audit.log

Test Vault Connectivity

Kubernetesbash
kubectl exec -it pod-name -- \
  curl -k https://vault.example.com:8200/v1/sys/health

Debug External Secret

Kubernetesbash
kubectl logs -n external-secrets-system \
  deployment/external-secrets

Kesimpulan

Pada episode 41 ini, kita telah membahas External Secret Manager di Kubernetes secara mendalam. Kita sudah belajar bagaimana gunakan HashiCorp Vault dengan External Secrets Operator untuk securely manage secret.

Key takeaway:

  • External Secret Manager menyediakan centralized secret management
  • HashiCorp Vault - Popular open-source secret manager
  • External Secrets Operator - Sync secret dari Vault ke Kubernetes
  • SecretStore - Define connection ke Vault
  • ExternalSecret - Define secret mana yang di-sync
  • Secret Engine - KV, Database, PKI, dll
  • Authentication Method - Kubernetes auth, AppRole, JWT
  • Encryption - Secret encrypted at rest dan in transit
  • Audit Logging - Track semua secret access
  • Access Control - Fine-grained permission
  • Secret Rotation - Automatic rotation tanpa downtime
  • Jangan store secret di Git - Gunakan external manager
  • Enable audit logging - Monitor secret access
  • Implement least privilege - Hanya grant necessary permission
  • Rotate secret regularly - Minimize compromise window

External Secret Manager essential untuk production Kubernetes deployment untuk ensure secret aman, auditable, dan compliant.

Catatan

Untuk kalian yang ingin melanjutkan ke episode selanjutnya, bisa click thumbnail episode 42 di bawah ini

Episode 42Episode 42

Related Posts