Secrets in Kubernetes: CSI Driver vs. ESO

12.06

In onze blogs over Workload ID legden we uit hoe je veilig kan authenticeren bij Azure services vanuit AKS, zónder langlevende secrets. Sowieso een best practice voor Azure-authenticatie, maar wat doe je met andere secrets die je applicaties nodig hebben? Denk aan API keys voor externe diensten, wachtwoorden voor systemen zonder Entra ID integratie, of andere gevoelige configuratiedata. 

Standaard Kubernetes Secret objecten zijn hiervoor niet ideaal, dus je beheert ze beter centraal in een externe kluis zoals Azure Key Vault. Maar hoe krijg je ze dan op een veilige en makkelijk te managen manier beschikbaar voor je pods in AKS? Twee populaire tools komen hier om de hoek kijken: de Secrets Store CSI Driver en de External Secrets Operator (ESO). Laten we ze vergelijken.

Waarom schieten Kubernetes Secrets tekort?

Voordat we de tools induiken, nog even kort waarom de standaard Kubernetes Secret objecten problematisch zijn voor gevoelige data: 

  • De data in een secret is standaard enkel Base64 encoded. Het valt dus makkelijk te decoderen door iedereen die toegang heeft tot het object via de Kubernetes API. 
  • De encoded data wordt opgeslagen in etcd, de database van Kubernetes. Hoewel managed services zoals AKS standaard encryptie-at-rest toepassen op etcd, blijft het secret via de API leesbaar. In clusters die zelf beheerd worden staat etcd-encryptie niet standaard aan, dus dit kan al snel over het hoofd gezien worden. 
  • Logisch, maar Base64-encoded secrets direct in je Git repository opslaan is natuurlijk verre van veilig. Lees er zeker onze GitOps repository blog eens op na voor meer info!

Secrets Store CSI Driver: flexibiliteit troef 

De Secrets Store CSI Driver is een specifieke implementatie van de Container Storage Interface (CSI) standaard voor secrets. Je installeert de driver op je cluster en configureert dan per applicatie of namespace een SecretProviderClass custom resource. Die resource definieert vervolgens welke secrets uit welke externe provider (in ons geval dus Azure Key Vault) gehaald moeten worden. 

De CSI Driver biedt twee manieren om de secrets beschikbaar te maken voor je pod: 

Als volume mount

De secrets worden als bestanden gemount in een (tijdelijk, in-memory) volume direct binnen de pod. Het grote voordeel hiervan is dat er nooit een Kubernetes Secret object wordt aangemaakt. De gevoelige data komt dus niet in de Kubernetes API of etcd terecht. Dit is de veiligste optie, zeker als je twijfelt over etcd-encryptie. De keerzijde is dat je applicatie moet aangepast zijn om secrets uit bestanden te kunnen lezen.

Als Kubernetes Secret

Je kan er ook voor zorgen dat er een standaard Kubernetes Secret object wordt aangemaakt of bijgewerkt met de waarden uit Key Vault. Dat doe je door de SecretProviderClass custom resource aan te vullen met de secretObjects property. Dit is handig voor applicaties die environment variables verwachten (die je dan vanuit dit secret kan mounten), maar het betekent wel dat het (Base64 encoded) secret weer in de API en (versleuteld in AKS) etcd bestaat.

In beide gevallen zijn de secrets pas beschikbaar nadat de pod is gestart en de CSI Driver zijn werk heeft gedaan, dus applicaties die hun secrets direct bij het opstarten nodig hebben kunnen problemen ondervinden. Een veelgebruikte workaround is het gebruik van init containers die wachten tot de secrets beschikbaar zijn voordat de hoofdapplicatie start, maar dat voegt wat extra complexiteit toe. 

De driver kan (via enableSecretRotation) periodiek controleren op updates in Key Vault. Als je volume mounts gebruikt, worden de bestanden bijgewerkt, maar je applicatie moet die dan wel opnieuw kunnen inlezen. Bij een sync naar een Kubernetes secret wordt dat object geüpdatet. 

External Secrets Operator (ESO): makkelijk en direct beschikbaar 

De External Secrets Operator (ESO) pakt het anders aan. Het is een Kubernetes Operator die continu waakt over specifieke custom resources: 

  • SecretStore (of ClusterSecretStore): hier definieer je de verbinding met je externe secret manager, zoals Azure Key Vault. Cruciaal is dat je hier ook de authenticatiemethode configureert, bij voorkeur Workload ID voor Azure Key Vault. 
  • ExternalSecret: In deze resource specificeer je welke secrets uit de geconfigureerde SecretStore je wil synchroniseren, en naar welk Kubernetes Secret object ze geschreven moeten worden.  
  • Via refreshInterval kan je bepalen hoe vaak die sync gebeurt. Hou er rekening mee dat je de pod mogelijk moet herstarten om je wijzigingen te zien, afhankelijk van je de environment variables mount. 

ESO synchroniseert secrets altijd naar een standaard Kubernetes Secret object: ofwel creëert het een nieuwe secret, ofwel werkt het een bestaande bij. Er is dus geen tweede optie zoals bij de CSI Driver. Daarom is het belangrijk dat je altijd etcd encryption-at-rest hebt ingeschakeld, maar dat is standaard het geval in AKS. 

Omdat de operator het Secret object onafhankelijk van je pods managet en synchroniseert, is het secret al beschikbaar op het moment dat je pod start. Je applicatie kan dus direct environment variables gebruiken die gemount zijn vanuit dit door ESO beheerde Kubernetes secret. Dat is meteen ook waarom we vaker ESO gebruiken in onze AKS-omgevingen.

Sealed Secrets: een derde optie? 

Een andere tool die je soms tegenkomt is Sealed Secrets. Die werkt nog eens anders: je encrypteert je Kubernetes Secret manifest lokaal met een publieke sleutel. Het resultaat (een SealedSecret object) kun je veilig in Git committen. Een controller in de cluster met de private sleutel kan dit weer decoderen naar een normaal Secret.  

Sealed Secrets lost dus het probleem van secrets in Git op, maar het biedt geen integratie met externe managers zoals Key Vault voor centraal management en rotatie. Zeker een optie als je geen externe store gebruikt, maar minder krachtig dan CSI/ESO in dat scenario. We raden het dus ook niet meteen aan. 

Workload ID: sowieso een aanrader 

Een belangrijk punt dat voor zowel CSI Driver als ESO geldt: om veilig te communiceren met Azure Key Vault, raden we je aan om Workload ID te gebruiken. Dit zorgt ervoor dat de synchronisatie-tool zelf geen (langlevende) credentials nodig heeft om bij Key Vault te kunnen.  

Het koppelt de Service Account van de CSI-driver pod of de ESO-operator pod aan een Azure Managed Identity met de juiste rechten op Key Vault. Zo blijft de hele keten, van externe store tot pod, werken zonder secrets. Alle details over Workload ID kan je terugvinden in onze tweedelige blog. 

Hoe kies je de juiste tools? 

Voor de secrets die je niet kunt vermijden met Workload ID, zijn de standaard Kubernetes Secret objecten te riskant en ongeschikt voor GitOps. De beste aanpak is om alles centraal te managen in Azure Key Vault en het te synchroniseren naar je cluster met de juiste tool. 

Zowel de Secrets Store CSI Driver als de External Secrets Operator (ESO) bieden hiervoor een goede oplossing, idealiter in combinatie met Workload ID voor de authenticatie naar Key Vault.  

De CSI Driver biedt de ultieme security met zijn volume mount optie (geen Kubernetes Secrets dus), maar is ook complexer zijn door app-compatibiliteit en het startup-probleem. ESO is vaak eenvoudiger in gebruik, lost het startup-probleem op, maar slaat het secret altijd op als een (in AKS versleuteld) Kubernetes Secret. 

De keuze zal dus afhangen van jouw balans tussen security, de eisen van je applicaties, en het gebruiksgemak. Bij CloudFuel maken we meestal gebruik van ESO, zeker in de context van een managed AKS-omgeving.

Heb je hulp nodig bij het kiezen of implementeren van jouw secret management aanpak? Neem contact op met ons, we helpen je graag verder. 

Smokescreen