Bezpečné ukládání a externí správa konfiguračních hodnot v Kubernetes

8. 11. 2022
Doba čtení: 5 minut

Sdílet

Autor: Depositphotos
V běžících aplikacích je kladen čím dál větší důraz na bezpečné ukládání a manipulaci s citlivými konfiguračními hodnotami. Ty se do aplikace vkládají většinou jako proměnné a zajišťují třeba napojení na externí služby.

Dávno jsou pryč časy jednoduchých textových souborů, kde byly tyto hodnoty uloženy. Kam tyto hodnoty vhodně a bezpečně uložit by měla zodpovědně řešit každá firma nebo projekt, kde se vyvíjí nová aplikace či spravuje stávající infrastruktura.

Co se dozvíte v článku
  1. External Secrets
  2. Ukázka
  3. Test
  4. Automatické načítání změn

V poslední době získává na popularitě orchestrace a správa aplikací pomocí platformy Kubernetes, proto se v tomto článku zaměříme na tuto platformu a práci s citlivými hodnotami (secrets) pomocí nástroje external-secrets.

Kubernetes přímo nabízí a doporučuje objekt Secret, do kterého je vhodné tyto hodnoty ukládat. Na rozdíl od objektu ConfigMap, který slouží primárně pro ukládání běžných a necitlivých konfiguračních hodnot.

Ukládání Kubernetes manifestů včetně definice citlivých hodnot v gitovském repozitáři není ideální, jelikož tyto citlivé hodnoty by zde byly uloženy a navzdory možnostem omezení přístupu podle rolí (RBAC) mohou být  k dispozici případným útočníkům a komukoli, kdo k tomuto repozitáři má přístup, včetně historie, i když už byly hodnoty například smazány.

Logicky by bylo tedy vhodné tyto hodnoty vkládat dynamickým způsobem. Navíc pokud je více prostředí nebo samotných aplikací – může chybějící či nevhodný nástroj na správu hesel pěkně znepříjemnit a zkomplikovat život.

Naopak, pokud se zvolí správný a robustní správce hesel, který si vezme na starost správu těchto hodnot, usnadní to práci administrátorů a zároveň to přinese i značné zvýšení bezpečnosti. 

External Secrets

Jaké máme možnosti? Pro své řešení jsme si zvolili open-source nástroj external-secrets, který integraci s Kubernetes nativně nabízí. V rámci Kubernetes objektu – ExternalSecret definujeme název nebo cestu k secretu, který máme uložený v externím uložišti (v našem případě cloudu).

Pro ten si nástroj sáhne a dynamicky ho vloží do objektu – Secret, který pak můžeme využít v rámci konfigurace aplikace. Nástroj běží jako služba kontinuálně a pravidelně kontroluje aktuální hodnotu. V případě, že se změní – například dojde k její aktualizaci – nahraje opět novou hodnotu do objektu Secret.

Autor: Vojtěch Kijenský

Nástroj external-secrets nabízí integraci pro všechny poskytovatele veřejných cloudů a jejich systémy správy secretů.

Například:

  • AWS – Parameter Store a Secret Store
  • Google Cloud – Secrets Manager
  • Azure – KeyVault
  • Hashicorp Vault

 Výhody uložení citlivých hodnot v cloudu jsou:

  • Šifrování secretů při přenosu a jejich uložení,
  • přístup k secretům je logovaný a auditovatelný,
  • změny hodnot mohou být verzovány – lze se vrátit k předchozí verzi,
  • secrety se mohou jednoduše rotovat.

V rámci ukázky si předvedeme napojení na Azure Keyvault.

Další alternativy

  • Sealed Secrets – umožňuje uložení citlivých údajů přímo v repozitáři, hodnoty se pak dešifrují přímo v Kubernetes pomocí běžícího controlleru a ukládají se také jako Secret
  • SOPS – také umožňuje uložení citlivých údajů přímo v repozitáři – narozdíl od Sealed Secrets však nevyžaduje běžící službu v Kubernetes – dešifrování probíhá před samotným deploymentem do Kubernetes například v rámci pipeliny
  • Aplikační závislost – použití např. Azure KeyVault SDK pro .NET/Java, kdy aplikace referencuje secret store přímo. Nevýhodou je explicitní závislost aplikace na jednom druhu secret storu např. KeyVault a v důsledku i vendor lock.

Ukázka

Co potřebujeme mít připravené, než začneme:

  • Účet Azure a přístup k CLI,
  • azure-cli – nástroj pro příkazovou řádku,
  • běžící Kubernetes cluster (v našem případě verze 1.2×),
  • Helm – external-secrets budeme instalovat pomocí Helmu.

Nastavení prostředí Azure

Service Principal

Vytvoříme novou resource groupu:

az group create --location westeurope --name es-example

Dále vytvoříme novou Active Directory aplikaci – service principala:

AD_APP_ID=$(az ad app create --display-name es-example --query appId | tr -d \")

Vygenerujeme si heslo pro SP. Uložte si výstup tohoto příkazu, kde máte appId, password a tenant ID, které dále použijeme:

az ad app credential reset --id $AD_APP_ID

{
  "appId": "xxxxxxx",
  "password": "xxxxxxx",
  "tenant": "xxxxxxx"
}

Azure KeyVault

Vytvoříme samotný KeyVault:

az keyvault create --location westeurope --name es-example --resource-group es-example

Zkušební Keyvault secret s hodnotou „test“:

az keyvault secret set --name es-example --vault-name es-example --value test

Nastavíme policy, aby k němu mohl nově vytvořený SP přistupovat:

az keyvault set-policy--name es-example--spn $AD_APP_ID --secret-permissionsget

Nyní máme service principala a Keyvault nastavený.

Poznámka: v tomto případě autorizace na Azure probíhá skrze SP a jeho ClientId a ClientSecret, který má životnost maximálně dva roky a není proto vždy vhodnou volbou (vzhledem k nutnosti manuální rotace) oproti preferovanému použití Managed identity nebo Workload identity federation (v době psaní článku pouze preview verze).

Konfigurace Externals Secrets

Nainstalujeme external-secrets pomocí Helmu:

helm repo addexternal-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace
kubectl get pods -n external-secrets
NAME                                               READY   STATUS    RESTARTS   AGE
external-secrets-8f7d97cb-nb29s                    1/1     Running   0          4m43s
external-secrets-cert-controller-bd9964f5d-lpzbv   1/1     Running   0          4m43s
external-secrets-webhook-94f6c58f5-htw5h           1/1     Running   0          4m43s

V rámci Kubernetes si vložíme získaný appId a secret do Kubernetes secretu:

kubectl create secret generic azure-secret-sp --from-literal=ClientID=<appId> --from-literal=ClientSecret=<password>

Pro napojení na Azure Keyvault potřebujeme vytvořit SecretStore. Doplníme tenantId:

cat << EOF | kubectl apply -f -
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: azure-backend
spec:
  provider:
    azurekv:
      tenantId:
      vaultUrl: "https://es-example.vault.azure.net"
      authSecretRef:
        clientId:
          name: azure-secret-sp
          key: ClientID
        clientSecret:
          name: azure-secret-sp
          key: ClientSecret
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: es-example
spec:
  secretStoreRef:
    kind: SecretStore
    name: azure-backend
  target:
    name: azure-secret
  data:
  - secretKey: es-example
    remoteRef:
      key: es-example
EOF

Test

Nyní zkontrolujeme status, jestli se external-secrets bylo schopné připojit na Azure Keyvault:

kubectl get es
NAME         STORE            REFRESH INTERVAL   STATUS         READY
es-example   azure-keyvault   1h                 SecretSynced   True

Necháme si vypsat hodnotu secretu:

kubectl get secret azure-secret -o jsonpath='{.data.es-example}' | base64 -dtest

Vidíme, že připojení proběhlo úspěšně a hodnota se správně propsala do secretu.

Automatické načítání změn

V této velmi jednoduché ukázce jsme si ukázali možnost dynamického vkládání do Kubernetes secretu pomocí nástroje external-secrets. 

Konfigurační hodnoty jsou bezpečně drženy v externím službě Azure KeyVault a external-secrets se nám sám automaticky stará o propagování hodnot do provozního prostředí, aniž by hodnoty exponoval.

Téměř dokonalé. Proč „téměř“? Je i zde prostor pro zlepšení? Ano, aktuálně je potřeba při aktualizaci hodnoty secretu pro načtení pody aplikace restartovat. Toto je možné automatizovat například dalším nástrojem Reloader, který dokáže rozpoznat změnu secretu v Kubernetes a automaticky všechny pody aplikace restartovat, tak aby si nové změny načetly. To si ale necháme na příště.

Autor článku

Pracuje v technologické společnosti Cleverlance na pozicích DevOps Lead a Cloud Solution Architect. Aktuálně se věnuje především vývoji projektů pro automotive v rámci značek koncernu Volkswagen AG.