· Kubernetes  · 7 Min. Lesezeit

SOPS in GitOps: die vollständige Stolperstein-Sammlung

Elf Fälle, in denen eine SOPS-Einrichtung mit age bricht, quer durch Flux, KSOPS und den sops-secrets-operator. Jeder Fall mit Symptom, Ursache, Prüfbefehl und Lösung, jeder gegen die offizielle Dokumentation belegt.

Elf Fälle, in denen eine SOPS-Einrichtung mit age bricht, quer durch Flux, KSOPS und den sops-secrets-operator. Jeder Fall mit Symptom, Ursache, Prüfbefehl und Lösung, jeder gegen die offizielle Dokumentation belegt.

Eine SOPS-Einrichtung fällt leise aus, an einer Endung im Secret-Namen, an einem Dateinamen mit einem Buchstaben Unterschied, an einem Schlüsselpfad, der auf dem Arbeitsplatz existiert und im Container nicht. Diese Sammlung ist für den Moment gedacht, in dem Sie eine dieser Meldungen vor sich haben und wissen wollen, wo Sie nachsehen müssen.

Die Reihenfolge folgt grob dem Ablauf der Einrichtung, den der Hauptbeitrag Secrets im Git, aber verschlüsselt: SOPS in der Praxis beschreibt. Die Fälle 1 bis 4 betreffen Verschlüsselung und Konfiguration, die Fälle 5 bis 7 die Schlüsselverwaltung und die Ausführungsumgebung, die Fälle 8 bis 11 die Werkzeuge der Kette. Wenn Sie den Ablauf noch nicht kennen, lesen Sie zuerst dort, sonst fehlt hier der Zusammenhang.

1. Die ganze Datei wurde verschlüsselt

Symptom: Ein SOPS-verschlüsseltes Kubernetes-Secret wird von Flux oder kustomize abgelehnt, obwohl die Datei sauber verschlüsselt ist.

Ursache: Es wurde die ganze Datei verschlüsselt statt nur data und stringData. Flux benennt den Klartext von metadata, kind und apiVersion als harte Anforderung.

Prüfung: Die verschlüsselte Datei öffnen und kontrollieren, dass diese drei Felder lesbar sind. Zusätzlich kubectl apply --dry-run=client -f gegen die entschlüsselte Fassung.

Lösung: In .sops.yaml encrypted_regex auf ^(data|stringData)$ setzen und die Datei neu erzeugen.

sops encrypt --encrypted-regex '^(data|stringData)$' -i basic-auth.yaml

2. Der Schlüsselname im Flux-Secret stimmt nicht

Symptom: Flux findet den age-Schlüssel nicht und die Kustomization bleibt im Fehler stehen, obwohl das Secret existiert.

Ursache: Der Datenschlüssel im Secret hat nicht die vorgeschriebene Endung. Der kustomize-controller erkennt age-Identitäten nur an Schlüsseln, die auf .agekey enden, OpenPGP-Keyrings nur an .asc. Für Cloud-KMS und OpenBao gelten feste Namen wie sops.aws-kms, sops.azure-kv, sops.gcp-kms und sops.vault-token.

Prüfung:

kubectl -n flux-system get secret sops-age -o jsonpath='{.data}'

Lösung: Das Secret so anlegen, dass der Datenschlüssel auf .agekey endet.

cat age.agekey | kubectl create secret generic sops-age \
  --namespace=flux-system --from-file=age.agekey=/dev/stdin

3. MAC-Fehler nach einer Handänderung

Symptom: Nach einer Änderung an einem unverschlüsselten Feld schlägt die Entschlüsselung mit einem MAC-Fehler fehl.

Ursache: mac_only_encrypted steht laut SOPS-Referenz standardmäßig auf false. Damit zählen auch unverschlüsselte Werte in die MAC-Berechnung. Jede Änderung am Klartext bricht sie.

Prüfung: sops decrypt auf die Datei anwenden. Läuft sie durch, stimmt die MAC.

sops decrypt --extract '["stringData"]["username"]' basic-auth.yaml

Lösung: Dateien über sops edit oder sops set ändern statt im Texteditor. Alternativ mac_only_encrypted in der creation_rule aktivieren und die Dateien neu erzeugen.

4. Die Konfigurationsdatei heißt .sops.yml

Symptom: SOPS liest die Konfiguration nicht und verschlüsselt mit den falschen Empfängern.

Ursache: Erwartet wird .sops.yaml. Eine Datei namens .sops.yml wird nicht als Konfiguration verwendet.

Prüfung: sops encrypt aufrufen und die Warnmeldung beachten, die seit 3.10.0 bei einer Datei namens .sops.yml erscheint. Danach im Dateikopf kontrollieren, welche age-Empfänger tatsächlich eingetragen sind.

ls -1 .sops.yaml

Lösung: Auf .sops.yaml umbenennen und die betroffenen Dateien mit den richtigen Empfängern neu verschlüsseln.

5. Mehrere Auswahloptionen in einer Regel

Symptom: In .sops.yaml sind mehrere Auswahloptionen gesetzt und SOPS verhält sich anders als erwartet.

Ursache: encrypted_regex, unencrypted_regex, encrypted_suffix, unencrypted_suffix, encrypted_comment_regex und unencrypted_comment_regex schließen sich gegenseitig aus. Pro Regel ist höchstens eine erlaubt.

Prüfung: sops encrypt auf eine Testdatei anwenden und kontrollieren, ob der Befehl mit einem Fehler abbricht statt still etwas anderes zu tun.

Lösung: Genau eine Auswahloption pro creation_rule setzen. Für Kubernetes-Secrets ist das encrypted_regex: ^(data|stringData)$.

6. Der entfernte Schlüssel hat weiter Zugriff

Symptom: Ein ausgeschiedener Mitarbeiter oder ein kompromittierter Schlüssel wurde aus .sops.yaml entfernt, kann aber weiterhin alte Stände entschlüsseln.

Ursache: Das Entfernen eines Master-Schlüssels ändert den Datenschlüssel nicht. Die Dokumentation zur Schlüsselverwaltung sagt das ausdrücklich und empfiehlt deshalb, beim Entfernen den Datenschlüssel zu rotieren, weil die Besitzer des entfernten Schlüssels ihn in der Vergangenheit kennen konnten.

Prüfung: sops updatekeys ohne -y aufrufen und die angezeigte Änderungsliste prüfen. Anschließend im Dateikopf kontrollieren, dass der alte Empfänger verschwunden ist.

Lösung: Erst den Schlüssel per updatekeys entfernen, danach den Datenschlüssel erneuern.

sops updatekeys secret.enc.yaml
sops rotate -i secret.enc.yaml

7. Auf dem Arbeitsplatz läuft es, im Container nicht

Symptom: Lokal entschlüsselt SOPS, in der CI oder im Container nicht.

Ursache: SOPS sucht die age-Identität an betriebssystemabhängigen Standardpfaden, unter Linux in $XDG_CONFIG_HOME/sops/age/keys.txt beziehungsweise $HOME/.config/sops/age/keys.txt. In einem schlanken Container existiert dieses Verzeichnis nicht.

Prüfung:

printenv SOPS_AGE_KEY_FILE
sops decrypt --extract '["stringData"]["username"]' basic-auth.yaml

Lösung: SOPS_AGE_KEY_FILE explizit setzen oder den Schlüssel über SOPS_AGE_KEY beziehungsweise SOPS_AGE_KEY_CMD bereitstellen. Für SSH-Schlüssel gibt es SOPS_AGE_SSH_PRIVATE_KEY_FILE und SOPS_AGE_SSH_PRIVATE_KEY_CMD, allerdings nur für ssh-rsa und ssh-ed25519, und der über die CMD-Variante gelieferte Schlüssel darf nicht passwortgeschützt sein. Ich empfehle stattdessen einen eigenen age-Schlüssel per age-keygen, weil damit die Einschränkungen der SSH-Varianten entfallen.

8. kustomize build ignoriert den KSOPS-Generator

Symptom: Der Build bricht mit einem Plugin-Fehler ab oder das Secret erscheint unverändert.

Ursache: KSOPS läuft als exec-Plugin und braucht beide Alpha-Schalter. Der aktuelle Stand ist v4.5.1 vom 13. April 2026.

Prüfung:

kustomize build --enable-alpha-plugins --enable-exec .

Lösung: Beide Flags dauerhaft in den Aufruf aufnehmen. Wer von einer 3.x-Version kommt, muss zusätzlich die Generator-Manifeste umschreiben. Bis v3.x.x gilt der alte Exec-Plugin-Stil, ab v4 die KRM-exec-Function-Architektur mit der Annotation config.kubernetes.io/function und exec.path: ksops.

Beachten Sie dabei die Bewertung von Argo CD. Die Dokumentation zum Secret Management rät von der Entschlüsselung während der Manifest-Erzeugung ausdrücklich ab, weil die erzeugten Manifeste samt Klartext in der Redis-Instanz landen und über die repo-server-API erreichbar sind.

9. Die CRD fehlt beim Operator

Symptom: Das Ausrollen des sops-secrets-operator schlägt fehl, weil die Ressource SopsSecret unbekannt ist.

Ursache: Die CRD wird in der dokumentierten Reihenfolge vor dem Helm-Chart ausgerollt. Wird der Schritt übersprungen, fehlt der Ressourcentyp.

Prüfung:

kubectl get crd sopssecrets.isindir.github.com
kubectl api-resources | grep -i sopssecret

Lösung: Die Reihenfolge einhalten.

kubectl apply -f config/crd/bases/isindir.github.com_sopssecrets.yaml
helm upgrade --install sops sops/sops-secrets-operator --namespace sops

10. Nach dem Operator-Update zeigt die Image-Referenz auf die alte Registry

Symptom: Nach einem Update auf 0.17.2 oder neuer passen Image-Referenz, Mirror-Regel und Pull-Secret nicht mehr zu der Quelle, aus der das Projekt seine Images veröffentlicht.

Ursache: Release 0.17.2 vom 18. Oktober 2025 hat die Registry gewechselt. Die Release-Note nennt den Wechsel von Docker Hub zu quay.io und AWS ECR sowie die Umstellung auf vollständig qualifizierte Namen der Form Registry, Repository, Image und Tag.

Prüfung:

kubectl -n sops get deploy -o jsonpath='{..image}'
kubectl -n sops get pods

Lösung: Image-Referenzen auf die neuen Registries umstellen und Mirror-Konfiguration sowie Pull-Secrets nachziehen. Kontrollieren Sie dabei, ob Ihre Werte den vollständig qualifizierten Namen verwenden statt eines Kurznamens, der implizit auf Docker Hub auflöst.

11. Auswahloptionen wirken beim Binary-Store nicht

Symptom: Für eine Binärdatei ist in .sops.yaml eine Auswahloption gesetzt, SOPS gibt beim Verschlüsseln eine Warnung dazu aus.

Ursache: Der Binary-Store wertet die Auswahloptionen nicht aus. Die Release-Note zu 3.11.0 führt diese Änderung als “Ignore encryption selection options for binary store (and warn when they are used)”.

Prüfung: Version feststellen und beim Verschlüsseln auf die Warnung achten.

SOPS_DISABLE_VERSION_CHECK=true sops --version

Lösung: Auf mindestens 3.11.0 aktualisieren, damit die Warnung überhaupt erscheint, und die Auswahloption für Binärdateien aus der creation_rule entfernen. Dieselbe Version stellt außerdem sicher, dass die temporäre Datei beim Bearbeiten nur für den Eigentümer les- und schreibbar ist.

Was diese Sammlung nicht abdeckt

Die Fälle hier betreffen die Einrichtung und den Betrieb der Werkzeuge. Sie decken nicht die Frage ab, ob SOPS für Ihren Zweck überhaupt das richtige Werkzeug ist, wo im Ablauf entschlüsselt werden sollte und welche Grenzen das Verfahren selbst hat. Das steht mit Vergleichstabelle und Bedrohungsmodell im Hauptbeitrag Secrets im Git, aber verschlüsselt: SOPS in der Praxis.

Eine Lücke bleibt in beiden Beiträgen offen, weil die offizielle Dokumentation sie offen lässt. Zur Aufbewahrung, Sicherung und Wiederherstellung des privaten age-Schlüssels gibt es dort weder eine Backup-Empfehlung noch ein Rotationsintervall noch ein Verfahren für den Notfallzugriff. Diese Antwort müssen Sie selbst formulieren und aufschreiben, bevor Sie das Verfahren produktiv nutzen. Wie ein Wiederherstellungstest aussieht, der diesen Namen verdient, steht im Beitrag Der Restore-Test, den niemand macht.

Sie wollen Secrets versionieren, ohne sie preiszugeben? Ich richte verschlüsselte Secret-Verwaltung ein, die zu Ihrem GitOps passt, und sorge dafür, dass der Schlüssel dahin gehört, wo er sicher ist. Mehr unter IT-Sicherheit & ISMS, das Erstgespräch ist unverbindlich.

Alex Jabi, Jabi IT

Alex Jabi

Ich betreue IT, Informationssicherheit und Datenschutz für KMU und Praxen an der Bergstraße und im Odenwald, persönlich, dokumentiert und ohne Cloud-Zwang.

Mehr über mich
Zurück zum Blog

Passende Artikel

Alle Artikel »
Secrets im Git, aber verschlüsselt: SOPS in der Praxis

Secrets im Git, aber verschlüsselt: SOPS in der Praxis

GitOps verlangt den kompletten Soll-Zustand in Git. Passwörter und Token gehören da nicht im Klartext hinein. Wie Sie SOPS mit age einrichten, an welcher Stelle im Ablauf entschlüsselt wird, welche Stelle Argo CD ausdrücklich nicht empfiehlt und wo die belegbaren Grenzen des Verfahrens liegen.