- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Config Management: ConfigMaps, Secrets und External Secrets Operator
TL;DR
- ConfigMaps fuer nicht-sensible Daten, Secrets fuer Credentials -- aber native Secrets sind nur Base64-kodiert, nicht verschluesselt
- Encryption at Rest in etcd ist Pflicht fuer jede produktive Umgebung
- External Secrets Operator synchronisiert Secrets aus Vault, AWS KMS oder Azure Key Vault automatisch in den Cluster
- Kustomize fuer einfache Umgebungs-Overrides, Helm fuer komplexere Szenarien mit Conditionals und Loops
- GitOps (ArgoCD oder Flux) ist der sauberste Weg, Konfigurationsaenderungen auditierbar zu machen
Das Problem: Warum Config Management in Kubernetes nicht trivial ist
Auf den ersten Blick wirkt Konfigurationsmanagement in Kubernetes simpel. ConfigMap fuer Settings, Secret fuer Passwoerter, fertig. In der Praxis tauchen aber schnell Probleme auf.
ConfigMaps und Secrets haben kein eingebautes Versioning. Aendert jemand einen Wert, gibt es keinen automatischen Rollback. Pods, die ConfigMaps als Environment Variables lesen, bekommen Aenderungen erst nach einem Restart mit. Secrets liegen standardmaessig als Base64 in etcd -- jeder mit etcd-Zugriff kann sie lesen.
Dazu kommt die Frage der Umgebungstrennung: Dev, Staging, Prod brauchen unterschiedliche Werte fuer dieselben Keys. Und sobald mehrere Teams auf demselben Cluster arbeiten, wird die Zugriffskontrolle auf Konfigurationen relevant.
Dieses Post zeigt die drei Ebenen des Config Managements -- native Objekte, Templating und externe Secret-Stores -- und wann welche Ebene sinnvoll ist.
Ebene 1: ConfigMaps und Secrets richtig einsetzen
ConfigMaps fuer nicht-sensible Konfiguration
ConfigMaps speichern Key-Value-Paare oder ganze Dateien. Sie lassen sich als Environment Variables injizieren oder als Volume mounten.
apiVersion: v1
kind: ConfigMap
metadata:
name: api-gateway-config
namespace: production
data:
LOG_LEVEL: "warn"
MAX_CONNECTIONS: "100"
CACHE_TTL_SECONDS: "300"
nginx.conf: |
worker_processes auto;
events {
worker_connections 1024;
}
http {
upstream backend {
server backend-svc:8080;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
}
}
Wichtiger Punkt: ConfigMaps, die als Volume gemountet sind, werden bei Aenderungen automatisch aktualisiert (mit Delay von bis zu 60 Sekunden). ConfigMaps, die als Environment Variables geladen werden, erfordern einen Pod-Restart. Wer automatische Reloads braucht, setzt auf Volume Mounts oder einen Sidecar wie Reloader.
Secrets: Notwendig, aber allein nicht ausreichend
apiVersion: v1
kind: Secret
metadata:
name: database-credentials
namespace: production
type: Opaque
stringData:
DB_HOST: "postgres-primary.db.svc.cluster.local"
DB_USER: "app_service"
DB_PASSWORD: "r4nd0m-g3n3r4t3d-p4ssw0rd"
DB_SSL_MODE: "verify-full"
Die stringData-Variante ist lesbarer als data mit Base64, wird aber bei kubectl get secret -o yaml trotzdem als Base64 angezeigt. Beides ist keine Verschluesselung.
Encryption at Rest aktivieren
Ohne Encryption at Rest liegen Secrets im Klartext in etcd. Die Konfiguration erfolgt ueber den API-Server:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key-2025
secret: <base64-encoded-32-byte-key>
- identity: {}
Nach dem Aktivieren muessen bestehende Secrets einmal neu geschrieben werden, damit sie verschluesselt abgelegt werden:
# Alle Secrets im Cluster neu verschluesseln
kubectl get secrets --all-namespaces -o json | \
kubectl replace -f -
# Verifizieren: etcdctl muss verschluesselte Daten zeigen
ETCDCTL_API=3 etcdctl get /registry/secrets/production/database-credentials | hexdump -C | head -20
Ebene 2: Templating fuer Umgebungstrennung
Kustomize: Overlays ohne Templating-Sprache
Kustomize arbeitet mit Basis-Manifesten und umgebungsspezifischen Patches. Kein Templating noetig, alles bleibt valides YAML.
Verzeichnisstruktur:
config/
base/
configmap.yaml
kustomization.yaml
overlays/
dev/
kustomization.yaml
staging/
kustomization.yaml
production/
kustomization.yaml
configmap-patch.yaml
Der Production-Overlay kann so aussehen:
# config/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patchesStrategicMerge:
- configmap-patch.yaml
configMapGenerator:
- name: api-gateway-config
behavior: merge
literals:
- LOG_LEVEL=error
- MAX_CONNECTIONS=500
- CACHE_TTL_SECONDS=600
Helm vs. Kustomize: Wann was
| Kriterium | Kustomize | Helm |
|---|---|---|
| Lernkurve | Flach, reines YAML | Steiler, Go Templates |
| Conditionals/Loops | Nicht moeglich | Ja, volle Templating-Logik |
| Packaging/Distribution | Nicht vorgesehen | Charts mit Versionierung |
| Umgebungs-Overrides | Overlays und Patches | values.yaml pro Umgebung |
| Rollback | Ueber Git-History | helm rollback mit Release-History |
| Community-Charts | N/A | Grosses Ecosystem (Bitnami, etc.) |
Faustregel: Kustomize fuer eigene Anwendungen mit einfacher Umgebungstrennung. Helm, wenn man Third-Party-Software deployt oder komplexere Templating-Logik braucht. Beides laesst sich kombinieren -- Helm zum Rendern, Kustomize fuer letzte Overrides.
Ebene 3: External Secrets Operator und Vault-Integration
Native Secrets haben ein fundamentales Problem: Wer Zugriff auf das Git-Repo oder etcd hat, hat Zugriff auf die Secrets. Der External Secrets Operator (ESO) loest das, indem Secrets nur im externen Store (Vault, AWS Secrets Manager, Azure Key Vault) liegen und on-demand in den Cluster synchronisiert werden.
External Secrets Operator Setup
# ExternalSecret, die Credentials aus HashiCorp Vault holt
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
namespace: production
spec:
refreshInterval: 5m
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: database-credentials
creationPolicy: Owner
deletionPolicy: Retain
data:
- secretKey: DB_USER
remoteRef:
key: secret/data/production/database
property: username
- secretKey: DB_PASSWORD
remoteRef:
key: secret/data/production/database
property: password
- secretKey: DB_HOST
remoteRef:
key: secret/data/production/database
property: host
Der dazugehoerige ClusterSecretStore verbindet sich per Kubernetes Service Account Authentication mit Vault:
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.internal.example.com:8200"
path: secret
version: v2
auth:
kubernetes:
mountPath: kubernetes
role: external-secrets
serviceAccountRef:
name: external-secrets-sa
namespace: external-secrets
Vergleich der Secret-Management-Ansaetze
| Ansatz | Sicherheit | Komplexitaet | Kosten | Empfehlung |
|---|---|---|---|---|
| Native Secrets + Encryption at Rest | Mittel | Niedrig | Keine | Einstieg, kleine Teams |
| Sealed Secrets (Bitnami) | Hoch | Niedrig | Keine | Secrets in Git verschluesseln |
| External Secrets + Vault | Sehr hoch | Mittel | Vault-Betrieb | Ab 5+ Microservices |
| External Secrets + Cloud KMS | Sehr hoch | Niedrig | Pay-per-Use | Cloud-native Setups |
Fuer die meisten Teams ist der Einstieg mit nativen Secrets und aktivierter Encryption at Rest der richtige erste Schritt. Sealed Secrets ist ein guter Zwischenschritt, wenn man Secrets in Git committen will. Der External Secrets Operator wird relevant, sobald mehrere Teams oder Cluster auf dieselben Secrets zugreifen muessen.
GitOps-Integration: Konfigurationen auditierbar ausrollen
Der sauberste Workflow fuer Config Management laeuft ueber GitOps. Jede Konfigurationsaenderung ist ein Git-Commit mit Review, Autor und Timestamp.
Der Ablauf:
- Entwickler aendert ConfigMap oder ExternalSecret-Definition im Git-Repo
- Pull Request wird reviewed und gemergt
- ArgoCD oder Flux erkennt die Aenderung und synchronisiert den Cluster
- Bei Problemen: Git Revert und Resync
Das hat zwei grosse Vorteile. Erstens Nachvollziehbarkeit: Jede Konfigurationsaenderung ist in der Git-History sichtbar -- wer, wann, warum. Das macht DSGVO-Audits deutlich einfacher. Zweitens Rollback: Ein git revert bringt den Cluster zurueck in den vorherigen Zustand, ohne dass jemand kubectl edit ausfuehren muss.
Typische Fehler und wie man sie vermeidet
Secrets in Git committen. Passiert staendig, besonders in der Anfangsphase. Loesung: Pre-commit Hooks mit detect-secrets oder gitleaks, plus Sealed Secrets oder ESO fuer den eigentlichen Workflow.
ConfigMaps nicht versionieren. Wenn eine ConfigMap-Aenderung Probleme verursacht, braucht man einen Rollback-Pfad. Loesung: ConfigMaps mit Hash-Suffix im Namen (Kustomize macht das automatisch mit configMapGenerator), sodass ein Rollback des Deployments automatisch die alte ConfigMap nutzt.
Zu breite RBAC-Regeln fuer Secrets. get secrets auf Namespace-Ebene gibt Zugriff auf alle Secrets im Namespace. Loesung: Secrets in dedizierte Namespaces isolieren oder RBAC auf einzelne Secret-Namen einschraenken.
Environment Variables statt Volume Mounts. Env Vars sind bequem, aber sie erfordern Pod-Restarts bei Aenderungen und tauchen in kubectl describe pod auf. Volume Mounts sind sicherer und unterstuetzen Live-Updates.
Weitergehende Themen
- RBAC im Enterprise-Kontext richtig konfigurieren
- GitOps Security: Secrets in der Pipeline absichern
- Kubernetes Storage: Persistente Daten schuetzen
- Supply Chain Security fuer Container Images
Wer Unterstuetzung beim Aufbau einer Config-Management-Strategie braucht -- von der Vault-Integration bis zum GitOps-Workflow -- kann sich gerne unter /kontakt melden.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
Kubernetes Secrets mit HashiCorp Vault verwalten
HashiCorp Vault als zentralen Secrets Store für Kubernetes einrichten mit External Secrets Operator, Vault Agent und praxisnahen YAML-Beispielen.
etcd Encryption at Rest: Kubernetes-Secrets verschlüsseln
Kubernetes-Secrets liegen standardmäßig unverschlüsselt in etcd. So aktivieren Sie Encryption at Rest mit EncryptionConfiguration und rotieren Schlüssel sicher.
GitOps Secrets: SOPS und Sealed Secrets im Vergleich
Secrets sicher in Git verwalten mit Sealed Secrets, Mozilla SOPS und External Secrets Operator. Praxisvergleich für GitOps-Workflows.
External Secrets: Kubernetes-Secrets sicher verwalten
Der External Secrets Operator synchronisiert Secrets aus AWS, Vault und Azure Key Vault nach Kubernetes. Anleitung mit Praxisbeispielen.
ConfigMap und Secret in Pods laden: Alle 4 Methoden
Kubernetes ConfigMaps und Secrets als Umgebungsvariablen oder Volume Mounts in Pods verwenden: env, envFrom, Volume Mount und Projected Volume mit YAML-Beispielen.