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.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