Sägetstrasse 18, 3123 Belp, Switzerland +41 79 173 36 84 info@ict.technology

    HashiCorp Vault Deep Dive – Teil 2b: Praktische Arbeit mit der Key/Value Secrets Engine

    Die Key/Value Secrets Engine ist fester Bestandteil nahezu jeder Vault-Implementierung. Sie bildet das Fundament für die sichere Ablage statischer Secrets und wird in der Praxis deutlich häufiger genutzt als viele dynamische Engines.

    Nach der theoretischen Einführung in Teil 2a wenden wir uns in diesem Artikel der konkreten Arbeit mit der KV Engine zu. Wir zeigen, wie sich Secrets schreiben, lesen, aktualisieren und löschen lassen und analysieren praxisnah die Unterschiede zwischen KV Version 1 und Version 2. Der Fokus liegt auf produktionsrelevanten Kommandos, realistischen Fallstricken und konkreten Empfehlungen für den operativen Alltag, weshalb ich Ihnen dieses Wissen als Mischung von Tutorial und Cheat-Sheet mitgebe.

    Das vault kv Kommando: Ihr Werkzeugkasten für den Alltag

    Die Interaktion mit der KV Engine erfolgt über das Kommando vault kv. Dieses Kommando abstrahiert intern die Unterschiede zwischen den Versionen, zeigt aber in der Ausgabe deutlich, ob es sich um eine v1- oder v2-Engine handelt. Die grundlegenden Subkommandos lassen sich in zwei Gruppen einteilen:

    Basis-Operationen (verfügbar in KV v1 und v2):

    • put: Secrets schreiben oder aktualisieren
    • get: Secrets abrufen
    • delete: Secrets löschen (nicht unbedingt final)
    • list: Alle vorhandenen Pfade anzeigen

    Erweiterte Operationen (nur KV v2):

    • patch: Einzelne Schlüssel aktualisieren, ohne andere zu überschreiben
    • rollback: Auf eine bestimmte Version zurücksetzen
    • undelete: Gelöschte Versionen wiederherstellen
    • destroy: Versionen unwiderruflich entfernen

    Diese erweiterten Kommandos stehen nur bei KV v2 zur Verfügung, weil sie auf den intern gespeicherten Metadaten aufbauen. Die alte v1 unterstützt noch keine Metadaten.

    Secrets schreiben mit put: Einfach, aber mit Tücken

    Der Schreibbefehl vault kv put ist die zentrale Methode, um Secrets in die KV Engine zu schreiben:


    vault kv put <pfad> <schlüssel>=<wert> [<schlüssel>=<wert>...]

    Ein einfaches Beispiel, zuerst aktivieren wir die Secrets Engines:


    $ vault secrets enable kv
    Success! Enabled the kv secrets engine at: kv/
    $
    $ vault secrets enable -path=kvv2 kv-v2
    Success! Enabled the kv-v2 secrets engine at: kvv2/

    Der jetzt folgende Befehl speichert das Secret unter dem Pfad kv/app/db mit dem Key pass und dem Wert 123. Die Ausgabe variiert je nach verwendeter Version:

    KV Version 1:


    $ vault kv put kv/app/db pass=123
    Success! Data written to: kv/app/db
    $

    KV Version 2:


    $ vault kv put kvv2/app/db pass=123
    == Secret Path ==
    kvv2/data/app/db
    
    ======= Metadata =======
    Key                Value
    ---                -----
    created_time       2025-07-01T10:52:07.551872783Z
    custom_metadata    <nil>
    deletion_time      n/a
    destroyed          false
    version            1
    $ 

    Die Version 2 liefert Metadaten, wie Erstellungszeitpunkt und aktuelle Version.

    Ein wichtiger Hinweis: Bei KV v2 erfolgt die Speicherung unter einem internen Pfad mit  dem zusätzlichen Prefix /data/. Das ist insbesondere bei direkter API-Nutzung zu beachten, denn das bedeutet, dass Sie nicht einfach von v1 auf v2 migrieren können, ohne ggf. Skripte und Applikationen entsprechend anzupassen!

    Mehrere Key/Value-Paare gleichzeitig speichern

    Ein einzelner put-Befehl kann beliebig viele Schlüssel speichern:


    $ vault kv put kv/app/db pass=123 user=admin api=myapisecret
    Success! Data written to: kv/app/db
    $ vault kv put kvv2/app/db pass=123 user=admin api=myapisecret
    == Secret Path ==
    kvv2/data/app/db
    
    ======= Metadata =======
    Key                Value
    ---                -----
    created_time       2025-07-01T10:56:04.624145825Z
    custom_metadata    <nil>
    deletion_time      n/a
    destroyed          false
    version            2
    [rramge@ol9 terraform-vault-kv]$ 

    In der Praxis spart dies Kommandos, aber vergessen Sie nicht: Der gesamte Inhalt am Pfad wird ersetzt. Im Zweifelsfall machen Sie es besser einzeln, um die Lesbarkeit von Skripten zu erhöhen und die Fehleranfälligkeit zu reduzieren - oder benutzen Sie Files wie im nächsten Abschnitt dargestellt. 

    Secrets aus JSON-Dateien importieren

    Gerade für automatisierte Umgebungen oder umfangreiche Secret-Strukturen empfiehlt sich die Nutzung von Dateien für die Eingabe von mehreren Key/Value-Paaren:


    $ vault kv put kv/app/db @secrets.json

    Beispielinhalt der Datei secrets.json:


    {
      "pass": "123",
      "user": "admin",
      "api": "myapisecret"
    }

    Wichtiger Unterschied zwischen put und patch

    Viele Vault-Nutzer machen früh einen folgenschweren Fehler: Sie verwenden put für Updates einzelner Werte. 

    Das führt bei KV v1 und v2 immer dazu, dass alle bereits vorhandenen Daten des Secrets gelöscht werden, wenn sie nicht im neuen put-Befehl enthalten sind.

    Beispiel:


    # Ausgangszustand
    $ vault kv put kv/app/db pass=123 user=admin api=myoldapisecret
    Success! Data written to: kv/app/db
    $ # Update des API-Keys, versehentlich per "put" $ vault kv put kv/app/db pass=123 user=admin api=myoldapisecret
    Success! Data written to: kv/app/db
    $ # Ergebnis: Nur "api" bleibt erhalten $ vault kv get kv/app/db
    === Data ===
    Key Value
    --- -----
    api mynewapisecret
    $

    Die Schlüssel user und pass sind somit verloren. 

    vault kv put war für den Erhalt der bestehenden Schlüssel user und pass das falsche Kommando. Denn nur patch verhindert deren Löschen. Darauf gehen wir weiter unten ein. Merken Sie sich für jetzt, dass put destruktiv ist:

    Wichtig: Ein vault kv put Befehl ersetzt immer alle Daten am angegebenen Pfad. Es ist kein Merge-Vorgang!

    Secrets lesen mit get: Ein Blick in den Speicher

    Mit vault kv get rufen Sie Secrets ab. Standardmäßig wird immer die aktuellste Version angezeigt.

    Zum Beispiel zeigt dieser Befehl:


    vault kv get kv/app/db

    Bei KV v1:


    $ vault kv get kv/app/db
    ==== Data ====
    Key Value
    --- -----
    api myapisecret
    pass 123
    user admin
    $

    Bei KV v2:


    $ vault kv get kvv2/app/db
    == Secret Path ==
    kvv2/data/app/db
    ======= Metadata =======
    Key Value
    --- -----
    created_time 2025-07-01T10:56:04.624145825Z
    custom_metadata <nil>
    deletion_time n/a
    destroyed false
    version 2
    ==== Data ====
    Key Value
    --- -----
    api myapisecret
    pass 123
    user admin
    $

    Hinweis: Auch hier ist der /data/-Pfad in KV v2 sichtbar. Falls Sie diese Rückgabe in Skripten oder Applikationen parsen, müssen Sie dies im Hinterkopf behalten.

    JSON-Ausgabe für Skripte und Automatisierung

    Mit -format=json erhalten Sie maschinenlesbare Daten:


    $ vault kv get -format=json kv/app/db
    {
      "request_id": "7de43863-d7c4-837f-b59c-4b5e546a1d65",
      "lease_id": "",
      "lease_duration": 2764800,
      "renewable": false,
      "data": {
        "api": "myapisecret",
        "pass": "123",
        "user": "admin"
      },
      "warnings": null,
      "mount_type": "kv"
    }
    $ 
    

    Sie können dies mit jq kombinieren: 


    $ vault kv get -format=json kv/app/db | jq -r '.data.api'
    myapisecret
    $ 
    

    Pro-Tipp: Sie können das Standard-Ausgabeformat über die Umgebungsvariable VAULT_FORMAT dauerhaft auf JSON umstellen:


    export VAULT_FORMAT=json

     

    Versionen eines Secrets abrufen mit -version

    Das Leseverhalten von get ist recht einfach zu verrstehen, aber dazu muss man die Unterschiede zuerst einmal wissen. Es gelten folgende Regeln:

    • Ein normaler get-Befehl gibt immer die neueste Version zurück. 
    • Bei gelöschten Secrets (KV v2) erhalten Sie zwar Metadaten, aber keine Daten.
    • Spezifische Versionen können mit --version=X abgerufen werden (ebenfalls nur bei KV v2).

    Beispiel für das Abrufen einer bestimmten Version eines Secrets:


      $ vault kv get --version=1 kvv2/app/db
      == Secret Path ==
      kvv2/data/app/db
      
      ======= Metadata =======
      Key                Value
      ---                -----
      created_time       2025-07-01T10:52:07.551872783Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          false
      version            1
      
      ==== Data ====
      Key     Value
      ---     -----
      pass    123
      $ vault kv get --version=2 kvv2/app/db
      == Secret Path ==
      kvv2/data/app/db
      
      ======= Metadata =======
      Key                Value
      ---                -----
      created_time       2025-07-01T10:56:04.624145825Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          false
      version            2
      
      ==== Data ====
      Key     Value
      ---     -----
      api     myapisecret
      pass    123
      user    admin
      $ 
      

      Ich habe es schon mehrmals gesagt, aber man kann es nicht oft genug betonen: Die Versionierung von Secrets ist nur in KV v2 verfügbar. Das bedeutet auch, dass nur die KV v2 Secrets Engine gezielte Einsicht in die Historie einzelner Secrets erlaubt. Das kann sehr wichtig für späteres Auditing sein, zum Beispiel für den Nachweis, ob und wie oft Secrets tatsächlich rotiert wurden.

      Gezielte Updates und Wiederherstellungen von Secrets

      patch: Den richtigen Schlüssel präzise aktualisieren

      Weiter oben in diesem Artikel haben wir bereits ausdrükclich betont, dass das put-Kommando existierende Secrets komplett überschreibt und dabei potenziell vorhandene Daten löschen könnte.  Bitte nutzen Sie deshalb patch, um gezielt einzelne Werte innerhalb eines Secets zu ändern.

      In KV v1 klappt dies mangels Metadaten nicht:


      $ vault kv patch kv/app/db user=dbadmin
      KV engine mount must be version 2 for patch support
      $

      In KV v2 hingegen schon:


      $ vault kv patch kvv2/app/db user=dbadmin
      == Secret Path ==
      kvv2/data/app/db
      
      ======= Metadata =======
      Key                Value
      ---                -----
      created_time       2025-07-01T11:07:50.365256138Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          false
      version            3
      $ 
      

      Resultat: Nur der user-Schlüssel wird aktualisiert, der Rest des Secrets bleibt erhalten.

      rollback: Versionen sicher zurückrollen

      Ein falsch gespeichertes Secret? Aus Versehen trotzdem vault kv put benutzt? Kein Problem in KV v2. Falls Sie versehentlich Daten überschrieben haben, können Sie in KV v2 mithilfe von rollback zu einer älteren Version zurückkehren:


      $ vault kv get kvv2/app/db
      == Secret Path ==
      kvv2/data/app/db
      
      ======= Metadata =======
      Key                Value
      ---                -----
      created_time       2025-07-01T11:07:50.365256138Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          false
      version            3
      
      ==== Data ====
      Key     Value
      ---     -----
      api     myapisecret
      pass    123
      user    dbadmin
      $
      $ vault kv rollback -version=2 kvv2/app/db
      Key                Value
      ---                -----
      created_time       2025-07-01T11:10:44.341592593Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          false
      version            4
      $ 
      

      Dies erstellt eine neue Version mit dem Inhalt der angegebenen alten Version. In unserem Beispiel:

      • Version 2 enthält den ursprünglichen Inhalt
      • Version 3 war der fehlerhafte Überschreibversuch
      • Version 4 ist das Ergebnis des Rollbacks

      Pro-Tipp: Es wird also nicht alles zum Zeitpunkt der Erstellung von Version 2 zurückgerollt, sondern eine neue Version mit dem Inhalt von Version 2 angelegt. Die Historie bleibt also erhalten. 

      Daten löschen: delete vs. destroy

      Hier müssen Sie sich unbedingt merken, dass sich das delete-Kommando bei KV v1 und v2 unterschiedlich auswirkt.

      KV v1: Hard delete

      Bei Secrets mit der KV v1 Secrets Engine werden mittels delete die Daten endgültig gelöscht:


      $ vault kv delete kv/app/db
      Success! Data deleted (if it existed) at: kv/app/db
      $
      $ vault kv get kv/app/db
      No value found at kv/app/db
      $

      Die Daten sind also unwiderruflich gelöscht. Eine Wiederherstellung ist somit nur über das Einspielen eines Vault-Snapshots möglich.

      KV v2: Soft delete

      Bei KV v2 ist ein delete nur ein Soft Delete:


      $ vault kv delete kvv2/app/db
      Success! Data deleted (if it existed) at: kvv2/data/app/db
      $
      $ vault kv get kvv2/app/db
      == Secret Path ==
      kvv2/data/app/db
      ======= Metadata =======
      Key Value
      --- -----
      created_time 2025-07-01T11:10:44.341592593Z
      custom_metadata <nil>
      deletion_time 2025-07-01T11:13:33.705332433Z
      destroyed false
      version 4
      $

      Die Daten selbst sind nicht mehr sichtbar, aber noch im System vorhanden. Die Metadaten hingegen sind noch da, beachten Sie bei diesen auch die neu hinzugefügte deletion_time, zuvor hatte dieser Schlüssel den Wert n/a.

      Soft gelöschte Secrets lassen sich mit undelete reaktivieren oder mit destroy endgültig löschen.

      undelete: Gelöschte Versionen reaktivieren

      Falls versehentlich gelöscht wurde:


      $ vault kv undelete -versions=4 kvv2/app/db
      Success! Data written to: kvv2/undelete/app/db
      $ 
      $ vault kv get kvv2/app/db
      == Secret Path ==
      kvv2/data/app/db
      
      ======= Metadata =======
      Key                Value
      ---                -----
      created_time       2025-07-01T11:10:44.341592593Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          false
      version            4
      
      ==== Data ====
      Key     Value
      ---     -----
      api     myapisecret
      pass    123
      user    admin
      $ 
      

      Die Daten werden wieder sichtbar. Voraussetzung ist, dass kein destroy erfolgte.

      destroy: Endgültiges Löschen einzelner Versionen

      Wichtig: destroy ist unumkehrbar - auch undelete und rollback funktionieren nicht mehr. Daher bitte nur verwenden, wenn Sie sicher sind und auf keinen Fall mit delete verwechseln!

      Danach ist keine Wiederherstellung mehr möglich:


      $ vault kv destroy -versions=2 kvv2/app/db
      Success! Data written to: kvv2/destroy/app/db
      $ 

      Sie können auch mehrere Versionen gleichzeitig entsorgen:


      $ vault kv destroy -versions=1,3,4 kvv2/app/db
      Success! Data written to: kvv2/destroy/app/db
      $ 
      

      Nach einem destroy zeigt das destroyed-Feld den Wert true:


      $ vault kv get kvv2/app/db
      == Secret Path ==
      kvv2/data/app/db
      
      ======= Metadata =======
      Key                Value
      ---                -----
      created_time       2025-07-01T11:10:44.341592593Z
      custom_metadata    <nil>
      deletion_time      n/a
      destroyed          true
      version            4
      
      $ 
      

      Dieses Feld existiert vor allem für Audit-Zwecke. Ein rollback oder undelete ist somit dann ausgeschlossen und es dient als Nachweis, dass ein destroy ausgeführt wurde. 

      Praktische Tipps für Ihren Alltag und Ihre KV-Strategie

      1. Versionskontrolle nutzen

      Prüfen Sie regelmäßig, welche KV-Version Sie verwenden:


      $ vault secrets list --detailed | grep kv
      kv/           kv           kv_11a18e23           system         system     false             replicated     false        false                      map[]             n/a                                                        4a479e06-6b44-e721-bbff-5ab3df0b7134    n/a        v0.21.0+builtin          n/a               supported
      kvv2/         kv           kv_be4ef9a0           system         system     false             replicated     false        false                      map[version:2]    n/a                                                        390c2b5f-45cd-6774-ae17-3d643d951401    n/a        v0.21.0+builtin          n/a               supported
      $ 
      

      Suchen Sie nach version:2 in der Options-Spalte (zweite von rechts).

      2. Strukturierte Pfade verwenden

      Entwickeln Sie eine konsistente Namenskonvention innerhalb des Pfades der Secret Engine, zum Beispiel:


      apps/
        └── payment-service/
            ├── prod/
            │   ├── db-credentials
            │   └── api-keys
            └── dev/
                ├── db-credentials
                └── api-keys

      3. patch statt put verwenden

      Für Updates einzelner Werte nutzen Sie immer patch statt put, um Datenverlust zu vermeiden.

      4. JSON-Output für automatisierte Workflows

      In Skripten verwenden Sie konsequent:


      vault kv get -format=json kv/app/db | jq -r '.data.password'

      3. Führen Sie eine Rollback-Strategie ein

      Dokumentieren Sie wichtige Versionen und halten Sie Rollback-Prozeduren bereit. Zum Beispiel:


      # Aktuelle Version sichern
      $ CURRENT_VERSION=$(vault kv get -format=json kvv2/app/db | jq -r '.data.metadata.version')
      $ echo $CURRENT_VERSION
      5
      
      # Bei Problemen: Rollback
      $ vault kv rollback --version=$((CURRENT_VERSION-1)) kvv2/app/db

      Häufige Fehlerquellen vermeiden

      1. Der "write is not merge"-Fehler

      Das häufigste Problem: Versehentliches Überschreiben durch put statt patch.

      2. Pfad-Verwirrung in KV v2

      Behalten Sie im Hinterkopf:

      • Unterschiedliche Pfade in KV v2 durch Groß-/Kleinschreibung
      • KV v2 fügt automatisch /data/ in den internen Pfad ein. Die CLI abstrahiert das, aber bei direkten API-Aufrufen müssen Sie das beachten.

      3. Verwechslung von delete und destroy

      • delete = Soft Delete (wiederherstellbar) bei KV v2, Hard Delete bei KV v1
      • destroy = Hard Delete (unwiderruflich) bei KV v2

      4. Keine Rücksetzung von Versionsnummern nach delete

      Versionsnummern in KV v2 sind fortlaufend und werden nie zurückgesetzt, auch nicht nach einem delete.

      Fazit

      Die Key/Value Secrets Engine ist schnell erklärt, aber in der praktischen Nutzung voller Nuancen. Ein fundiertes Verständnis der Versionierung, der Kommandos und ihrer Seiteneffekte entscheidet über einen stabilen und sicheren Betrieb.

      Wer put mit Bedacht einsetzt, patch zur gezielten Pflege nutzt und rollback im Ernstfall beherrscht, hat das Werkzeug KV Engine im Griff. Und wer destroy meidet, solange es nicht unbedingt notwendig ist, erspart sich viel Ärger und bewahrt sich im Fehlerfall den Rückweg aus dem Tal der Tränen.

      Merksatz für die Praxis: In KV v2 ist fast alles wiederherstellbar - außer nach einem destroy.

      Nutzen Sie diese Sicherheit, aber gestalten Sie Ihre Prozesse dennoch vorausschauend.