`ssmenv-cli`: kleine CLIs für große Ordnung
Eine kleine CLI über AWS SSM zeigt, wie wenig Werkzeug reicht, um Konfiguration zur einzigen Quelle zu machen und Teamabläufe robuster zu machen.
Eine kleine CLI über AWS SSM zeigt, wie wenig Werkzeug reicht, um Konfiguration zur einzigen Quelle zu machen – und damit Teamabläufe deutlich robuster.
Warum ich das aufschreibe
Jedes Team, das ich begleite, hat irgendwann dasselbe stille Problem: Konfiguration lebt an fünf Orten gleichzeitig. Ein .env auf dem Laptop, ein anderes im CI, ein drittes im Onboarding-Wiki, ein viertes als Screenshot in einem Chat und ein fünftes „nur bei mir lokal". Niemand weiß mehr, welcher Wert führend ist. Genau an dieser Stelle entstehen die Bugs, die man nicht reproduzieren kann, und die Onboarding-Tage, die man nicht zurückbekommt.
ssmenv-cli ist meine Antwort darauf – aber die eigentliche Aussage ist nicht das Tool, sondern die Entscheidung dahinter: Konfiguration bekommt eine einzige, zentrale, zugriffskontrollierte Quelle, und das Werkzeug bleibt bewusst dünn. Ich schreibe das auf, weil an diesem kleinen Beispiel eine größere Architekturhaltung sichtbar wird, die ich in fast jedem Projekt wiederverwende.
Das Problem hinter dem Werkzeug
Das klassische Muster ist der geteilte .env-Zettel. Er funktioniert am ersten Tag und zerfällt danach langsam. Die typischen Symptome kenne ich auswendig: Ein Secret liegt versehentlich im Git-Verlauf. Ein neuer Kollege bekommt eine veraltete Kopie und verliert einen halben Tag mit „bei mir läuft es nicht". Ein Wert wird in Produktion geändert, aber nirgends nachvollziehbar dokumentiert. Und niemand kann auf Anhieb sagen, wer eigentlich das Recht hat, ein Produktions-Secret zu lesen.
Das ist im Kern kein Tooling-Problem, sondern ein Grenzproblem. Es fehlt eine klare Antwort auf drei Fragen: Welche Daten sind führend? Wer darf sie lesen und ändern? Wo wird eine Änderung nachvollziehbar? Solange diese Grenzen unscharf bleiben, hilft auch das schönste Skript nicht. Deshalb fange ich nie beim Tool an, sondern bei genau diesen drei Fragen.
Die Entscheidung: SSM als einzige Quelle
Die tragende Entscheidung lautet: Der AWS Systems Manager Parameter Store wird zur einzigen Quelle für Konfiguration und Secrets. Nicht Git, nicht der Laptop, nicht der Chat – ein hierarchischer Namensraum in AWS, der ohnehin schon da ist, wenn man dort deployt.
Das ist eine bewusste Wahl gegen ein eigenes System und gegen ein großes zusätzliches Produkt. Der Parameter Store bringt genau das mit, was ich für diese Grenze brauche: eine Hierarchie über Pfade wie /myapp/prod/DATABASE_URL, Verschlüsselung sensibler Werte über KMS als SecureString, Zugriffskontrolle über IAM und eine lückenlose Aufzeichnung über CloudTrail. Damit sind die drei offenen Fragen von oben beantwortet, ohne dass ich eine einzige Zeile Infrastruktur selbst betreibe.
Was jetzt noch fehlt, ist nur die letzte Meile: der Weg vom Parameter Store in die Umgebungsvariablen eines Prozesses. Genau das – und nichts mehr – ist die Aufgabe der CLI.
Architektur: ein dünner Adapter, keine Plattform
Die wichtigste Architekturentscheidung an ssmenv-cli ist, was das Tool bewusst nicht tut. Es speichert nichts, es entscheidet über keine Rechte, es hält keinen Zustand. Es ist ein dünner Adapter zwischen einer führenden Datenquelle und dem 12-Factor-Prinzip „config in the environment".
Diese Trennung ist die eigentliche Grenze. Der Parameter Store ist der Wahrheitsspeicher. IAM ist die Berechtigungsgrenze. KMS ist die Vertraulichkeitsgrenze. Die CLI ist reine Übersetzung: Sie liest einen Pfad-Präfix, löst SecureString-Werte auf und stellt sie einem Prozess als Umgebung bereit. Weil das Tool selbst keine Autorität hat, kann ich es jederzeit austauschen, ohne dass sich am Sicherheits- oder Datenmodell irgendetwas ändert. Das ist der Wert einer sauber gezogenen Grenze: Sie macht das Werkzeug ersetzbar.
Kleines Beispiel
Der praktische Kern passt in wenige Zeilen. Werte setzt man einmal – idealerweise über Automatisierung, hier zur Anschauung von Hand:
# Store a secret as an encrypted SecureString under a namespaced path
ssmenv set --path /myapp/prod DATABASE_URL "postgres://db.internal:5432/app"
# List everything under a prefix (values masked by default)
ssmenv list --path /myapp/prod
Der eigentliche Gewinn zeigt sich beim Laden. Statt eine Datei zu verteilen, löst man die Umgebung zur Laufzeit auf:
# Run a process with the resolved environment, nothing written to disk
ssmenv exec --path /myapp/prod -- node server.js
# Or export into the current shell for a quick local session
eval "$(ssmenv export --path /myapp/staging)"
Und weil zwei Umgebungen selten identisch sind, ist der Vergleich ein erstklassiges Feature und keine Nebensache:
# Show which keys differ between staging and prod
ssmenv diff --path /myapp/staging --path /myapp/prod
Das Beispiel ist bewusst klein. Es simuliert keine vollständige Plattform, sondern zeigt die Grenze: Die CLI berührt nur die letzte Meile zwischen Speicher und Prozess. Ein gutes Beispiel ist nicht das mit den meisten Optionen, sondern das, bei dem man die Entscheidung nach fünf Minuten diskutieren kann.
Skizze
flowchart LR Store["SSM Parameter Store<br/>/myapp/prod/*"] --> CLI["ssmenv-cli<br/>thin adapter"] IAM["IAM<br/>permission boundary"] --> CLI KMS["KMS<br/>SecureString decrypt"] --> CLI CLI --> Env["process env"] Env --> App["node server.js"]
Die Skizze macht die Verantwortlichkeiten sichtbar: Der Store hält die Wahrheit, IAM und KMS ziehen die Grenzen, die CLI übersetzt. Kein Kasten in diesem Bild ist auf einen Toolnamen angewiesen – das ist Absicht.
Trade-offs: warum klein, warum nicht mehr
Die naheliegende Gegenfrage lautet: Warum nicht gleich ein vollwertiges Secret-Management-Produkt? Die ehrliche Antwort ist ein Trade-off, kein Dogma. Ein großes System bringt Rotation, dynamische Credentials und feingranulare Policies mit – und dazu Betrieb, Lernkurve und eine weitere Abhängigkeit. Für viele Teams, die ohnehin auf AWS deployen, ist das mehr Maschine, als das Problem verlangt.
Meine Regel: Ich baue die kleinste Lösung, die die drei Grenzfragen sauber beantwortet, und lasse Raum für den Wechsel. Weil ssmenv-cli nur ein Adapter ist, ist dieser Wechsel billig. Wenn ein Team später Rotation im großen Stil braucht, tausche ich den Backend-Speicher aus, nicht das mentale Modell. Die teure Entscheidung – Konfiguration ist zentral, zugriffskontrolliert und auditierbar – bleibt dieselbe. Genau so sollte ein Trade-off aussehen: klein anfangen, ohne sich den Ausbau zu verbauen.
Der zweite Trade-off betrifft Netzabhängigkeit. Werte zur Laufzeit aus dem Store zu lösen heißt, dass ein Prozessstart eine AWS-Erreichbarkeit voraussetzt. Das ist bewusst gewählt: Ich tausche einen kurzen Netzaufruf beim Start gegen die dauerhafte Gefahr veralteter lokaler Kopien. Für lokale Offline-Arbeit gibt es weiterhin einen expliziten Export – aber als sichtbare Ausnahme, nicht als stiller Normalfall.
Betriebliche Konsequenz
Die Konsequenz einer Architektur zeigt sich nicht in der Demo, sondern bei Fehlern, Last, Rollback und Review. Hier trägt das Modell, weil die schweren Aufgaben dort liegen, wo sie hingehören.
Zugriff ist eine IAM-Frage. Wer /myapp/prod/* lesen darf, steht in einer Policy und nicht in einem Chatverlauf – und lässt sich damit prüfen und entziehen. Vertraulichkeit ist eine KMS-Frage: Sensible Werte liegen als SecureString verschlüsselt, und die CLI entschlüsselt nur, wenn der Aufrufer das Recht dazu hat. Nachvollziehbarkeit ist eine CloudTrail-Frage: Jeder Lese- und Schreibzugriff ist aufgezeichnet. Wenn jemand fragt „wer hat dieses Secret wann gelesen?", gibt es eine Antwort statt eines Schulterzuckens.
Rückbaubarkeit ist der stärkste Punkt. Weil der Parameter Store Versionen hält, ist ein fehlerhaft gesetzter Wert kein Notfall, sondern ein Rollback auf die vorige Version. Eine Änderung an Konfiguration wird damit so behandelbar wie eine Änderung an Code.
Fehlerfälle
Eine Idee ist erst belastbar, wenn der Fehlerpfad beschrieben ist. Drei Fälle prüfe ich immer.
Fehlende Berechtigung: Wenn der Aufrufer den Pfad nicht lesen darf, muss die CLI hart und deutlich abbrechen. Ein leerer Wert, der stillschweigend als leerer String durchrutscht, ist der gefährlichste Bug – die Anwendung startet mit halber Konfiguration und fällt erst tief im Betrieb um. Ein exec muss deshalb bei fehlenden oder unlesbaren Schlüsseln scheitern, bevor der Zielprozess überhaupt startet.
Teilweise aufgelöste Umgebung: Wenn von zehn erwarteten Schlüsseln nur neun da sind, ist das kein „fast richtig", sondern falsch. Ich behandle das als Fehler mit klarer Meldung, welcher Schlüssel fehlt.
Netz- und Regionsfehler: Ein nicht erreichbarer Store oder eine falsche Region darf keine kryptische SDK-Ausnahme durchreichen, sondern eine Meldung, die den Pfad und die Ursache benennt. Der Unterschied zwischen Demo und Betrieb liegt fast immer in genau diesen unaufgeregten Fehlermeldungen.
Dieselbe Grenze im CI
Der wahre Test einer Konfigurationsgrenze ist die Pipeline. Im CI läuft kein Mensch mit persönlichen Rechten, sondern eine Rolle – und genau das macht das Modell sauber. Statt Secrets als CI-Variablen zu duplizieren, bekommt der Build-Job eine IAM-Rolle, die exakt den Pfad lesen darf, den er braucht, und keinen anderen. Ein Staging-Deploy sieht /myapp/staging/*, ein Produktions-Deploy /myapp/prod/*, und die Trennung ist keine Konvention, sondern eine Berechtigung.
# In CI: the job's role grants read on /myapp/staging/* only
ssmenv exec --path /myapp/staging -- npm run deploy
Damit verschwindet die Klasse der „Secret liegt jetzt auch im CI"-Kopien. Es gibt keine zweite Quelle, die veralten kann, und das Prinzip der geringsten Rechte gilt für Maschinen genauso wie für Menschen. Wenn ein CI-Token kompromittiert wird, ist der Schaden auf genau den Pfad begrenzt, den dieser Job lesen durfte – nachlesbar in CloudTrail, entziehbar in einer Policy. Dass lokal, im CI und in Produktion buchstäblich derselbe Befehl mit einem anderen Pfad läuft, ist der Kern der Reproduzierbarkeit.
Business-Outcome: kürzere Zyklen, weniger Reibung
Der Nutzen ist messbar, auch wenn das Werkzeug klein ist. Onboarding, das früher „hol dir das aktuelle .env von irgendwem" hieß, wird zu einem einzigen Befehl gegen einen Pfad – aus einem halben Tag Reibung werden Minuten. Die ganze Klasse „bei mir läuft es, bei dir nicht"-Fehler verschwindet, weil dev, CI und Produktion dieselbe führende Quelle nutzen und sich nur im Pfad-Präfix unterscheiden. Und das Risiko, ein Secret im Git-Verlauf zu hinterlassen, sinkt strukturell, weil es keinen Grund mehr gibt, Secrets in Dateien abzulegen, die versioniert werden.
Das sind die drei Hebel, die für technische Entscheider zählen: kürzere Zyklen beim Aufsetzen und Wechseln von Umgebungen, weniger Reibung im Alltag und höhere Qualität durch reproduzierbare Konfiguration. Der Gewinn steckt nicht im Toolnamen, sondern in der Entscheidung, Konfiguration wie ein prüfbares Datensystem zu behandeln.
Das Muster für kleine CLIs
ssmenv-cli ist ein Beispiel für eine Haltung, die ich verallgemeinere. Ich beschreibe solche Themen in drei Schichten: fachliche Absicht, technische Grenze und betriebliche Konsequenz. Die Absicht erklärt, warum das System existiert – hier: eine einzige Quelle für Konfiguration. Die Grenze entscheidet, was unabhängig geändert werden kann – hier: der Adapter ist ersetzbar, das Datenmodell nicht. Die Konsequenz zeigt sich bei Fehlern, Last, Rollback und Review.
Der häufigste Fehler ist, das Werkzeug mit der Lösung zu verwechseln. Eine CLI ist keine Architektur. Der Parameter Store ist kein Konfigurationskonzept. Diese Bausteine können eine gute Grenze ausdrücken, aber sie erzeugen sie nicht von selbst. Die Grenze entsteht durch die Entscheidung, wer welche Daten führen darf – und die trifft ein Mensch, kein Tool.
Deshalb baue ich lieber viele kleine, scharf umrissene CLIs als ein großes, unscharfes Framework. Jede erledigt eine Aufgabe, hat eine sichtbare Grenze und mindestens einen ehrlichen Fehlerfall. Dieselbe Denkweise steckt hinter Werkzeugen wie ContentKit oder SlideKit: klein im Umfang, klar in der Verantwortung, ersetzbar im Detail. Große Ordnung entsteht nicht aus großen Werkzeugen, sondern aus vielen kleinen mit sauberen Kanten.
Schluss
Der Beitrag ist dann stark, wenn er nicht nur erklärt, wie ssmenv-cli funktioniert, sondern warum die Grenze so gezogen wurde: Konfiguration zentral und auditierbar, das Werkzeug bewusst dünn und austauschbar. Genau dort entsteht der Nutzen für Entwickler, Architekten und technische Entscheider – nicht im Toolnamen, sondern in der wiederverwendbaren Entscheidung, die man morgen im Teamgespräch weiterverwenden kann.
Weiterführende Quellen
- Repository ssmenv-cli: https://github.com/MikeBild/ssmenv-cli
Die Quelle hilft beim Gegenprüfen der konkreten Umsetzung. Die eigentliche Aussage bleibt die Architekturentscheidung im konkreten Beispiel.
Kommentare