External Secrets Operator เป็น Kubernetes Operator ที่ช่วย Integrate Kubernetes Secret กับ KMS ภายนอกโดย Operator จะทำการ sync credential จาก KMS ภายนอกและทำการ update secret ของ Kubernetes อัตโนมัติ ช่วยให้การจัดการ credential สามารถจัดการแก้ไขจากระบบ KMS ได้จากที่เดียว
สำหรับ NKP สามารถ Enable ได้จากหน้า Applications Catalog

หลังจาก enable แล้ว เราจะต้องทำให้ Vault trust Kubernetes จากนั้นสร้าง SecretStore เพื่อเป็นสะพานเชื่อมระหว่าง Kubernetes และ Vault หลังจากนั้นสร้าง ExternalSecret เพื่อ Sync Secret ให้กับ Kubernetes
ขั้นตอนการทำให้ Vault trust Kubernetes
# Exec into your vault-0 podkubectl exec -it vault-0 -n vault -- shvault login hvs.SMpvYTqteXW6Vjup8HWIB972# 1. Enable Kubernetes authvault auth enable kubernetes# 2. Configure it to talk to the local K8s APIvault write auth/kubernetes/config \ kubernetes_host="https://kubernetes.default.svc:443"# 3. Create a policy for ESO to read secretsvault policy write eso-read-policy - <<EOF path "secret/data/*" { capabilities = ["read"] }EOF# 4. Create a role that binds the ESO ServiceAccount to the policy# Assuming ESO is in 'external-secrets' namespace with SA name 'external-secrets'vault write auth/kubernetes/role/eso-role \bound_service_account_names=external-secrets \bound_service_account_namespaces=external-secrets \policies=eso-read-policy \ttl=1h
สร้าง SecretStore ด้วย yaml file ดังนี้
apiVersion: external-secrets.io/v1kind: ClusterSecretStoremetadata: name: vault-backendspec: provider: vault: server: "http://vault.vault.svc.cluster.local:8200" path: "secret" version: "v2" auth: kubernetes: # This must match the role name you created in Vault Step 1.4 role: "eso-role" mountPath: "kubernetes" serviceAccountRef: name: "external-secrets" namespace: "external-secrets"
สร้าง External Secret store สำหรับ sync secret กับ Vault มายัง Kubernetes ด้วย yaml file ดังนี้
apiVersion: external-secrets.io/v1kind: ExternalSecretmetadata: name: my-app-secret namespace: defaultspec: refreshInterval: "1h" # How often to sync secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: k8s-app-secret # The name of the resulting K8s Secret creationPolicy: Owner data: - secretKey: DATABASE_PASSWORD # Key in the K8s Secret remoteRef: key: my-app/db-creds # Path in Vault property: password # Key inside the Vault JSON
ตรวจสอบว่ามีการสร้าง secret k8s-app-secret ที่ namespace default จากคำสั่งข้างต้นจริง
kubectl get secretNAME TYPE DATA AGEk8s-app-secret Opaque 1 31s
ดูข้อมูลของ secret จะพบว่ามีการ sync DATABASE_PASSWORD จาก Vault มาให้
kubectl get secret k8s-app-secret -o yamlapiVersion: v1data: DATABASE_PASSWORD: cGFzc3dvcmQxMjM=kind: Secretmetadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"external-secrets.io/v1","kind":"ExternalSecret","metadata":{"annotations":{},"name":"my-app-secret","namespace":"default"},"spec":{"data":[{"remoteRef":{"key":"my-app/db-creds","property":"password"},"secretKey":"DATABASE_PASSWORD"}],"refreshInterval":"1h","secretStoreRef":{"kind":"ClusterSecretStore","name":"vault-backend"},"target":{"creationPolicy":"Owner","name":"k8s-app-secret"}}} reconcile.external-secrets.io/data-hash: 69b12d606fda3589324b709f341cf77986d7128c2fb089486fe84d76 creationTimestamp: "2026-02-05T11:21:32Z" labels: reconcile.external-secrets.io/created-by: ea4461eb1de01e986cc8315e7fc9b7bdbdf0204590c521bfc076aa6e reconcile.external-secrets.io/managed: "true" name: k8s-app-secret namespace: default ownerReferences: - apiVersion: external-secrets.io/v1 blockOwnerDeletion: true controller: true kind: ExternalSecret name: my-app-secret uid: 084595bf-cef5-417f-9a98-2f77b82512ec resourceVersion: "949692" uid: c0a8c2aa-e0c7-44c3-86bc-dcfacc7190a0type: Opaque
