- Authors

- Name
- Phillip Pham
- @ddppham
TL;DR
Secrets gehören nicht als Klartext in Git. Sealed Secrets verschlüsselt direkt im Cluster, SOPS nutzt externe Schlüssel wie age oder KMS, und der External Secrets Operator holt Secrets aus Vaults. Welche Lösung passt, hängt von Teamgröße, Cloud-Provider und vorhandener Infrastruktur ab.
Secrets in GitOps: Das Grundproblem
GitOps verlangt, dass der gesamte Cluster-State in Git liegt. Kubernetes Secrets sind aber nur Base64-kodiert — nicht verschlüsselt. Wer ein Secret als YAML committed, legt Passwörter praktisch im Klartext ab.
Drei Tools lösen dieses Problem auf unterschiedliche Weise. Hier ist ein praxisnaher Vergleich.
# So NICHT — Base64 ist keine Verschlüsselung
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
password: cGFzc3dvcmQxMjM= # echo -n "password123" | base64
Sealed Secrets (Bitnami)
Sealed Secrets besteht aus einem Controller im Cluster und dem CLI-Tool kubeseal. Der Controller generiert ein asymmetrisches Schlüsselpaar. Du verschlüsselst lokal mit dem Public Key — entschlüsseln kann nur der Controller im Cluster.
Installation
# Controller installieren
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets \
--namespace kube-system
# CLI installieren
# macOS
brew install kubeseal
# Linux
KUBESEAL_VERSION=0.27.3
curl -LO "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION}/kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz"
tar -xzf kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz
sudo mv kubeseal /usr/local/bin/
SealedSecret erstellen
# Normales Secret erstellen (wird nicht applied)
kubectl create secret generic db-credentials \
--from-literal=password=mein-sicheres-pw \
--dry-run=client -o yaml > secret.yaml
# Mit kubeseal verschlüsseln
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
Das Ergebnis ist eine SealedSecret-Ressource, die sicher in Git committed werden kann:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: default
spec:
encryptedData:
password: AgBy3i4OJSWK+PiTySYZZA9rO... # RSA-verschlüsselt
template:
metadata:
name: db-credentials
Der Controller entschlüsselt die SealedSecret automatisch und erstellt daraus ein normales Kubernetes Secret.
Mozilla SOPS mit age
SOPS (Secrets OPerationS) verschlüsselt einzelne Werte innerhalb von YAML- oder JSON-Dateien. In Kombination mit age brauchst du keinen Cloud-KMS — nur ein Schlüsselpaar.
Setup mit age
# age installieren
# macOS
brew install age
# Linux
sudo apt install age
# Schlüsselpaar generieren
age-keygen -o age-key.txt
# Public key: age1abc123...
# SOPS installieren
brew install sops # oder via GitHub Release
Konfiguration
Erstelle eine .sops.yaml im Repository-Root:
creation_rules:
- path_regex: .*\.secret\.yaml$
age: "age1abc123def456..." # Dein Public Key
- path_regex: .*\.enc\.yaml$
age: "age1abc123def456..."
Secrets verschlüsseln
# Secret-Datei verschlüsseln
sops --encrypt --in-place k8s/overlays/prod/db.secret.yaml
# Zum Bearbeiten (entschlüsselt temporär im Editor)
sops k8s/overlays/prod/db.secret.yaml
# Entschlüsseln
sops --decrypt k8s/overlays/prod/db.secret.yaml
SOPS verschlüsselt nur die Werte, nicht die Schlüssel. Das macht Diffs lesbar:
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
data:
password: ENC[AES256_GCM,data:abc123...,tag:xyz...]
sops:
age:
- recipient: age1abc123...
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
SOPS mit Flux CD
Flux hat native SOPS-Integration. Der Decryption-Key wird als Secret im Cluster hinterlegt:
# age-Key als Secret im Cluster
kubectl create secret generic sops-age \
--namespace flux-system \
--from-file=age.agekey=age-key.txt
# In der Kustomization SOPS aktivieren
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app-secrets
namespace: flux-system
spec:
decryption:
provider: sops
secretRef:
name: sops-age
path: ./k8s/overlays/prod
sourceRef:
kind: GitRepository
name: main-repo
External Secrets Operator
Der dritte Ansatz: Secrets liegen gar nicht in Git, sondern in einem externen Secret Store (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault). Der External Secrets Operator synchronisiert sie in den Cluster.
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
--namespace external-secrets --create-namespace
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: db-credentials
data:
- secretKey: password
remoteRef:
key: production/database
property: password
Vergleich der drei Ansätze
| Kriterium | Sealed Secrets | SOPS + age | External Secrets |
|---|---|---|---|
| Secrets in Git | Ja (verschlüsselt) | Ja (verschlüsselt) | Nein (nur Referenz) |
| Externe Abhängigkeit | Keine | Keine | Vault/Cloud KMS |
| ArgoCD-Integration | Nativ | Plugin nötig | Nativ |
| Flux-Integration | Via Controller | Nativ | Via Controller |
| Key-Rotation | Controller-Restart | Re-Encrypt | Automatisch |
| Multi-Cluster | Umständlich | Einfach | Einfach |
Sealed Secrets eignet sich für Teams, die alles in Git haben wollen und einen einzelnen Cluster betreiben. Der Nachteil: Der Private Key lebt nur im Cluster. Bei Cluster-Verlust ohne Key-Backup sind alle Secrets verloren.
SOPS ist flexibler bei Multi-Cluster-Setups. Derselbe verschlüsselte File funktioniert überall, wo der age-Key verfügbar ist. Flux-Nutzer profitieren von der nativen Integration.
External Secrets passt zu Organisationen, die bereits einen zentralen Secret Store betreiben. Secrets werden nie in Git gespeichert — dafür braucht man aber stabile Netzwerkverbindungen zum Store.
ArgoCD-Integration
Für ArgoCD mit Sealed Secrets brauchst du keine Extra-Konfiguration — der Controller läuft im Cluster und verarbeitet SealedSecret-Ressourcen automatisch.
Für SOPS mit ArgoCD gibt es das argocd-vault-plugin oder den Weg über ein Init-Container-Setup mit Kustomize:
# argocd-repo-server Patch für SOPS
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-repo-server
namespace: argocd
spec:
template:
spec:
containers:
- name: argocd-repo-server
env:
- name: SOPS_AGE_KEY_FILE
value: /app/config/age/age-key.txt
volumeMounts:
- name: age-key
mountPath: /app/config/age
volumes:
- name: age-key
secret:
secretName: sops-age-key
FAQ
Welche Lösung ist am einfachsten für den Einstieg?
Sealed Secrets. Installation dauert unter fünf Minuten, und der Workflow ist simpel: Secret erstellen, kubeseal ausführen, Ergebnis committen. Kein externes Key-Management nötig.
Was passiert bei Sealed Secrets, wenn der Cluster neu aufgesetzt wird?
Ohne Backup des Signing-Keys kannst du bestehende SealedSecrets nicht mehr entschlüsseln. Sichere den Key regelmäßig: kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > sealed-secrets-key-backup.yaml
Kann ich SOPS und Sealed Secrets kombinieren?
Technisch ja, aber es erhöht die Komplexität ohne klaren Vorteil. Entscheide dich für einen Ansatz pro Cluster oder Umgebung.
Wie funktioniert Key-Rotation bei SOPS?
Neuen age-Key generieren, .sops.yaml aktualisieren, dann alle Dateien neu verschlüsseln: find . -name "*.secret.yaml" -exec sops updatekeys {} \;. Der alte Key kann danach entfernt werden.
Ist der External Secrets Operator auch ohne Cloud nutzbar?
Ja, mit HashiCorp Vault als Backend. Vault kann on-premises laufen und unterstützt alle Features des External Secrets Operators inklusive automatischer Rotation.
Nächster Schritt: Wenn du bereits ArgoCD nutzt, starte mit Sealed Secrets für einzelne Cluster oder SOPS für Multi-Cluster-Setups. Für eine umfassende GitOps-Einführung mit ArgoCD lies unseren ArgoCD ApplicationSet Guide.
Kubernetes-Expertise gesucht?
Managed Services, Beratung, Training oder Security – wir unterstützen deutsche Unternehmen bei allen Kubernetes-Themen.
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
Sealed Secrets Anleitung: Kubernetes Secrets in Git
Sealed Secrets verschlüsseln Kubernetes Secrets für Git-Repos. Installation, kubeseal-Nutzung und GitOps-Integration Schritt für Schritt erklärt.
GitOps Security: Supply Chain mit ArgoCD und Cosign sichern
GitOps-Pipelines für Kubernetes absichern: Image Signing mit Cosign, Policy Enforcement mit OPA Gatekeeper und Drift Detection in ArgoCD einrichten.
ArgoCD ApplicationSets: Multi-App Deployment Patterns
ArgoCD ApplicationSets automatisieren Multi-App und Multi-Cluster Deployments mit Generatoren. Praxis-Patterns für Git, Cluster und Matrix.
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 Repository-Struktur: Best Practices
Die richtige Repository-Struktur entscheidet über den Erfolg von GitOps. Mono-Repo vs. Multi-Repo, Verzeichnisaufbau und Environment-Promotion praxisnah erklärt.