Kubernetes secrets management: Sealed Secrets, ESO en Vault vergeleken

Kubernetes Secrets zijn base64-gecodeerd, niet versleuteld. Voor GitOps-workflows betekent dat: geheime waarden staan onbeschermd in Git of in etcd, tenzij je er een specifiek tool voor inzet. Sealed Secrets, External Secrets Operator en HashiCorp Vault lossen dit probleem elk op hun eigen manier op. Deze vergelijking zet de architectuur, GitOps-geschiktheid, multi-cluster gedrag en operationele kosten naast elkaar zodat je de juiste keuze kunt maken voor jouw team.

Verdict in een oogopslag

Criterium Sealed Secrets External Secrets Operator Vault
GitOps-geschiktheid Uitstekend (versleutelde waarden in Git) Uitstekend (referenties in Git, waarden extern) Matig (secrets staan niet in Git)
Secret-rotatie Handmatig opnieuw sealen Automatisch via refreshInterval Automatisch, TTL-gebaseerd
Dynamische secrets Nee Nee (kan wel door Vault gegenereerde secrets ophalen) Ja (database-credentials, PKI, etc.)
Multi-cluster Slecht (sealing key is clusterspecifiek) Uitstekend (een externe store, veel clusters) Uitstekend (centrale Vault, veel clusters)
Audit trail Git-history + Kubernetes audit log Audit logs van cloudprovider (CloudTrail, etc.) Compleet (elke toegang gelogd)
Infrastructuurafhankelijkheid Alleen de controller Externe secret store vereist Vault-cluster vereist
Complexiteit Laag Gemiddeld Hoog
Geschatte kosten (100 nodes) ~$200/maand ~$530/maand ~$2.400/maand

Kort verdict. Sealed Secrets past bij kleine teams met een enkel cluster die de simpelste GitOps-workflow willen. ESO past bij cloud-native teams die al AWS Secrets Manager, GCP Secret Manager of Azure Key Vault gebruiken en multi-cluster rotatie nodig hebben. Vault past bij enterprise-omgevingen die dynamische secrets, fijnmazige toegangsregels of een volledige audit trail voor compliance nodig hebben.

Waarom base64 geen versleuteling is

Kubernetes Secrets worden standaard onversleuteld opgeslagen in etcd. Het data-veld in een Secret-manifest gebruikt base64-encoding, en dat is een serialisatieformaat, geen beveiligingsmaatregel. Omdraaien kost een commando:

echo "cGFzc3dvcmQxMjM=" | base64 -d
# Output: password123

Iedereen met API-toegang tot het cluster kan Secrets ophalen. Iedereen met toegang tot etcd (direct of via backups) kan ze volledig uitlezen. De officiele Kubernetes-documentatie zegt het zo: "Anyone with API access can retrieve or modify a Secret, and so can anyone with access to etcd."

Dit is het basisprobleem. Alle drie de tools in deze vergelijking bestaan vanwege dit probleem.

etcd-encryptie at rest

Kubernetes ondersteunt encryptie at rest via een EncryptionConfiguration-resource die je aan de API-server meegeeft. De aanbevolen aanpak voor productie is KMS envelope encryption: een unieke data encryption key (DEK) per resource, gewrapt door een key encryption key (KEK) uit een externe KMS zoals AWS KMS, GCP Cloud KMS of Azure Key Vault.

Managed providers (EKS, GKE, AKS) kunnen envelope encryption standaard inschakelen afhankelijk van de clusterconfiguratie, maar ga er niet vanuit dat het actief is zonder verificatie.

etcd-encryptie at rest staat los van de tools hieronder. Sealed Secrets, ESO en de Vault Secrets Operator maken allemaal gewone Kubernetes Secrets die in etcd terechtkomen. Alleen de Vault Agent Injector en de CSI Driver vermijden etcd helemaal door secrets naar memory-backed volumes te schrijven.

Sealed Secrets

Sealed Secrets kiest voor de encrypt-and-commit-aanpak. Je versleutelt een Secret lokaal met de publieke sleutel van de controller, commit de versleutelde SealedSecret naar Git, en de controller in het cluster ontsleutelt hem.

Hoe het werkt

Twee componenten:

  1. Controller (draait in kube-system): genereert en beheert RSA-sleutelparen, kijkt naar SealedSecret-resources, ontsleutelt ze en maakt gewone Kubernetes Secrets.
  2. kubeseal CLI (op je werkstation): versleutelt een plain-tekst Secret-manifest met het publieke certificaat van de controller.

De encryptie is hybride: AES-256-GCM voor de secretwaarde, met de sessiesleutel gewrapt in RSA-2048. De versleutelde SealedSecret kun je veilig committen naar een openbare repository.

GitOps-workflow

# 1. Maak een plain Secret (niet applyen)
kubectl create secret generic db-creds \
  --from-literal=password=s3cretV4lue \
  --dry-run=client -o yaml > secret.yaml

# 2. Seal het
kubeseal < secret.yaml > sealed-secret.yaml

# 3. Verwijder het plain Secret
rm secret.yaml

# 4. Commit sealed-secret.yaml naar je Git-repository

Argo CD en Flux syncen SealedSecret-resources native. De controller regelt de ontsleuteling in het cluster. Als je een Argo CD-gebaseerde GitOps-setup hebt, werken SealedSecret-manifesten gewoon als elke andere Kubernetes-resource in je Application.

Scoping

Scope Gebonden aan Wanneer gebruiken
Strict (standaard) Naam + namespace Hoogste beveiliging; voorkomt cross-namespace replay
Namespace-wide Alleen namespace Hernoemen binnen dezelfde namespace mogelijk
Cluster-wide Geen van beide Spaarzaam gebruiken; vergroot de blast radius als de sleutel lekt

Strict scope verwerkt de naam en namespace in de encryptie-input, waardoor een SealedSecret onbruikbaar is in een andere namespace, zelfs als de private sleutel dezelfde is.

Sleutelrotatie

Sealing keys worden automatisch elke 30 dagen vernieuwd. Nieuwe sleutels worden toegevoegd; oude blijven behouden voor ontsleuteling. Dat betekent dat sleutelrotatie geen re-sealing van bestaande SealedSecrets vereist, maar ook dat de secretwaarden zelf niet geroteerd worden. Het wachtwoord in een sealed secret wijzigen vereist nog steeds een handmatige re-seal.

Het multi-clusterprobleem

Elke controller genereert zijn eigen RSA-sleutelpaar. Een SealedSecret geseald voor cluster A kan niet worden ontsleuteld door cluster B. Voor fleet-brede GitOps heeft elk cluster zijn eigen gesealede versie van elk secret nodig, of je deelt een enkele private sleutel over clusters (wat cluster-level isolatie opheft).

Disaster recovery

Als de sealing private key verloren gaat, zijn alle bestaande SealedSecrets permanent ontoegankelijk. Maak een backup van de sleutel:

kubectl get secret -n kube-system \
  -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > sealing-keys.yaml

Omdat sleutels elke 30 dagen vernieuwd worden, moet je deze backup minstens maandelijks herhalen.

Zwakte: wat Sealed Secrets niet doet

  • Geen dynamische secretgeneratie
  • Geen automatische rotatie van secretwaarden
  • Multi-cluster beheer is operationeel zwaar
  • De private sleutel is een single point of failure
  • Geen fijnmazige toegangsauditing buiten Kubernetes audit logs

External Secrets Operator

External Secrets Operator (ESO) kiest voor de reference-and-fetch-aanpak. Je commit een ExternalSecret-manifest (dat alleen een referentie bevat, nooit een waarde) naar Git. De operator haalt de werkelijke waarde op uit een externe secret store.

Hoe het werkt

ESO breidt Kubernetes uit met drie CRDs:

  • SecretStore (namespace-scoped): definieert de connectie naar een externe provider
  • ClusterSecretStore (cluster-scoped): hetzelfde, maar clusterbreed toegankelijk
  • ExternalSecret: specificeert welk extern secret opgehaald moet worden en hoe het gemapt wordt naar een Kubernetes Secret

Op een configureerbaar schema maakt de operator verbinding met de externe store, haalt waarden op en maakt of updatet een Kubernetes Secret.

Ondersteunde providers

ESO ondersteunt meer dan 40 providers. Stabiele providers zijn onder andere AWS Secrets Manager, AWS Parameter Store (SSM), GCP Secret Manager, Azure Key Vault, HashiCorp Vault, Oracle Vault, Akeyless en CyberArk. Beta- en alpha-providers zijn onder meer 1Password, Bitwarden, Doppler, GitLab Variables en nog veel meer.

Vault is een van de vele opties, geen vereiste.

GitOps-workflow

# Gecommit naar Git: vertelt ESO waar het secret staat, niet de waarde zelf
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-creds
  namespace: production
spec:
  refreshInterval: 15m          # poll elke 15 minuten
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-creds              # het Kubernetes Secret dat ESO aanmaakt
  data:
  - secretKey: password         # key in het K8s Secret
    remoteRef:
      key: production/db-creds  # pad in AWS Secrets Manager
      property: password

Nul secretwaarden in Git. Alleen referenties en metadata.

Refresh-interval en rotatie

Het refreshInterval-veld bepaalt hoe vaak ESO de externe provider pollt. De standaardwaarde is nul, wat betekent dat secrets eenmalig opgehaald worden en nooit bijgewerkt. Stel het expliciet in (bijv. refreshInterval: 15m) als je automatische rotatie wilt.

Wanneer ESO een update detecteert, wordt het Kubernetes Secret bijgewerkt. ESO triggert niet automatisch pod-restarts; daar heb je een tool als Reloader of een deployment rollout-strategie voor nodig.

Multi-cluster sterkte

Een ClusterSecretStore die naar een enkele AWS Secrets Manager-account wijst (of naar elke andere ondersteunde provider) kan een onbeperkt aantal clusters bedienen. Geen per-cluster re-encryptie, geen per-cluster sleutelbeheer. Dit is het punt waar ESO een duidelijk structureel voordeel heeft ten opzichte van Sealed Secrets.

Zwakte: etcd-blootstelling

ESO maakt gewone Kubernetes Secrets. Die secrets komen in etcd terecht. Gebruik je ESO, dan is etcd-encryptie at rest sterk aanbevolen.

Vault op Kubernetes

HashiCorp Vault is een volledig secrets management-platform. Het slaat secrets op, genereert dynamische credentials, handhaaft fijnmazige toegangsregels en logt elke toegangsgebeurtenis. Op Kubernetes biedt Vault drie integratiemethoden:

Vault Secrets Operator (VSO)

De moderne, Kubernetes-native aanpak. VSO gebruikt CRDs (VaultStaticSecret, VaultDynamicSecret, VaultPKISecret) om Vault-secrets te synchroniseren naar Kubernetes Secrets. Een controller per cluster. Laagste resourceverbruik. Secrets zijn onafhankelijk van de pod-lifecycle.

Beperking: ondersteunt momenteel alleen de Kubernetes auth-methode.

Vault Agent Injector

Een mutating webhook die een vault-agent sidecar injecteert in geannoteerde pods. De sidecar authenticeert naar Vault, haalt secrets op en schrijft ze naar een in-memory volume (tmpfs). Secrets komen nooit in etcd. Ondersteunt alle Vault auth-methoden en Golang-templating.

Afweging: maakt per-pod connecties naar Vault, dus bij schaal is de load op Vault het hoogst van de drie methoden.

Vault CSI Provider

Gebruikt het Container Storage Interface om secrets als ephemeral volumes te mounten. Leveranciersonafhankelijk (werkt naast andere CSI-compatibele stores). Secrets blijven buiten etcd. Vereist een DaemonSet met privileged access.

Vergelijking integratiemethoden

Factor VSO Agent Injector CSI Provider
Secrets in etcd Ja Nee Nee
Vault-load Laagst Hoogst Gemiddeld
Auth-methoden Alleen Kubernetes Alle Kubernetes, JWT
Secret-templating Nee Ja (Golang) Nee
Pod lifecycle-koppeling Onafhankelijk Gekoppeld Gekoppeld
Privileged pod vereist Nee Nee Ja

Dynamische secrets: het unieke verkoopargument van Vault

Sealed Secrets noch ESO kunnen secrets genereren. Vault wel. Via de database secrets engine maakt Vault kortlevende, on-demand database-credentials met een TTL. Wanneer de lease verloopt, trekt Vault de credentials in en verwijdert de databasegebruiker. Geen wachtwoorden delen, geen verouderde credentials, automatische expiry.

Het "secret zero"-probleem

Elk secrets-tool heeft een initiele credential nodig om te authenticeren. Vault lost dit op via de Kubernetes auth-methode: een pod presenteert zijn ServiceAccount JWT aan Vault, Vault valideert die tegen de Kubernetes API-server via TokenReview, en geeft een scoped Vault-token terug. Geen vooraf gedeelde secrets nodig. Het Kubernetes-identiteitssysteem zelf is het vertrouwensanker.

Als je RBAC hebt geconfigureerd met least-privilege service accounts, controleert dezelfde ServiceAccount-identiteit die API-toegang regelt ook de Vault-toegang.

Zwakte: operationele kosten

Vault is de meest complexe optie. Een productie-HA-deployment vereist 3-5 dedicated StatefulSet-pods, operationele expertise voor unsealing, upgrades en backups, en doorlopende monitoring. HCP Vault (de managed service) verschuift de operationele last naar SaaS-pricing, maar de conceptuele complexiteit blijft.

Wanneer kies je welke

Kies Sealed Secrets wanneer

  • Je een enkel cluster draait of een heel klein fleet
  • Er geen bestaande externe secret store-infrastructuur is
  • Secrets niet vaak wijzigen
  • Je de simpelste GitOps-first workflow wilt
  • Je team klein is en de voorkeur geeft aan self-contained tooling

Kies ESO wanneer

  • Je al AWS Secrets Manager, GCP Secret Manager, Azure Key Vault of een andere ondersteunde provider gebruikt
  • Multi-cluster omgevingen waar secrets centraal beheerd moeten worden
  • Je automatische rotatie nodig hebt (stel refreshInterval in)
  • Je nul secretwaarden in Git wilt (alleen referenties)
  • Audit logs van je cloudprovider (CloudTrail, Cloud Audit Logs) onderdeel zijn van je complianceverhaal

Kies Vault wanneer

  • Dynamische secretgeneratie vereist is (database-credentials, PKI-certificaten)
  • Enterprise-compliance een volledige, per-access audit trail vereist
  • On-premises of hybride omgevingen zonder managed cloud secret store
  • Fijnmazige, per-applicatie toegangsregels een vereiste zijn
  • Je team Vault-operationele expertise heeft (of je HCP Vault gebruikt)

De hybride optie: ESO + Vault

Veel productie-setups gebruiken ESO als de Kubernetes-integratielaag met Vault als backend. ESO's SecretStore wijst naar Vault; ExternalSecret-CRDs verwijzen naar Vault-paden. Dat geeft je GitOps-vriendelijke declaratieve manifesten, Vault's dynamic secrets engine en ESO's multi-cluster synchronisatie in een enkele architectuur. Een productie-casestudy over 17 clusters rapporteerde nul secrets in Git en automatische propagatie zonder handmatige interventie bij routinematige rotaties.

Wat deze vergelijking niet behandelt

SOPS (Secrets OPerationS) is een bestandsniveau-encryptietool die AWS KMS, GCP KMS, Azure Key Vault en PGP ondersteunt. Flux heeft native SOPS-integratie. Het is een valide GitOps-secrets-optie maar volgt een ander patroon (bestanden versleutelen, niet Kubernetes-resources) en verdient een eigen artikel.

De Secrets Store CSI Driver (het Kubernetes-SIG-project, los van Vault's CSI Provider) mount secrets vanuit externe stores zonder Kubernetes Secrets aan te maken. Het vermijdt etcd volledig maar heeft andere trade-offs rond refresh-controle en GitOps-geschiktheid.

Terugkerende server- of deploymentproblemen?

Ik help teams productie betrouwbaar maken met CI/CD, Kubernetes en cloud—zodat fixes blijven en deploys geen stress meer zijn.

Bekijk DevOps consultancy

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.