
API-Keys, Passwörter, Zertifikate und weitere sensible Daten in cloud-nativen Secret-Management-Diensten ablegen und aus K8s-Clustern darauf zugreifen.
Einführung
Secrets sind für den Betrieb vieler Produktivsysteme unverzichtbar. Eine ungewollte Offenlegung zählt zu den größten Risiken und muss konsequent adressiert werden. Entwickler sollten alles daran setzen, Anwendungs-Secrets zu schützen.
Noch komplexer wird es, sobald ein Unternehmen auf eine Microservice-Architektur umstellt und mehrere Services für ihren Betrieb auf unterschiedliche Secrets zugreifen müssen. Daraus ergeben sich neue Herausforderungen: Wie lassen sich Anwendungs-Secrets verteilen, verwalten, überwachen und rotieren, ohne dass sie ungewollt nach außen dringen?
Im vorherigen Beitrag (Teil I) habe ich gezeigt, wie sich die Secret-Management-Dienste von AWS und Google Cloud (AWS Secrets Manager, AWS SSM Parameter Store und Google Cloud Secret Manager) mit Kubernetes verbinden lassen – über den initContainer doitintl/secrets-init, der manuell in den Ziel-Pod eingefügt wird.
In diesem Beitrag stelle ich einen Kubernetes-nativen Ansatz vor, mit dem sich die genannten Cloud-Secret-Management-Dienste anbinden lassen.
Automatische Cloud-Secret-Injection
Zwar lassen sich Kubernetes-Deployment-YAML-Dateien manuell anpassen, um secret-init als init-System eines Containers zu nutzen – eleganter ist es jedoch, wenn das automatisch geschieht, und zwar nur für Kubernetes-Pods, die tatsächlich auf Cloud-Secrets verweisen. Glücklicherweise erlaubt Kubernetes, jeden Pod vor der Container-Erstellung zu prüfen und zu verändern – über einen Mechanismus namens Mutating Admission Webhook.
doitintl/kube-secrets-init ist ein Open-Source-Projekt von DoiT International, das einen Kubernetes-Mutating Admission Webhook für die Injection von Cloud-Secrets bereitstellt – sowohl für AWS- als auch für Google-Cloud-verwaltete Secrets.
kube-secrets-init beobachtet Kubernetes-Cluster auf neu erstellte oder aktualisierte Pods und ergänzt einen initContainer mit dem Tool doitintl/secrets-init in allen Pods, die direkt (über Umgebungsvariablen) und/oder indirekt (über Kubernetes-Secret und ConfigMap) auf Cloud-Secrets verweisen.

Integration mit AWS Secrets Manager
Sie können einen ARN-Verweis auf ein AWS-Secret als Wert einer Umgebungsvariable hinterlegen. secrets-init löst diesen Wert anhand des angegebenen ARN in den eigentlichen Secret-Wert auf.
https://gist.github.com/930c9ea733557f9715f976df042bf361
Integration mit AWS Systems Manager Parameter Store
Der AWS Systems Manager Parameter Store eignet sich, um Anwendungsparameter und Secrets abzulegen.
Sie können einen ARN-Verweis auf einen Eintrag im AWS Parameter Store als Umgebungsvariable hinterlegen. secrets-init löst den Wert über den angegebenen ARN in den entsprechenden Parameter-Store-Wert auf.
https://gist.github.com/f7d9a81d5e239cdd734989a689d46f82
Integration mit Google Secret Manager
Sie können einen Google-Secret-Namen (mit dem Präfix gcp:secretmanager:) als Wert einer Umgebungsvariable hinterlegen. secrets-init löst den Wert anhand des angegebenen Namens in den entsprechenden Secret-Wert auf. Der Secret-Name kann zusätzlich eine Versionsangabe enthalten, um eine bestimmte Version des Secrets zu referenzieren.
https://gist.github.com/d121cce3a9d4664a876deb95f18493d7
Voraussetzungen
AWS
Damit AWS-Secrets aus AWS Secrets Manager und Parameter Store aufgelöst werden können, muss die Anwendung secrets-init unter einer AWS-IAM-Rolle laufen, der eine der folgenden IAM-Policies zugewiesen ist.
Für AWS Secrets Manager:
https://gist.github.com/7348301b4882a564cbd9644d6697c3eb
Für AWS Systems Manager Parameter Store:
https://gist.github.com/3f3dd3d015a4c000341491c18ac2c4b7
Im Betrieb innerhalb eines EKS-Clusters empfiehlt sich der Einsatz von AWS IAM Roles for Service Account. Alternativ lässt sich der EC2-Instanz, auf der der Container läuft, eine IAM-Rolle zuweisen. Diese Variante gilt jedoch als weniger sicher.
Google Cloud
Damit Google-Secrets aus Google Secret Manager aufgelöst werden können, muss die Anwendung secrets-init unter einer IAM-Rolle laufen, die ausreichende Berechtigungen für die gewünschten Secrets besitzt. Sie können einem Google Service Account beispielsweise die beiden vordefinierten Google-IAM-Rollen Secret Manager Viewer und Secret Manager Secret Accessor zuweisen.
Im GKE-Cluster lässt sich einem Kubernetes-Pod über Workload Identity eine IAM-Rolle zuweisen. Alternativ ist die Zuweisung an die GCE-Instanz möglich, auf der der Container läuft. Diese Variante gilt als weniger sicher.
Entfernen Sie das Kommentarzeichen vor dem Flag --provider=google in der Datei deployment.yaml.
Webhook-Deployment
- Um den Webhook-Server
kube-secrets-initauszurollen, legen wir einen Webhook-Service und ein Deployment in unserem Kubernetes-Cluster an. Im Grunde unkompliziert – mit einer Ausnahme: der TLS-Konfiguration des Servers. Ein Blick in die Datei deployment.yaml zeigt, dass das Zertifikat und die zugehörige Private-Key-Datei aus Kommandozeilenargumenten gelesen werden und der Pfad zu diesen Dateien aus einem Volume Mount stammt, der auf ein Kubernetes-Secret zeigt:
https://gist.github.com/b861984a2be2f2f63596f089f417cefc
Wichtig: Hinterlegen Sie das passende CA-Zertifikat später in der Webhook-Konfiguration, damit der apiserver es akzeptiert. Vorerst greifen wir auf das ursprünglich vom Istio-Team geschriebene Skript zurück, um einen Certificate Signing Request zu erzeugen. Anschließend senden wir den Request an die Kubernetes-API, holen das Zertifikat ab und erzeugen daraus das benötigte Secret.
Führen Sie zunächst das Skript webhook-create-signed-cert.sh aus und prüfen Sie, ob das Secret mit Zertifikat und Schlüssel erstellt wurde:
https://gist.github.com/43135c6af29328bcd74a37b0df5188f8
Sobald das Secret existiert, können wir Deployment und Service anlegen. Dabei handelt es sich um ganz gewöhnliche Kubernetes-Deployment- und -Service-Ressourcen. Bis hierhin haben wir nichts weiter erzeugt als einen HTTP-Server, der Requests über einen Service auf Port 443 entgegennimmt:
https://gist.github.com/3971cf1f46f5a57d11d922ed84b0543f
Mutating Admission Webhook konfigurieren
Unser Webhook-Server läuft nun und kann Requests vom apiserver entgegennehmen. Zuvor müssen wir jedoch noch einige Konfigurationsressourcen in Kubernetes anlegen. Beginnen wir mit dem Validating Webhook; um den Mutating Webhook kümmern wir uns anschließend. Ein Blick in die Webhook-Konfiguration zeigt, dass sie einen Platzhalter für CA_BUNDLE enthält:
https://gist.github.com/fcafa7ed3b3c3b951b7fad3c0d5fbdb6
Es gibt ein kleines Skript, das den Platzhalter CA_BUNDLE in der Konfiguration durch diese CA ersetzt. Führen Sie folgenden Befehl aus, bevor Sie die Validating-Webhook-Konfiguration anlegen:
https://gist.github.com/6d5bb7724cef04e9e6a2af12da917a21
Legen Sie eine Mutating-Webhook-Konfiguration an:
https://gist.github.com/f946d6046cc1a76a21526c346ca403c1
RBAC für secrets-init-webhook konfigurieren
Erstellen Sie einen Kubernetes Service Account für secrets-init-webhook:
https://gist.github.com/0cda887b586609cbdbb700f7412e70ad
Definieren Sie die RBAC-Berechtigungen für den Webhook Service Account:
https://gist.github.com/1205f1a5d2f449cc3340a404ea474b77
Fazit
Ich hoffe, dieser Beitrag ist für Sie hilfreich. Über Kommentare und Fragen freue ich mich.
Sie sind außerdem herzlich eingeladen, zum GitHub-Projekt doitintl/kube-secrets-init beizutragen (Issues, Features, PRs).
Mehr Beiträge von Alexei? Schauen Sie in unseren Blog oder folgen Sie Alexei auf Twitter.