Podcast

Kubernetes Secrets

Schützenswerte Resscourcen

Wie schütze ich meine sensiblen Daten und Schlüssel innerhalb einer Container-Umgebung? Sebastian und Sascha widmen sich dieser Fragestellung und geben Antworten, wie Kubernetes Secrets genau dieses Problem lösen.
Weitere Episoden anhören

Shownotes & Links

Transkript

Transkript ausklappen / einklappen

Sebastian: Herzlich willkommen zu einer neuen Episode des INNOQ Podcasts. Heute mit mir und dem Sascha. Hi Sascha.

Sascha: Hi Sebastian.

Sebastian: Wir haben uns ein Thema Kubernetes Secrets vorgenommen. Da wir beide schon damit so ein bisschen gearbeitet haben, wollten wir uns mal ein bisschen dazu austauschen, bisschen was zu erzählen. Am besten machen wir es an einem Beispiel. Nehmen wir mal an, wir haben so eine Anwendung, eine Twelve-Factor App, dazu hatten wir auch mal eine Episode hier auf dem Podcast. Das heißt, die macht irgendetwas, es ist eigentlich völlig egal, was sie macht, aber sie braucht auch eine Konfiguration, die bekommt sie über Umgebungsvariablen rein. Und lokal kann ich sie ganz normal starten. Sie liest ihre Parameter ein, möchte aber vielleicht auch mit einem externen System reden, mit einer Datenbank zum Beispiel und in der Regel ist dafür auch ein Passwort fällig. Passwort schützenswert. Ja, was mache ich damit? Lokal starten ist kein Problem. Aber wie kriege ich das jetzt in meinen Kubernetes rein deployed? Was mache ich da, Sascha?

Sascha: Man muss sich nochmal anschauen, wie Kubernetes intern funktioniert. Das Herzstück von dem ganzen Kubernetes ist eigentlich diese Ressourcenbeschreibung. Alles was wir in Kubernetes haben wollen, beschreiben wir in Form von Ressourcen. Das ist unsere Wunschvorstellung, was Kubernetes dann umsetzen soll, das sind teilweise Konfigurationen von irgendwelchen Netzwerkkomponenten, das sind Deployments von eigenen Applikationen, aber auch irgendwelche Config-Parameter. Dafür gibt es im Kubernetes Umfeld das Secret und die ConfigMap. Vom Namen hört man schon, die Secrets sind die Sachen, die schützenswert sind und beide Sachen funktionieren aber sehr ähnlich. Sie sind als Key Values abgelegt, werden gespeichert und werden dann den Applikationen zur Verfügung gestellt von Kubernetes. Zum Beispiel in Form von Umgebungsvariablen.

Sebastian: Alles ist irgendwie eine Ressource. Viele finden das kompliziert. Ich finde es aber eigentlich sehr angenehm bei Kubernetes, weil ich mir alle diese Ressourcen angucken kann. Und wie ist das alles zusammengebaut? Und klar, die ConfigMap und das Secret sagst du jetzt sind zwei Ressourcen, wo ich meine Konfiguration unterbringen kann. Und ich habe auch mal irgendwo gehört, Kubernetes grundsätzlich unterscheidet da gar nicht, welche Ressource das ist. Oder hat das Secrets irgendeine besondere Bewandtnis in Kubernetes?

Sascha: Vom Typ her, überall wo ich ein Secret verwenden kann, kann ich auch eine ConfigMap theoretisch verwenden. Der einzige Unterschied ist, dass die Werte von einem Secret Base64 entcodiert werden, bevor sie gespeichert werden innerhalb von Kubernetes. Sie werden dann sozusagen decodiert, bevor es als Umgebungsvariable zur Verfügung gestellt wird. Aber das ist der einzige große Unterschied innerhalb des Clusters.

Sebastian: Also nicht verschlüsselt, sondern codiert, damit es als String kompatibel überall ist.

Sascha: Genau.

Sebastian: Okay, gut. Ich habe jetzt meine Anwendungen. Ich möchte die deployen, das heißt ich schreibe ein Deploy Deskriptor, eine Deploy Ressource dafür, also YAML. Und dann muss ich natürlich noch eine ConfigMap dazulegen, die dann da die Umgebungsvariablen definiert und teile dann noch mal davon die Secrets ab, die schützenswerten Sachen. So, jetzt habe ich das lokal auf meiner Platte gemacht, jetzt ist aber mein Projekt in der Versionskontrolle. Was mache ich jetzt damit? Ich möchte es nicht einchecken. Ich könnte es wahrscheinlich direkt im Kubernetes anlegen, oder?

Sascha: Genau. Wir als Entwickler interagieren eigentlich mit Kubernetes mit dem kubectl, mit dem CLI Tool von Kubernetes. Und da gibt es ein paar Kommandos, die wir direkt nutzen können, um so ein Secret zu erzeugen. Auf Basis von irgendeiner lokalen datei oder von Key Values, die wir selbst definieren. Das ist meistens als kubectl create. Und dann kann man so ein generisches Secret erzeugen. Das wäre eine Variante, wie ich das manuell in den Cluster bekomme.

Sebastian: Okay, aber das habe ich bei mir gemacht. Jetzt ist die Frage, ich habe ja vielleicht auch Updates oder muss das ändern oder so, da kann es natürlich auch praktisch sein, wenn ich es direkt machen kann. In der Regel arbeite ich aber im Team und vielleicht möchte ich auch den Server später mal so updaten, dass ich das Passwort rotiere. Irgendwie hat das Passwort ja auch einen Lifecycle, den ich abbilden will.

Sascha: Ja, vor allem dieser Life Cycle gehört auch immer zu der jeweiligen Applikation. Wir können vielleicht mit bestimmten Variablen umgehen in einer Version und mit anderen in einer anderen. Das heißt, es muss eigentlich immer zusammenpassen. Der Lifecycle von den Secrets passt eigentlich zu den Versionen unseres Deployments. Eigentlich sollten die irgendwie zusammen deployed werden. Mit dem manuellen Schritt ist es ein bisschen problematisch, weil wir müssen uns immer selbst merken, dass wir diese Datei anlegen müssen, also dieses Secret manuell erzeugen müssen, weil wir nicht immer davon ausgehen können, dass es vielleicht schon vorherrscht. Wir können uns vorstellen, wenn der Cluster neu aufgesetzt wird, dann müssen wir das manuell nochmal ausführen. Das heißt, wir müssen irgendwo das Secret ablegen. entweder es hat nur einen Entwickler, der macht es dann jedes Mal oder wir müssen es irgendwo anders ablegen, dass jeder das theoretisch erzeugen könnte.

Sebastian: Ja, dann könnte ich das natürlich direkt mal schön in Git einchecken, dann haben es ja alle. Also alle haben das dann.

Sascha: Richtig, jeder, der Zugriff auf das Git Repo hat, kann sich auch das Secret anschauen, die Credentials anschauen. Ich glaube aus Security Sicht ist das nicht der beste Weg.

Sebastian: Ich glaube, es gibt Security Scanner, die öffentliche Git Repos oder überhaupt Repos durchsuchen nach Credentials und die werden erstaunlich fündig.

Sascha: Ja, ich glaube auch, dass man sich nicht darauf verlassen sollte, dass die Gruppenrichtlinien für das Git Repository reichen, sondern man muss sich irgendetwas anderes überlegen, wie man sicherer solche Secrets einchecken kann.

Sebastian: Dann verschlüssel ich meine Secrets doch. Da gibt es ja auch Tools für.

Sascha: Genau. Eins, was wir auch schon mal im Einsatz hatten, in ein paar Projekten ist das git-crypt. Das ist sozusagen ein kleiner Zusatz zu Git selbst, es ist ein eigenes Tool. Und da habe ich die Möglichkeit beliebige Dateien in meinem Git Repository zu verschlüsseln. Und das funktioniert meistens so, dass ich GPG Keys habe von meinen ganzen Entwicklern, die darauf Zugriff haben dürfen. Dann füge ich den Public Key von allen dem git-crypt hinzu. Und sobald das passiert ist und ich das eingecheckt habe, kann jeder, dessen Public Key hinterlegt ist, das selber lokal entschlüsseln.

Sebastian: Das klingt erst mal gar nicht so verkehrt. Aber ich will wahrscheinlich nicht das ganze Repo verschlüsseln. Da kann ich also Pattern anwenden wie in der gitignore?

Sascha: Genau, man kann Datei Patterns hinterlegen, welche Dateien jetzt angezogen werden sollten für die Verschlüsselung. Das muss man sich dann für das Repo überlegen, was ein sinnvolles Pattern ist. Meistens wahrscheinlich irgendwo, wo Secret drauf steht im Dateinamen. Aber das ist schon mal ein guter Anfang.

Sebastian: Ja, die Wahrscheinlichkeit ist hoch, dass da auch was drin ist. Jetzt habe ich das schön verschlüsselt und meine Kollegen können das auch klonen und entschlüsseln, solang ihr Key hinzugefügt worden ist. Jetzt muss ich das aber auch deployen. Das heißt, mein Cluster weiß da nichts von git-crypt. Das heißt, das muss ich Deployment machen, das Entschlüsseln.

Sascha: Genau. Kubernetes selber kennt git-crypt nicht. Das ist für ihn sozusagen wie eine nicht lesbare Datei. Das heißt, das müsste irgendwo vorher passieren, zum Beispiel im CI/CD System, was wir klassisch ja immer haben. Irgendwas, was das Deployment für uns übernimmt. Und da ist es so, natürlich braucht man auf eben dieses CI-System Zugriff auf die Secrets. Im Normalfall bei git-crypt läuft es so, dass man einen symmetrischen Schlüssel exportieren kann. Und den dann dem CI-System hinterlegt, damit dort diese Entschlüsselung stattfindet, bevor das Deployment wirklich loslegt.

Sebastian: Das heißt, da wird irgendwas deployed. Wenn ich ein Deploy Job habe, der muss dann git-crypt als Tool installiert haben oder in einem Container oder so was. Und dann starte ich das Ganze und dann entschlüsselt er das und braucht dieses Secret. Das heißt im CI-System, das ist so ungefähr gleichwertig zu den Entwicklern, die haben dann alle das gleiche Secret, wenn es ein symmetrischer Schlüssel ist oder das CI-System hat auch einen GPG Key, der da hinzugefügt worden ist. Aber häufig kann ich das dann auch auslesen als Entwickler oder ich printe mir das in die Build Locks rein, wenn ich böse bin. Also irgendwie komme ich da wahrscheinlich auch dran. Und wenn ich das habe, dann habe ich auch die Secrets in der Hand.

Sascha: Vor allem, wenn man das ein bisschen getrennt betrachtet. Es gibt so diese Entwicklungsumgebung, da gehören diese Git Repositories dazu, die CI, das CI-System dazu. Und dort möchten wir eigentlich gar nicht die Secrets haben, im besten Fall, dass man da überhaupt irgendwas entschlüsseln kann. Eigentlich wollen wir es nur in einem gesicherten Umfeld haben, wie es am Ende der Produktion ist. Aber mit git-crypt ist es eigentlich nicht möglich. Mit git-crypt ist es eher für die lokale Verschlüsselung gedacht und ist natürlich ein Sicherheitsrisiko an der Stelle. Egal ob das jetzt lokal passiert oder in der CI Pipeline.

Sebastian: Und bezüglich Teammitglieder, Offboarding oder so was. Wenn da jemand das Team verlässt, ich meine, ich habe es in der Versionskontrolle. Das heißt, ich kann jederzeit jeden alten Stand auschecken, weil er mein GPG-Key berechtigt ist, das zu entschlüsseln. Ansonsten, wie sieht der Prozess aus? Jemand verlässt das Team und soll da keine Rechte mehr haben?

Sascha: Ja, das ist bei git-crypt tatsächlich sehr problematisch. Es gibt kein richtiges Offboarding. Es ist nicht vorgesehen, bestehende Schlüssel wieder zu entfernen. Der Weg wäre wahrscheinlich, alle Dateien noch einmal neu zu verschlüsseln ohne den einen zusätzlichen Schlüssel. Und das wieder einzustecken. Aber wie du schon gesagt hast, in der Historie, im Git liegt nicht nur die Information der verschlüsselten Datei, sondern auch mit welchen Schlüsseln verschlüsselt wurde. Das heißt, wenn man auf den alten Stand geht, wo diese Person noch berechtigt war, kann er dort immer noch entschlüsseln, selbst wenn wir es später neu verschlüsselt haben, ohne seinen Schlüssel.

Sebastian: Das kann auf jeden Fall ein Nachteil sein. Oder, auch schon erlebt, es gibt Projekte, die laufen stabil oder Repositories und es gibt kein Team mehr dazu. Und dann muss man recherchieren: Wer hatte denn hier mal Zugriff? Und kannst du mir das denn noch mal entschlüsseln? Weil das git-crypt Repos sind, die das verwenden, die dann verwaist sind und dann hat man ein Problem unter Umständen.

Sascha: Da hofft man, dass man noch einen symmetrischen Schlüssel im CI System findet.

Sebastian: Richtig. Da fängt die Recherche an. Ein Tool, das ich auch mal ausprobiert hatte, ist das SOPS. Das ist von Mozilla ein Tool, das basiert auch auf GPG. Das macht sich allerdings das Prinzip von dem asymmetrischen Verschlüsseln oder den Schlüssel macht es sich zunutze, sodass der Cluster oder das CI System, je nachdem, den Private Key hat und jeder, der da rein was deployen möchte, hat den Public Key. Ähnlich wie bei E Mail, wo ich auch nur die Public Keys brauche, um für die Empfänger etwas zu verschlüsseln. Und die Empfänger sind einzig und allein in der Lage, das zu entschlüsseln. Das setzt man dann so auf, dass man so einen Schlüsselpaar erzeugt, den Private Key in den Cluster legt und dann kann der die Ressourcen, die man da rein deyployed entschlüsseln. Solange der irgendeine Mechanik installiert ist, ein Operator, die das auch alles verstehen. Das ist wie bei git-crypt auch. Kubernetes an sich kann damit jetzt erst mal nichts anfangen, wenn es verschlüsselt ist. Aber es gibt zum Beispiel f.lux, was das wohl von Haus aus kann oder wo es eine Möglichkeit dazu gibt. Oder Argo CD mit irgendwelchen Hooks um, sobald der Cluster eine neue Ressource rein deployed bekommt, dass er das vorher entschlüsselt und dann erst weiter vom Kubernetes verarbeiten lässt. Und das geht auch mit mehreren Key. Das fand ich auch ganz spannend. Bei git-crypt legt man fest über ein globbing pattern, welche Dateien verschlüsselt werden auf Dateisystem-Ebene. Und bei SOPS ist es so, dass man ein ein Dot-File, .sops.yaml, hinterlegt und daran schreibt man dann nicht ein Datei-Pattern, sondern die YAML Keys, dessen values verschlüsseln soll. Damit kann ich zum Beispiel dafür sorgen, dass bei allen Ingressen der Host name, wenn der geheim bleiben soll, weil ich komplett Public Repo hätte, zum Beispiel, dass ich dann da diesen Host verschlüsseln möchte. Genauso schreibt man das: host:* und welchen Key man verwenden soll. Man kann auch mehrere DOT SOPS Files anlegen im Repo, je nachdem, wenn ich jetzt Deployments für prod und für non-prod hätte, dass ich die mit verschiedenen Keys verschlüsseln,. Da kann ich so ein bisschen fein-granularer steuern.

Sascha: Ich finde auch noch ganz gut, dass nach der Verschlüsselung die YAML Struktur an sich immer noch gültig ist. Die können zumindest noch die Keys lesen. Und das ist der große Unterschied zu git-crypt. Bei git-crypt wird die ganze Datei immer verschlüsselt. Und hier, ich glaube SOPS unterstützen YAML, JSON und ich weiß nicht ob noch was, aber es versteht die Struktur der Datei und verschlüsselt darauf.

Sebastian: Ja, genau das ist richtig. In der Regel, wenn ich in meinem Projekt irgendetwas suche, dann interessieren mich selten die Passwörter selbst, sondern eher: Wo ist das hinterlegt? Wie sieht das Secret aus oder die ConfigMap oder was auch immer. Das ist recht entwicklerfreundlich.

Sascha: Wenn ich jetzt nur mal daran denke, wenn ich eine Applikation schreibe und sage, ich möchte bestimmte Werte aus dem Secret bei mir als Umgebungsvariable mappen, ist das was ich eigentlich brauche, der Name des Keys, damit ich weiß, was ich herausgreifen kann. Und das ist mit git-crypt einfach nicht machbar, wenn ich nicht die ganze Datei lesen kann.

Sebastian: Ja, das stimmt. Das ist auch ein Vorteil. Ein Nachteil ist, das kann bei git-crypt auch der Fall sein. Bei git-crypt habe ich einen Vorteil, ich habe eine Datei, wo diese globbing patterns hinterlegt sind. Bei SOPS ist es so, dass ich wie bei DOT n files einfach so eine ganze Hierarchie und eine ganze Kette aufbauen kann. Das heißt, wenn ich hoffentlich nicht, feststelle, dass irgendwas nicht verschlüsselt, dann muss ich mir eventuell verschiedene Dateien, die vielleicht sich auch irgendwie widersprechen, angucken, warum denn da vielleicht auch der falsche Key verwendet wird. Und das fällt dann vielleicht auch beim Deployment auf, wenn da irgendein Job diese Ressourcen nicht dekodieren, de-crypten kann.

Sascha: Was vielleicht noch spannend sind bei SOPS ist, dass wir mehr als eine Art von Backend anziehen können. Der Standard Weg, was wir jetzt beschrieben haben, war mit dem GPG Keys. Aber es gibt auch noch externe Services, um Keys zu managen. Bei AWS, das KMS, das Key Management Service. Das ist relativ gut integriert mit dem SOPS, dass ich die Keys gar nicht mehr lokal haben muss, sondern ich nur Zugriff auf dieses KMS haben muss und damit auch lokal theoretisch arbeiten kann und entschlüsseln kann.

Sebastian: Ja, mit dieser eingangs erwähnten lokalen Variante ist es ein bisschen seltsam, denn die Zugriffsverwaltung, die Authentifizierung findet über den Besitz des Public Keys statt. Jeder, der den Public Key hat, kann dem Cluster beliebig irgendwas unterjubeln. Das will ich überhaupt nicht. Das heißt, ich hänge dann nur noch an dem GitLab, GitHub oder was auch immer, an dem Abrechnungssystem vielleicht, wenn ich da irgendwie was zur Verfügung stelle als CI Variable oder so, aber das wird dann sehr dünn. Wenn ich externe Secrets dafür verwende, dann ist das natürlich dann wesentlich besser und auch managebarer, wo wir eben das Thema Offboarding oder Team ändert sich oder so was besprochen haben. Das macht es natürlich auch wieder komplizierter, weil ich dann auch ein Key Management System habe, was ich dann da etablieren muss. Und ich glaube, du hast dir noch die Sealed Secrets angeguckt.

Sascha: Ja, genau. Wenn wir noch eine Lösung brauchen, wo es eigentlich nur wichtig ist, dass die Entwickler mal Secrets lokal anlegen kann, speichern kann und dem Cluster übergeben kann, danach aber nicht unbedingt mehr wieder lokal die Werte lesen muss. Dann bietet sich sowas wie Sealed Secrets an. Das Setup dort ist ähnlich wie das, was wir ein bisschen bei dem SOPS beschrieben haben. Es läuft sozusagen ein Stück Software im Kubernetes Cluster, im Operator. Der hat einen privaten Schlüssel bei sich. Und er gibt über eine API seinen Public Key raus. Es gibt zum Sealed Secrets auch noch ein kleine CLI, womit dann der Entwickler arbeitet. Der nimmt sich eine lokale Secret Ressource und sagt: Ich möchte die gerne verschlüsselt haben für diesen Cluster und er wird sozusagen mit dem Public Key von dem Operator verschlüsselt. Ich kriege dann eine andere Ressourcen Beschreibung. Ich speicher mir das lokal nicht mehr als Secret ab, sondern als Sealed Secret. Da sind die Werte auch verschlüsselt und das kann ich einchecken ohne Probleme, weil ich lokal damit nichts mehr machen kann. Der einzige, der das entschlüsseln kann, ist eigentlich der Operator, der im Cluster läuft.

Sebastian: Ja, das stimmt. Das hat einige Parallelen zu SOPS. Aber das hat einen echten Operator. Der ist nur dafür da, das zu tun?

Sascha: Genau, der macht nichts anderes. Wir haben kurz darüber geredet. Er bringt auch eine eigene Ressourcen Beschreibung mit. Im Kubernetes Umfeld nennt man das Custom Ressource Definitions, das sind Ressourcen Definitionen, die jetzt nicht Standard Kubernetes sind, die eigentlich andere Anwendungen mitbringen. Und im Rahmen von dem Operator ist sozusagen die neue Ressource das Sealed Secret. Was der Operator macht, wenn er die sieht, wenn die im Cluster angelegt wird. Der liest die Information aus dem Sealed Secret aus und erzeugt dynamisch, basierend auf der Information mit seinem Private Key eine entschlüsselte Version davon. Er erzeugt für uns im Cluster diese Secret Ressource, die man dann ganz normal verwenden kann, als Umgebungsvariablen hinzufügen kann oder mounten kann. Das geht.

Sebastian: Mountain zum Beispiel, da hätte ich ein Zertifikat zum Beispiel, wenn ich einen Webservice habe und auch ein TLS Zertifikat, das wäre dann auch eine Variante dafür, oder?

Sascha: Richtig. Es gibt nicht nur die klassischen Fälle, wo wir Secrets als Umgebungsvariable haben wollen. Theoretisch kann man in so einem Secret auch ganze Dateien speichern. Ich glaube, sie sind limitiert. Ich weiß gerade nicht die Größe. Die Secrets, können nicht beliebig groß werden. Aber solche klassischen Fälle wie ein Zertifikat ist möglich dort abzulegen. Und dann würde man anstelle des Umgebungsvariablen hinzufügen, würde man das eher als File System mounten, was auch möglich ist mit Secrets und mit ConfigMaps.

Sebastian: Das sind jetzt alles drei Varianten, die ich mehr oder weniger in der Versionskontrolle habe, wo ich das resonieren kann. Es gibt natürlich jetzt auch noch mal das sehr bekannte Ding External Secrets.

Sascha: Ja, das ist noch mal ein anderes Biest an der Stelle. Die drei davor kann man sagen, das können wir komplett selber betreiben. Wir nutzen keine Public Keys, wir haben das nur lokal am laufen. Oder wir haben diesen Operator, der auch im Cluster läuft. Der External Secrets Operator wurde eigentlich gebaut, um externe Ressourcen mit anzuziehen. Secrets liegen bei uns normalerweise nicht nur im Cluster oder nur in Git. In ganz vielen Systemen, wenn man schon bei AWS oder bei Google ist, dann nutzt man diesen nativen Secret Manager, die sie anbieten. Das heißt, irgendwo liegen schon unsere Secrets und der External Secrets Operator ist dafür da, aus diesen externen Quellen in unseren Cluster zu mappen.

Sebastian: Der klingt sehr generisch, der ist, glaube ich, auch sehr generisch, oder?

Sascha: Der ist relativ generisch. Sie versuchen zumindest bei den großen Cloud Anbietern alles abzudecken. Sie können Secrets aus Azure rausziehen, aus Google rausziehen, aus AWS rausziehen, aus IBM theoretisch auch. Wir haben versucht, so ein generischen Operator zu bauen, der aus den verschiedensten Secret Quellen Informationen ziehen kann.

Sebastian: Und den kann ich dann über die Zugriffsmethoden, die der Cloud Anbieter zur Verfügung stellt, absichern, dass die lesen können. Aber andere können reinschreiben. So kann ich das dann ganz gut steuern.

Sascha: Ich nutze das User Management, was mir der Cloud Provider zur Verfügung stellt. Und wenn die Entwickler darauf zugreifen dürfen, dann können sie es sehen. Wenn nicht, dann nicht. Der große Vorteil ist, das was ich am Ende in mein Git einchecke ist eigentlich nur ein Verweis auf den Secrets Manager. Bei Amazon wäre das so eine typische Amazon Resource Name, so ein langer Name, wo ich die Ressource mit definiere, wo der Secret drinsteckt. Das ist die einzige Information, die die Entwicklungsteams benötigen, um das einzuchecken. In dem Setup bräuchten sie theoretisch nie Zugriff auf die echten Secret, sie müssten es gar nicht sehen können. Und vom Ablauf her ist das sehr ähnlich wie die Sealed Secrets. Es ist eine eigene CRD, das ist es dann der External Secret, wo dieser Link drin steht. Wenn das deployed ist, fängt der Operator an, die Informationen aus dem externen System rauszuziehen und erzeugt für uns dann diese Secrets im Cluster mit den richtigen Werten.

Sebastian: Genau, die kann ich mir da irgendwo hinlegen lassen. Damit hätte ich dann keine Secrets mehr in Git oder in dem Versionskontrollsystem der Wahl. Das ist natürlich super. Auf der anderen Seite hat natürlich External Secrets dann sehr viele Rechte über alle meine Secrets. Das wäre natürlich noch so ein Nachteil, den man hier auf jeden Fall aufführen sollte.

Sascha: Es ist definitiv eine Abwägungssache. Es macht viele Sachen leichter. Wenn man das jetzt eher so aus dem Plattform Team Gedanken rausschaut, ist das ganze User Management einfacher, weil man kontrolliert eh schon, wer auf AWS oder Google zugreifen darf, dann ist das dieselbe Art, aber dafür ist halt der Operator relativ mächtig. Der kann viele Sachen machen. Wenn man es richtig sieht, er müsste eigentlich auf alle Secrets draufkommen, die für irgendjemanden relevant sind. Und damit ist das schon ein Einfallstor, weil wer immer die Rechte bekommt, die der Operator benutzt, kann mehr oder weniger alles machen.

Sebastian: Und wie synchronisiert er sich? Ich habe schon verschiedenste externe Systeme. Wenn ich jetzt so einen Secret Manager, AWS etwas aktualisiere, wie kriegt er das mit?

Sascha: Da gibt es verschiedene Varianten. Das ist abhängig von der Konfiguration. Der klassischste Fall ist, er pollt einfach alle drei Minuten. Alle drei Minuten macht ein API-Call, schaut, ob sich die Daten geändert haben und aktualisieren dann die Secrets. Oder wir geben ihm einen externen Trigger mit. Wir sagen: Okay, der Identifier hat sich geändert und damit erkennt eigentlich das der Operator, dass es was neues ist und würde es noch mal neu lesen. Aber es gibt keinen aktiven Trigger aus dem AWS Backends oder Google Backends, die dem sagen: Apropos, hier hat sich was geändert. Es geht entweder übers Polling oder ich mache das irgendwie indirekt, dass ich jedes Mal neue Identifier erzeuge, also neue Ressourcen erzeuge im Hintergrund, damit der Operator weiß: Da ist was Neues. Bitte leg das noch mal neu an.

Sascha: Wir können mal noch darüber reden. Das kann ein Kostenfaktor sein. Je nachdem, welchen Anbieter man so hat. Polling kann relativ teuer sein, immer wieder Zugriff zu machen. Da würde sich natürlich irgendwas anderes als Optimierung anbieten. Aber im einfachsten Fall wäre das Polling eigentlich wahrscheinlich die Variante, die man zuerst wählen würde. Aber man sollte sich dann nicht über die Rechnung wundern.

Sebastian: External Secrets pollt, was denn da vielleicht für Updates reinkommen würden. Jetzt habe ich vielleicht den Fall, ich rotierte einen Secret. Ich finde irgendein Passwort oder so und lege ein neues Passwort ab. Und das möchte ich ja nicht, dass er mir direkt mein Secret im Cluster kaputt macht, weil ich dann einen Pod neu starte oder so und der zieht das neue Secret an, dann habe ich das vielleicht in echt in der DB noch gar nicht rotiert. Was habe ich denn da für Möglichkeiten?

Sascha: Das ist eine gute Frage. Da muss man wahrscheinlich sich überlegen, wie man dann solche Secrets neu anlegt. Man kann es auch wie ein komplett eigenständige neue Secrets betrachten. Ich lege sie parallel an und entscheide dann aktiv selbst, wann ich ein neues Secret anziehe in meiner Applikation, indem ich auf die neue Secret verweise. Aus dem Stegreif fällt mir nichts ein, dass es da irgendwas Automatisiertes von External Secrets direkt gibt, weil soweit ich weiß, würde der External Secrets Operator einfach knallhart das bestehende Secret überschreiben.

Sebastian: Der AWS Manager, da kann ich die Dinger aktualisieren. Da gibt es so eine Version. Ich vermute, das kann man auch zurückrollen und so weiter. Vielleicht hat External Secrets diese Information auch irgendwo zur Verfügung.

Sascha: Es kommt manchmal noch auf das Backend drauf an, was die können. Bei AWS Secrets Manager gibt es diese Versionierung. Es gibt so eine Art Current Version und ich kann eine neue anlegen, muss aber nicht unbedingt diesen Point, diese Current wird weiter geschoben, aber ich kann auch beliebige andere Namen vergeben, für Versionen. Zum Beispiel, welche gerade für Pot verwendet wird. So ein Pot Pointer und ich kann das Script anlegen. Die Informationen, auf welche Version verwiesen wird, das kennt External Secret schon. Ich kann sagen: Ziehe bitte unter dem Identifier die Informationen raus, aber nutze bitte die Version, wo der Pointer drauf ist. Und erst wenn der verschoben wird, dann würde sozusagen neues Secret erzeugt. Diese Erzeugung im Backend kann schon getrennt passieren. Von unserem Cluster. Aber wenn die Information, wo er hin verweist, wenn die sich ändert, dann zieht der External Secrets Operator das einfach durch. Ich muss sozusagen dieses ganze Management von der Rotation wahrscheinlich außerhalb von dem Operator machen.

Sebastian: Ich meine, wir hatten ziemlich am Anfang auch gesagt, dass ich in Kubernetes auch so eine gewisse Reproduzierbarkeit haben möchte von meinem Deployment und das Secret da mit einschließt. Viele verwenden auch Customized und da gibt es auch den ConfigMap oder einen Secret Generator, wo ich dann auch so Literale angeben kann. Gut, dann sind sie wieder bei mir im Repo. Aber worauf ich hinaus will ist, dass da so ein Fingerprinting stattfindet. Da gibt es um so eine Hash Summe über die Datei, die abgelegt wird. Wenn ich das benutze und deploye, habe ich natürlich zwei Secrets für die Anwendung, aber einmal mit dem einen und mit dem anderen Hash und das eine Deployment, das alte Deployment zieht das alte Secret an, bei dem neuen wird, wenn sich der Secret geändert hat, wird es ein anderes Hash sein. Und da habe ich das dann eben auch zur Verfügung.

Sascha: Ja, vielleicht um das zu verstehen, muss man überlegen: wann werden denn die Applikationen neu gestartet in Kubernetes? Wenn wir sagen, wir haben eine Applikation, die Secrets kommen aus dieser Secrets Ressource heraus, werden als Umgebungsvariable reinge-mounted. Wenn sich diese Werte im Hintergrund ändern, wenn dieses Secrets Objekt ändert, dann wird nicht automatisch meine Applikation neu gestartet. Das ist sozusagen voneinander getrennt, weil sich der Name der Secrets nicht ändert, solange sich an dem Secrets Namen nichts ändert, läuft meine Applikation weiter und nur wenn jetzt ein Fehler auftritt oder wir wirklich gerade zufälligerweise im Deployment sind und die Applikation neu gestartet werden, würde er die neuesten Werte nehmen. Das heißt, nur das Ersetzen, das Aktualisieren der Secrets. Da passiert erst mal nichts mit meiner Anwendung und dasist eigentlich blöd.

Sebastian: Das heißt, auch der manuelle Weg wäre, wenn ich jetzt manuell im Cluster mit CubeCTL rumfuhrwerke, ich aktualisiere irgendein Secret, dann muss ich mein Deployment neustarten?

Sascha: Entweder manuell, ich stoppe die Container, also die Pods in Kubernetes und lasse sie wieder neustarten, damit er die neuen Werte bekommt. Aber es gibt erstmal keinen Standard Weg bei Kubernetes, dass er mitbekommt, dass er die Applikation neustarten muss. Dafür muss ich tatsächlich auf andere Tools zugreifen, auf andere Operator. Eins, das was man schon kennt, ist der Reloader, der genau das für uns macht. Der Reload ist ein Operator, so ähnlich wie Sealed Secrets und so weiter. Aber seine Aufgabe ist eigentlich auf Werte in den Secrets zu achten. Und wenn die sich ändern, findet er heraus, welche Applikationen eigentlich Zugriff darauf haben und startet die neu für uns. Der macht das dann dynamisch. Wenn man noch mal zu diesem Punkt zurückkommt mit Customized ist an der Stelle, da würde ich das Problem nicht haben, weil sozusagen durch dieses Fingerprinting, immer wieder neue Secrets erzeugt würden, wenn der Inhalt sich ändert und dann ändert sich automatisch die Referenz in unserem Deployment. Und durch diese Änderung der Referenz ist es eigentlich wie ein neues Deployment und alle Ports werden neu gestartet.

Sebastian: Ja, da ist dann ein Change. Operator können wir gar nicht genug haben. Es gibt noch einen, den 1Password Operator. Der funktioniert so, wenn ich ein 1Passwort Teams oder Business Account habe und so einem geshareden Vault, einen geshareden Tresor habe, dann kann ich damit dafür sorgen, wenn ich so ein paar Features in meinem Account aktiviere. Secrets Automation ist einer davon, um so eine API zu haben, kann ich den Operator von 1Password deployen und dann spiegelt er, das ist fast derselbe Mechanismus wie bei External Secrets, spiegelt er die Werte, die ich in meinem 1Password habe 1:1 in den Cluster wieder als Secret. Ich kann da auch Secrets anziehen in meinem Deployment. Genauso wie ich es bei External Secrets auch mache. Und dann kann ich die da genauso verwenden. Das sieht ein bisschen seltsam aus, das ist Key Value. Das heißt, ich benutze dann in meinem Eintrag in 1Password auch der Name, wo vorher Website steht, ist dann der Key und der Value ist der Value. Das ist sehr bequem. Es funktioniert sehr schnell. Wenn ich da irgendwas ändere, dann ist das sehr schnell auch in den Cluster reingesynct. Das finde ich ganz gut. Das birgt natürlich das Risiko. Wenn ich aus Versehen in meinem 1Password mal ein paar Einträge lösche, dann sind die natürlich auch genauso schnell gesynct. Das kann natürlich auch ein großer Nachteil sein. Ansonsten für Firmen oder für größere Installationen bin ich recht feingranular mit den Bolds (37:16) unterwegs. Da kann ich das Risiko ein bisschen aufteilen, wenn ich pro Team einen Bold (38:33) habe, das Team hat dann Zugriffskontrolle darauf und kann dann anlegen. Und hat auch die Features, die man von einem Passwort Manager kennt und irgendwelche Änderung auch rückgängig machen kann. Oder wenn ich was lösche. Am Ende ist es natürlich dann in einem Papierkorb und ich kann es da natürlich auch wiederherstellen. Aber es ist wieder ein weiteres Tool.

Sascha: Aber was man auch sagen muss, es ist losgelöst von jedem Cloud Provider an der Stelle. Wir können, was immer wieder bei größeren Firmen der Fall ist, dass wir immer so eine Art Exitstrategie brauchen von einem Cloud Provider zum nächsten. Da bindet man sich zumindest nicht an einen konkreten Provider an der Stelle. Und ich finde die Sicht des Entwicklers sehr gut darauf, weil wir kennen es schon, wie die Integration von 1Password im Browser die CLIs die wir benutzen können. Es ist schon sehr angenehm, damit zu arbeiten und jetzt können wir es dann auch für den Cluster benutzen.

Sebastian: Du hattest eben über die Größen gesprochen. Es gibt natürlich bei Secrets und Kubernetes selbst auch Größengrenzen. Wahrscheinlich haben bei den lokalen Sachen, SOPS, git-crypt, da wird es wahrscheinlich nicht so starke Größenlimitierungen geben. Nicht sinnvoll. Ich möchte keine drei Gigabyte Datei oder die JDKs, die ich so verwendet habe, mit einchecken und verschlüsseln. Das wird glaube ich nicht passieren. Aber, ich habe natürlich auch so ein bisschen das Problem. Wir haben am Anfang gesagt, es gibt ConfigMaps, es gibt Secrets. Manchmal ist das auch ein bisschen zusammengesetzt. Wenn ich jetzt an DB Connection String denke, dann habe ich dann da den Hostnamen mit drin. Vielleicht noch irgendwelche TLS Parameter soll die ganze Chain verifiziert werden oder nicht. Da würde ich jetzt so im Nachhinein, wo wir über die Tools gesprochen haben, sagen, ich habe einen Vorteil, wenn ich sehr selektiv die Sachen verschlüsseln kann.

Sascha: Ja, das hat definitiv Vorteile, auch ein bisschen aus der Wartbarkeit heraus. Wenn ich den Host jetzt theoretisch als Secret, den kompletten Connection String als Secret verpacken würde, bei jeder Änderung, ob es jetzt ein Zertifikat ist, das Passwort sich geändert hat, der Nutzer sich geändert hat oder der Host sich geändert hat, muss ich überall hinrennen, wo sich das geändert hat und für alle das anpassen. Selektiv würde bedeuten, dass das sich relativ wenig ändert. Sowas wie der Host, das ziehe ich raus. Und habe stabilere Konfigurationensparameter oder nur kleinen Sub-Set, der sich vielleicht ändert. Und muss dafür das Deployment nicht jedes Mal so oft anfassen. Der Nachteil ist, ich muss das dann in der Anwendung wieder zusammenbauen. Aber es hat schon Vorteile klar zu trennen, was sind Config Parameter, was darf querschnittlich lesen? Was sind echte Secrets und die auch getrennt voneinander speichert.

Sebastian: Wenn ich in meinen Repositories suche, wer connected sich dann zu welcher Datenbank? Und es ist alles verschlüsselt oder extern. Dann kann das was dauern, bis man alle Secrets abgeklappert hat, wenn man sie denn überhaupt alle identifiziert.

Sascha: Und man sie lesen darf.

Sebastian: Wenn man sie lesen darf. Richtig, genau. Jetzt haben wir alle möglichen Arten, wie man oder wie wir bisher auch schon mal Secrets in Kubernetes bekommen haben, mal so durchgesprochen. Ich glaube, zusammenfassend kann man festhalten, von Anfang an Secrets und Configs zu trennen, wenn das Tool es hergibt oder wenn man es selbst programmiert. Wenn man es in der Hand hat. Das Passwort separat von einem Connection String abzulegen, kann hilfreich sein. Und man muss auf jeden Fall überlegen: Wann lohnt sich welche Lösung?

Sascha: Man kann es wahrscheinlich gar nicht pauschal beantworten. Es ist immer sehr abhängig vom Kontext, wo man sich drin bewegt. Aber wahrscheinlich gibt es ein paar Kriterien, wo man überlegen kann, welche von diesen Lösungen am sinnvollsten sind. Eine Sache ist natürlich immer diese Frage: Was für ein Projekt haben wir da und welche Team Größe haben wir? Ist das Projekt bei mir daheim? Da muss ich mich jetzt nicht gleich mit dem External Secrets Operator, mit AWS herumschlagen. Da reicht wahrscheinlich auch die Schmalspurlösung, das manuell zu machen.

Sebastian: Das sprengt vielleicht auch das Hobby Budget.

Sascha: Das sprengt vielleicht auch sehr schnell das Hobby Budget. Oder wie die Teams aufgestellt sind. Habe ich eher so diesen klassischen Dev- und Betriebsansatz. Getrennt Dev und OPs oder habe ich einen DevOps Ansatz, wo das zusammen ist? Bei so einem klassischen Dev Betrieb könnte es helfen, wenn die Teams eigentlich gar nichts mit dem Secrets zu tun haben, die lokal auch gar nicht benötigen und ich mir einfach irgendwelche Identifier zur Verfügung stellen lasse. Bei DevOps, wo ich vielleicht auch mal lokal drauf schaue und die beides habe, sind wahrscheinlich Lösungen sinnvoll, wo ich auch lokal mal an die Secrets rankomme. Man muss sich überlegen: Alles, was man dazu kauft, wenn man das auslagert. Diese ausgelagerten Systeme haben alle ihre Vorteile. Sie sind darauf spezialisiert, wie das KMS, sinnvoll Keys zu verwalten, Rotationen zu machen, Zugriffskontrollen zu haben. Aber natürlich, jedes System, was man dazu holt, ist eins mehr als das, wo wir gestartet sind und das kann das ganze komplex machen.

Sebastian: Genau, eins mehr und die möchten auch upgedatet und gewartet werden.

Sascha: Richtig.

Sebastian: Genau, das kommt alles dazu.

Sascha: Und vielleicht noch so als letzten Punkt, den man mitnehmen könnte, zu überlegen, was davon sinnvoll ist. Ob ich sowas im Projekt wie Multi-Cloud Ansatz habe. Möchte ich die Chance haben, von einem Anbieter zum nächsten wechseln zu können? Dann sind natürlich externe Sourcen schwierig zu migrieren, wenn wir jetzt auf einmal übers Azure betreiben und die Secrets noch im AWS Secrets Manager liegen. Da muss ich mir auf einmal Migrationsstrategien überlegen. Das ist natürlich mit allem, was im Cluster selbst läuft, einfacher, als wenn ich jetzt nur mal das Sealed Secrets hernehmen würde, ich müsste diesen einen Prio Key umziehen von dem Operator, damit er wieder arbeiten kann. Das ist bei externen Ressourcen wie der Secrets Manager von AWS oder Google schwieriger. Das muss ich irgendwie selbst basteln.

Sebastian: Zu den erwähnten Tools und so weiter packen wir Links auch noch in die Shownotes, wen das interessiert. Dann danke ich dir, Sascha, auf jeden Fall für das Gespräch.

Sascha: Bitte, bitte.

Sebastian: Ich würde sagen, dann bis zum nächsten Mal. Tschüss.

Sascha: Bis dann. Ciao, ciao.

Senior Consultant

Sebastian Janzen ist Entwickler und Senior Consultant bei INNOQ. Er arbeitet mit Web-Technologien seit 2007. Er widmet sich am liebsten Internet of Things Projekten und agiert im Frontend sowie Backend.

Alumnus

Sascha Selzer arbeitete bis Januar 2024 als Senior Consultant bei INNOQ und verfügt über umfassende Erfahrung in der Entwicklung mit JVM-basierten Sprachen sowie in der Softwarearchitektur. Er konzentriert sich derzeit auf die Konzeption und Umsetzung von Backend-Architekturen und Continuous Delivery/Deployment-Strategien. Weiterhin interessiert er sich für Themenbereiche wie Cloud-Monitoring und -Tracing, Microservices und DevOps.