Secret Management mit HashiCorp’s Vault

Security ist nach wie vor ein heisses Thema in der IT. Das zeigt auch das Aufkommen diverser Security bezogenen Tools wie z.B. Square’s Keywhiz oder HashiCorp’s Vault. Wir haben uns Vault etwas genauer angeschaut und uns überlegt wie wir Vault in der Adfinis SyGroupeinsetzen können.

Was ist Vault?

In seiner simpelsten Form ist Vault ein hierarchischer Key/Value Store zum Speichern von Secrets. Die Idee ist, dass man Vault an eine persistente Datenbank (z.B. MySQL, PostgreSQL, Consul, …) seiner Wahl anschliesst oder alternativ auf das built-in File-Backend zurückgreift. Die Interaktion mit Vault geschieht über eine HTTP REST API, zu welcher es Client Libraries in den verschiedensten Programmiersprachen gibt.

Bevor wir aber genauer darauf eingehen wie Vault funktioniert, sollte geklärt sein, welche Probleme Vault lösen zu versucht. Betrachtet man den Lifecycle eines generischen Secrets, z.B. eines Passwortes für einen Datenbank-Benutzer, sieht dieser meist wie folgt aus:

1. Der Admin legt ein Secret mit Berücksichtigung der firmenweiten Passwort-Richtlinien fest.
2. Das Passwort wird in einem Passwortmanager seiner Wahl festgehalten.
3. Beim Rückbau des Benutzers wird die Passwortliste entsprechend angepasst.

Leider geht oftmals ein wichtiger Punkt vergessen, nämlich die regelmässige Rotation der Secrets. Mit der Annahme, dass man mit genug Zeit und Ressourcen jede Verschlüsselung brechen kann, wäre es verheerend wenn ein Angreifer an eine Kopie der verschlüsselten Passwort-Datenbank gelangt.

Die Vision von HashiCorp sind sogenannte „dynamische Secrets“. Anstatt, dass der System Administrator beim Einrichten einer Webapplikation das Passwort setzt, holt sich die Webapplikation das Secret selber in regelmässigen Zeitabständen bei Vault ab. Dabei wird jedem Secret eine TTL mitgegeben, welche die Lebensdauer des Secrets auf wenige Stunden oder Tage limitiert. Sollte in einem solchen Szenario der Angreifer an die verschlüsselten Passwörter gelangen, wäre dies „harmlos“ da in einem Tag bereits alle rotiert sind.

Durch die Zentralisierung entsteht ausserdem ein weiterer Nebeneffekt, denn sie ermöglicht sogenannte Break Glass Procedures. Stellt man in der eigenen Infrastruktur eine Schwachstelle fest, kann der Zugriff auf das betroffene Subset an Secrets gesperrt werden. Hat man die Schwachstelle gefunden und behoben, werden die Secrets rotiert und wieder freigegeben.

Zu diesem Zeitpunkt unterstützen die wenigsten Applikationen Vault nativ. Verwendet man allerdings das HashiCorp eigene Consul als Datenbackend, können Konfigurationsdateien durch das Tool consul-template bei Key/Value Änderung automatisch neu generiert werden.

Um Änderungen am Datenbestand protokollieren zu können, stellt Vault verschiedene Audit Backends zur Verfügung (Structured Logs und Syslog). So können Mutation auch später eingesehen werden. Der Zugriff auf Secrets lässt sich ausserdem durch ein ausgeklügeltes ACL System einschränken. ACLs lassen sich wiederum mit verschiedenen Authentication Backends verknüpfen. So kann man den Zugriff auf einen Pfad für eine bestimmte LDAP Gruppe bspw. auf „Read-Only“ einschränken.

Die Konfiguration von Vault geschieht wahlweise über eine HCL oder JSON Datei. In folgendem Beispeil sieht man eine Konfiguration mit einem Consul Backend:

backend "consul" {
address = "127.0.0.1:8500"
path = "vault"
}

listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 0
tls_cert_file = "/etc/ssl/host.crt"
tls_key_file = "/etc/ssl/host.key"
tls_min_version = "tls12"
}

> Was die Erstellung des TLS Zertikates betrifft, verweise ich an dieser Stelle gerne auf unseren Post OpenSSL x509 Zertifikate erstellen.

Demo

Um ein Gefühl dafür zu bekommen wie sich Vault bedienen lässt, folgt nun eine kleine Demo.

Sobald der Vault Server läuft, muss er initialisiert werden.

$ vault init
Unseal Key 1: aRqypTLVENeZ9Tt1Kw2sy7XlnqHLT8XOUn3yqGTFMvsB
Unseal Key 2: o4Rd/1ZyzBwZaVEksIHsMpCJimv/pOt1+pSfQFiOEUkC
Unseal Key 3: S1x0hTZ5SrqiQlH1Boh8c/teKtfypu/PS6c5aHGj31cD
Unseal Key 4: TNdq4mdDDUMXAlxbtH8GCRRn3KU4HR3VSiefbWDUjtAE
Unseal Key 5: pA9DmAdIi+WsKVyKAnaWSH+wfBk1Hxlv+xQ5RUn5QM4F
Initial Root Token: 53368d66-8d50-ba5a-f953-7ef6b2dc03de
...

$ for KEY in ${UNSEAL_KEYS}; do vault unseal ${KEY}; done
...
Key (will be hidden):
Sealed: false
Key Shares: 5
Key Threshold: 3
Unseal Progress: 0
...

$ vault auth $ROOT_TOKEN
Successfully authenticated! You are now logged in.
token: 1bb7c7c6-6d4e-be92-cb5c-2838ccde3b5c
token_duration: 0
token_policies: [root]
...

Dabei wird ein Master Key generiert und in mehrere Subkeys aufgeteilt (siehe Shamir’s Secret Sharing). Von den generierten Subkeys werden in der Standardkonfiguration ein Quorum von 3 Keys benötigt um die Vault Instanz zu „entsiegeln“, ein Prozedere das bei jedem Start der Vault Instanz vorgenommen werden muss. Das initiale Root Token wird anschliessend benötigt um sich gegenüber Vault zu authentisieren.

Ab jetzt können Secrets in das standardmässig vorhandene secret/ Backend geschrieben werden.

$ vault mounts
Path Type Default TTL Max TTL Description
cubbyhole/ cubbyhole n/a n/a per-token private secret storage
secret/ generic system system generic secret storage
sys/ system n/a n/a system endpoints used for control, policy and debugging

$ vault write secret/test secret_key=secret_value
Success! Data written to: secret/test

$ vault list secret/
Keys
----
test

$ vault read secret/test
Key Value
--- -----
refresh_interval 720h0m0s
secret_key secret_value

Das war nur ein kleiner Auszug aus den verfügbaren Features welche Vault anbietet. Hier ein paar weiterführende Use Cases welche aber den Rahmen dieses Blogpostes sprengen würden:

  • Generieren von Amazon Web Services IAM Policies
  • Verwaltung von dynamischen Datenbank Benutzer/Rollen für MySQL, PostgreSQL, MongoDB…
  • Vollständige PKI zum Erstellen und Signieren von TLS Zertifikaten
  • SSH Zugriff auf Systeme durch OTP absichern

Ich kann jedem empfehlen einen Blick in die hervorragende Dokumentation von Vault zu werfen. In kürze folgt ausserdem ein zweiter Teil der aufzeigt, wie wir Vault adaptiert haben.