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

BackendAm besten fürInfrastruktur
ageEinfacher moderner StandardKeine
PGP/GPGLegacy, weit verbreitetGPG-Keyring
AWS KMSNative AWS-TeamsAWS-Konto + IAM
GCP KMSNative GCP-TeamsGCP-Projekt
Azure Key VaultAzure/Microsoft-UmgebungenAzure-Abonnement
HashiCorp VaultMulti-Cloud, On-PremVault-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

ToolVerschlüsseltDiffbarInfra BenötigtGitOps
SOPSNur WerteJaOptional (age)Ausgezeichnet
Sealed SecretsGanzes k8s SecretNeinControllerNur Kubernetes
External SecretsWerte zur LaufzeitN/AVault/KMSJa, nur online
git-cryptGanze DateienNeinGPG-KeyringBegrenzt
BlackBoxGanze DateienNeinPGP-KeyringBegrenzt

Fallstricke und Sonderfälle

  • Private Key niemals committen — Nur der Public Key gehört in .sops.yaml.
  • .sops.yaml muss im Repository-Stammverzeichnis liegen — Oder --config pfad/.sops.yaml angeben.
  • Berechtigungen der age-Schlüsseldatei — SOPS lehnt eine für andere lesbare keys.txt ab. chmod 600 verwenden.
  • Shamir-Schwellenwert muss erfüllt sein — Bei shamir_threshold: 2 und 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.yaml creation_rules — Pfadmuster auf Verschlüsselungsschlüssel mit Gruppen und Shamir-Schwellenwert zuordnen.
  • Nativer Kubernetes-Support — KSOPS für ArgoCD, nativer Provider für Flux.

Verwandte Artikel