Secrets Management verständlich erklärt – von .env-Dateien über SOPS und age bis HashiCorp Vault

Passwörter, API-Keys, Datenbank-Zugänge, Tokens: Jedes Projekt sammelt mit der Zeit eine ganze Reihe von Geheimnissen an. Und fast genauso schnell landen diese irgendwo, wo sie nicht hingehören – in einer .env-Datei im Repo, im Chatverlauf oder im Klartext auf dem Server. Secrets Management beschäftigt sich genau mit der Frage, wie man solche Geheimnisse sicher speichert, verteilt und verwaltet.

In diesem Artikel schauen wir uns an, warum .env-Dateien gefährlich sein können, worin sich Passwörter und API-Keys unterscheiden und wie Werkzeuge wie Docker Secrets, SOPS, age und HashiCorp Vault helfen, Geheimnisse sauber zu handhaben.

Zum Thema Sicherheit im weiteren Sinne passt auch der Beitrag Backups richtig machen.

Was ist Secrets Management?

Secrets Management bezeichnet den geordneten Umgang mit allen sensiblen Zugangsdaten einer Anwendung oder Infrastruktur. Dazu gehören:

  • Passwörter und Datenbank-Zugänge
  • API-Keys und Tokens
  • Zertifikate und private Schlüssel
  • Verschlüsselungsschlüssel

Das Ziel ist immer dasselbe: Geheimnisse sollen nur dort verfügbar sein, wo sie wirklich gebraucht werden, möglichst kurzlebig sein und niemals ungeschützt herumliegen. Klingt einfach, wird im Alltag aber überraschend oft falsch gemacht.

Warum .env-Dateien gefährlich sein können

Die .env-Datei ist der Klassiker: schnell angelegt, bequem eingebunden, und alle Geheimnisse liegen an einem Ort. Genau das ist aber das Problem.

1. Sie landen im Repository

Der häufigste Fehler: Die .env wird versehentlich committet. Einmal in der Git-Historie, bleibt das Geheimnis dort auch nach dem Löschen erhalten. Ein vergessener Eintrag in .gitignore reicht, um Zugangsdaten dauerhaft offenzulegen.

2. Sie liegen im Klartext

.env-Dateien sind unverschlüsselt. Wer Zugriff auf das Dateisystem, ein Backup oder einen kompromittierten Container bekommt, liest alle Geheimnisse sofort im Klartext.

3. Sie werden weitergereicht

.env-Dateien wandern gern per Chat, E-Mail oder USB-Stick von Person zu Person. Jede dieser Kopien ist ein unkontrollierter Aufbewahrungsort für Geheimnisse.

4. Sie kennen keine Rechte und keine Historie

Eine .env weiß nicht, wer welchen Wert wann gesehen oder geändert hat. Es gibt keine Zugriffskontrolle, kein Audit-Log und keine einfache Möglichkeit, ein einzelnes Geheimnis gezielt zu rotieren.

.env-Dateien sind für die lokale Entwicklung in Ordnung, solange sie konsequent aus der Versionskontrolle herausgehalten werden. Für Produktivumgebungen sind sie aber die schwächste Lösung.

Passwörter vs. API-Keys

Beide sind Geheimnisse, werden aber oft in einen Topf geworfen, obwohl sie unterschiedlich behandelt werden sollten.

Passwörter

Ein Passwort ist meist einem Menschen zugeordnet und dient der Anmeldung. Es ist in der Regel langlebig, sollte aber durch zusätzliche Maßnahmen wie Multi-Faktor-Authentifizierung abgesichert werden. Passwörter gehören idealerweise in einen Passwortmanager, nicht in Konfigurationsdateien – für Selbsthoster zum Beispiel Vaultwarden.

API-Keys

Ein API-Key identifiziert eine Anwendung oder einen Dienst, nicht eine Person. Er wird automatisiert verwendet und sollte deshalb:

  • möglichst eng in den Rechten begrenzt sein (nur das, was nötig ist)
  • regelmäßig rotiert werden können
  • pro Dienst und Umgebung getrennt sein
  • jederzeit einzeln widerrufbar sein

Der wichtigste Unterschied im Alltag: Ein API-Key ist dafür gemacht, automatisiert und in großer Zahl verwendet zu werden. Genau deshalb braucht er ein System, das Rotation und Widerruf einfach macht – ein Passwort im Kopf eines Menschen funktioniert hier nicht.

Docker Secrets

Wer mit Containern arbeitet, steht schnell vor der Frage, wie Geheimnisse in den Container kommen. Die naheliegende, aber schlechte Lösung sind Umgebungsvariablen direkt im docker run oder im Compose-File, denn sie sind über docker inspect und die Prozessumgebung auslesbar und landen erfahrungsgemäß auch gern in Logs.

Docker Secrets lösen das sauberer. Ein Secret wird nicht als Umgebungsvariable übergeben, sondern als Datei in einem speziellen, nur im Arbeitsspeicher gehaltenen Bereich bereitgestellt:

1
echo "supergeheim" | docker secret create db_password -

Im Swarm-Modus erscheint das Secret dann unter /run/secrets/ im Container:

1
cat /run/secrets/db_password

Die Vorteile:

  • Das Geheimnis steht nicht in Umgebungsvariablen.
  • Es taucht nicht in docker inspect auf.
  • Es wird nur den Diensten zugänglich gemacht, die es ausdrücklich brauchen.

Voraussetzung dafür ist ein initialisierter Swarm (docker swarm init). Wer ohne Cluster arbeitet, muss auf das Prinzip aber nicht verzichten: Auch Docker Compose ohne Swarm kennt secrets auf oberster Ebene und bindet die Datei ebenfalls unter /run/secrets/ im Container ein:

1
2
3
4
5
6
7
8
services:
app:
image: beispiel:latest
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt

Wichtig bleibt dabei, dass die Quelldatei auf dem Host selbst geschützt ist – mit restriktiven Dateirechten, außerhalb des Repositories oder verschlüsselt abgelegt und erst beim Deployment entschlüsselt, etwa über SOPS.

Wer statt Swarm mit Kubernetes arbeitet, sollte einen häufigen Irrtum kennen: Kubernetes Secrets sind von Haus aus nur Base64-kodiert, nicht verschlüsselt. Wer die YAML-Datei oder den etcd-Speicher auslesen kann, hat die Geheimnisse im Klartext. Echte Absicherung braucht dort zusätzliche Bausteine wie Encryption at Rest oder einen externen Secret-Store.

Docker Secrets sind ein guter Schritt für containerbasierte Setups – decken aber vor allem die Verteilung ab, nicht die verschlüsselte Aufbewahrung im Git-Repository. Dafür gibt es passendere Werkzeuge.

age – moderne, einfache Verschlüsselung

age ist ein modernes Verschlüsselungswerkzeug mit dem Ziel, einfach und ohne Konfigurationsdschungel zu funktionieren. Es ersetzt im Alltag oft die deutlich komplexere GPG-Nutzung.

Ein Schlüsselpaar erzeugt man mit:

1
age-keygen -o key.txt

Eine Datei verschlüsselt man an einen öffentlichen Schlüssel:

1
age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p -o secret.txt.age secret.txt

Und entschlüsselt sie mit dem privaten Schlüssel wieder:

1
age -d -i key.txt -o secret.txt secret.txt.age

age ist bewusst minimalistisch: ein Schlüsseltyp, klare Befehle, keine endlosen Optionen. Genau das macht es zu einem idealen Baustein für andere Werkzeuge – allen voran SOPS.

SOPS – Secrets verschlüsselt im Git verwalten

SOPS (Secrets OPerationS) löst ein konkretes Alltagsproblem: Man möchte Konfigurations- und Secret-Dateien im Git-Repository versionieren, aber natürlich nicht im Klartext.

Der Trick von SOPS: Es verschlüsselt nur die Werte, nicht die Struktur. Eine YAML- oder JSON-Datei bleibt also lesbar, nur die geheimen Inhalte sind verschlüsselt. Das macht Diffs und Reviews weiterhin sinnvoll.

SOPS lässt sich hervorragend mit age kombinieren. Eine Datei verschlüsselt man etwa so:

1
sops --encrypt --age age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p secrets.yaml > secrets.enc.yaml

Zum Bearbeiten öffnet SOPS die Datei entschlüsselt im Editor und verschlüsselt sie beim Speichern automatisch wieder:

1
sops secrets.enc.yaml

Die Stärken von SOPS:

  • Geheimnisse können verschlüsselt im Repo liegen.
  • Nur die Werte sind verschlüsselt, die Struktur bleibt lesbar.
  • Mehrere Empfänger (Personen oder Maschinen) können Zugriff erhalten.
  • Es funktioniert mit age, GPG und Cloud-KMS-Diensten.

Für viele kleine und mittlere Projekte ist die Kombination aus SOPS und age der ideale Mittelweg: sicher, nachvollziehbar und ohne große Infrastruktur.

HashiCorp Vault – der Einstieg

Wenn Projekte und Teams wachsen, stößt das dateibasierte Vorgehen an Grenzen. Hier kommt HashiCorp Vault ins Spiel – ein dedizierter Dienst zentral für die Verwaltung von Geheimnissen.

Vault speichert Geheimnisse nicht in Dateien, sondern in einem zentralen, abgesicherten Dienst, der über eine API angesprochen wird. Das bringt einige Konzepte mit:

Zentrale Verwaltung

Alle Geheimnisse liegen an einem Ort, mit klarer Zugriffskontrolle und vollständigem Audit-Log. Man sieht also, wer wann welches Geheimnis abgerufen hat.

Dynamische Secrets

Vault kann Geheimnisse bei Bedarf erzeugen, etwa kurzlebige Datenbank-Zugänge, die nach kurzer Zeit automatisch wieder verfallen. Statt eines dauerhaften Passworts gibt es ein Geheimnis nur für genau den Moment, in dem es gebraucht wird.

Sealing und Unsealing

Im Ruhezustand ist Vault „versiegelt”: Selbst wer Zugriff auf den Speicher bekommt, kann ohne den Entsiegelungsprozess nichts auslesen. Erst beim Start wird Vault kontrolliert entsiegelt.

Ein einfacher Einstieg gelingt mit dem Entwicklungsmodus, der nur zum Ausprobieren gedacht ist:

1
vault server -dev

Der Dev-Server läuft ohne TLS, die Vault-CLI muss die Adresse daher explizit kennen:

1
export VAULT_ADDR='http://127.0.0.1:8200'

Danach lässt sich ein Geheimnis ablegen und wieder auslesen:

1
2
vault kv put secret/myapp db_password=supergeheim
vault kv get secret/myapp

Wichtig: Der Dev-Modus hält alles im Arbeitsspeicher und ist völlig ungesichert. Er eignet sich zum Lernen, niemals für den Produktivbetrieb. Eine echte Vault-Installation erfordert sorgfältige Planung rund um Speicher, Entsiegelung und Zugriffsrichtlinien.

Eine Anmerkung zur Lizenz: HashiCorp hat Vault im August 2023 auf die Business Source License umgestellt – es ist seither kein Open Source im strengen Sinn mehr. Wer eine freie Alternative sucht, findet mit OpenBao einen Fork der Linux Foundation, der API-kompatibel zu Vault bleibt und sich in Kommandos und Konzepten kaum unterscheidet. Als moderne Alternative ohne Vault-Kompatibilität ist außerdem Infisical einen Blick wert.

Vault ist mächtig, aber auch komplex. Für kleine Projekte ist es oft überdimensioniert. Sobald jedoch viele Dienste, Teams und automatisierte Zugriffe zusammenkommen, spielt es seine Stärken aus.

Und wenn ein Secret doch im Git gelandet ist?

Früher oder später passiert es fast jedem Projekt. Wichtig ist dann die Reihenfolge:

  1. Erst rotieren, dann aufräumen. Das kompromittierte Geheimnis sofort sperren beziehungsweise neu vergeben. Ab dem Moment des Commits gilt es als bekannt – unabhängig davon, ob das Repository öffentlich war oder nicht.
  2. Die Historie bereinigen. Ein normaler git rm-Commit reicht nicht, das Geheimnis bleibt in der Historie lesbar. Werkzeuge wie git filter-repo oder der BFG Repo-Cleaner entfernen Dateien und Zeichenketten rückwirkend aus allen Commits.
  3. Alle Kopien bedenken. Forks, lokale Klone und CI-Caches behalten die alte Historie. Nach dem Force-Push müssen alle Beteiligten neu klonen oder rebasen.

Damit es gar nicht so weit kommt, helfen Scanner, die Commits automatisiert auf Geheimnisse prüfen – etwa gitleaks oder trufflehog als Pre-Commit-Hook oder im CI-Job. GitHub und GitLab bringen mit Secret Scanning beziehungsweise Push Protection außerdem eine eingebaute Erkennung mit, die bekannte Token-Formate schon beim Push ablehnt.

Welches Werkzeug wann?

Die Auswahl hängt vor allem von Größe und Anspruch des Projekts ab:

  • Lokale Entwicklung: .env, konsequent aus Git heraushalten
  • Geheimnisse versioniert im Repo: SOPS in Kombination mit age
  • Container und Orchestrierung: Docker Secrets für die Verteilung
  • Größere Teams und Infrastruktur: HashiCorp Vault als zentraler Dienst

Alle Ansätze münden am Ende in derselben Frage – dem sogenannten Secret-Zero-Problem: Jede Kette endet bei einem letzten Geheimnis, das nicht noch einmal in einem Tresor liegen kann. Bei SOPS ist das der private age-Schlüssel, bei Vault der Root-Token beziehungsweise die Unseal-Schlüsselteile, bei Compose die Quelldatei auf dem Host. Die Antwort darauf ist keine weitere Abstraktion, sondern ein bewusster Umgang mit dieser letzten Stelle: Der Schlüssel liegt offline oder an Hardware gebunden – etwa ein age-Schlüssel auf einem Sicherheitsschlüssel per age-plugin-yubikey –, die Unseal-Anteile sind auf mehrere Personen verteilt, und wer ihn verwaltet, weiß um seine Bedeutung. Ein sichtbar und bewusst gesichertes letztes Geheimnis schlägt ein unsichtbares, das niemand mehr kennt.

In der Praxis werden diese Ansätze oft kombiniert. Entscheidend ist, dass man bewusst auswählt und nicht aus Bequemlichkeit bei der ungeschützten .env bleibt.

Fazit

Secrets Management ist kein optionales Extra, sondern ein fester Bestandteil sauberer Entwicklung. .env-Dateien sind ein praktischer Startpunkt, aber für mehr als die lokale Entwicklung zu schwach. Wer Geheimnisse verschlüsselt versionieren will, ist mit SOPS und age gut bedient. Container profitieren von Docker Secrets, und größere Umgebungen kommen langfristig kaum an einer zentralen Lösung wie Vault vorbei.

Der entscheidende Punkt ist einfach: Geheimnisse gehören nicht ungeschützt in Dateien, Repos oder Chatverläufe. Mit den richtigen Werkzeugen lässt sich der sichere Umgang ohne großen Mehraufwand zur Gewohnheit machen.

Quellen