TL;DR — Kurzzusammenfassung
SOPS verschlüsselt Werte in YAML/JSON und lässt Schlüssel lesbar. Anleitung: age, KMS, Schlüsselrotation, CI/CD, Kubernetes und ArgoCD GitOps-Integration.
Mozilla SOPS (Secrets OPerationS) löst eines der schwierigsten Probleme von GitOps: Wie man Secrets in der Versionskontrolle speichert, ohne sie preiszugeben. Im Gegensatz zu Tools, die ganze Dateien verschlüsseln, verschlüsselt SOPS nur die Werte in YAML-, JSON-, ENV- und INI-Dateien — Schlüssel bleiben im Klartext, damit Diffs lesbar bleiben.
Warum SOPS? Das Secrets-in-Git-Problem
Plaintext-Secrets in Git zu committen ist ein Sicherheitsvorfall in Wartestellung:
- Nur Umgebungsvariablen — Funktioniert zur Laufzeit, versioniert aber keine Secret-Änderungen.
- Vault / External Secrets — Leistungsstark, benötigt aber Infrastruktur und Online-Zugang.
- git-crypt — Verschlüsselt ganze Dateien; Diffs werden zu unlesbaren Binär-Blobs.
- SOPS — Verschlüsselt nur Werte. Schlüssel bleiben im Klartext. Dateien sind normal vergleichbar.
Eine mit SOPS verschlüsselte Datei sieht so aus:
database:
password: ENC[AES256_GCM,data:abc123...,iv:...,tag:...,type:str]
host: db.example.com # ← unverschlüsselt, kein Secret
Installation
# macOS
brew install sops age
# Ubuntu/Debian
apt install age
wget https://github.com/getsops/sops/releases/latest/download/sops-v3.x.x.linux.amd64 \
-O /usr/local/bin/sops && chmod +x /usr/local/bin/sops
Verschlüsselungs-Backends
| Backend | Am besten für | Infrastruktur |
|---|---|---|
| age | Einfacher moderner Standard | Keine |
| PGP/GPG | Legacy, weit verbreitet | GPG-Keyring |
| AWS KMS | Native AWS-Teams | AWS-Konto + IAM |
| GCP KMS | Native GCP-Teams | GCP-Projekt |
| Azure Key Vault | Azure/Microsoft-Umgebungen | Azure-Abonnement |
| HashiCorp Vault | Multi-Cloud, On-Prem | Vault-Cluster |
Für neue Projekte ist age der empfohlene Standard.
age: Detaillierte Betrachtung
# Schlüsselpaar generieren
age-keygen -o ~/.config/sops/age/keys.txt
# Public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Umgebungsvariable setzen
export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
# Korrekte Berechtigungen (SOPS lehnt für andere lesbare Dateien ab)
chmod 600 ~/.config/sops/age/keys.txt
age unterstützt auch SSH-Schlüssel als Empfänger, nützlich wenn Ihr Team bereits SSH-Schlüssel hat.
.sops.yaml Konfiguration
creation_rules:
- path_regex: secrets/.*\.yaml$
age: >-
age1alice1111111111111111111111111111111111111111111111111111111,
age1bob2222222222222222222222222222222222222222222222222222222222
- path_regex: k8s/.*secret.*\.yaml$
kms: "arn:aws:kms:us-east-1:123456789:key/mrk-abc123"
Schlüsselgruppen und Shamir-Schwellenwert um M von N Parteien zur Entschlüsselung zu erfordern:
creation_rules:
- path_regex: critical/.*
key_groups:
- age:
- age1alice...
- age1bob...
- kms:
- arn: "arn:aws:kms:us-east-1:123456789:key/mrk-abc123"
shamir_threshold: 2
Dateien Verschlüsseln und Bearbeiten
# In neue Datei verschlüsseln
sops --encrypt secrets.yaml > secrets.enc.yaml
# Im Editor öffnen (entschlüsselt, bearbeiten, beim Speichern neu verschlüsseln)
sops secrets.enc.yaml
# Zu stdout entschlüsseln
sops --decrypt secrets.enc.yaml
# Als Umgebungsvariablen injizieren
sops exec-env secrets.enc.yaml 'docker-compose up'
Schlüsselrotation
# 1. Neuen Schlüssel hinzufügen, alten aus .sops.yaml entfernen
# 2. Betroffene Dateien neu verschlüsseln
sops updatekeys --yes secrets/db.yaml
# 3. Prüfen, dass alter Schlüssel nicht mehr funktioniert
SOPS_AGE_KEY="alter_privater_schlüssel" sops --decrypt secrets/db.yaml
# Muss fehlschlagen: "could not decrypt data key"
CI/CD- und Kubernetes-Integration
GitHub Actions:
- name: Secrets entschlüsseln
env:
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
run: sops --decrypt k8s/secrets.enc.yaml | kubectl apply -f -
Kubernetes-Workflow:
kubectl create secret generic db-creds \
--from-literal=password=supersecret \
--dry-run=client -o yaml > k8s/db-secret.yaml
sops --encrypt --in-place k8s/db-secret.yaml
git add k8s/db-secret.yaml && git commit -m "Verschlüsseltes DB-Secret hinzufügen"
KSOPS für ArgoCD und der native Flux-Provider ermöglichen automatische Entschlüsselung beim Deploy.
SOPS vs. Alternativen
| Tool | Verschlüsselt | Diffbar | Infra Benötigt | GitOps |
|---|---|---|---|---|
| SOPS | Nur Werte | Ja | Optional (age) | Ausgezeichnet |
| Sealed Secrets | Ganzes k8s Secret | Nein | Controller | Nur Kubernetes |
| External Secrets | Werte zur Laufzeit | N/A | Vault/KMS | Ja, nur online |
| git-crypt | Ganze Dateien | Nein | GPG-Keyring | Begrenzt |
| BlackBox | Ganze Dateien | Nein | PGP-Keyring | Begrenzt |
Fallstricke und Sonderfälle
- Private Key niemals committen — Nur der Public Key gehört in
.sops.yaml. .sops.yamlmuss im Repository-Stammverzeichnis liegen — Oder--config pfad/.sops.yamlangeben.- Berechtigungen der age-Schlüsseldatei — SOPS lehnt eine für andere lesbare keys.txt ab.
chmod 600verwenden. - Shamir-Schwellenwert muss erfüllt sein — Bei
shamir_threshold: 2und nicht verfügbarem KMS braucht man 2 age-Schlüsselinhaber gleichzeitig.
Zusammenfassung
- SOPS verschlüsselt Werte, nicht Schlüssel — Dateien bleiben in Git vergleichbar und auditierbar.
- age ist der moderne Standard — Keine Infrastruktur, funktioniert offline, unterstützt mehrere Empfänger.
.sops.yamlcreation_rules — Pfadmuster auf Verschlüsselungsschlüssel mit Gruppen und Shamir-Schwellenwert zuordnen.- Nativer Kubernetes-Support — KSOPS für ArgoCD, nativer Provider für Flux.