Featured image of post Secret Kubernetes depuis Azure Key Vault

Secret Kubernetes depuis Azure Key Vault

Comment stocker et utiliser les secrets Kubernetes depuis Azure Key Vault.

Introduction

La gestion sĂ©curisĂ©e des secrets dans Kubernetes est crucial pour maintenir la sĂ©curitĂ© dans nos applications. Dans cet article, je vais donc prĂ©senter la gestion des secrets dans Kubernetes en utilisant External Secrets Operator et Azure Key Vault via une authentification par workload identity. Ceci dans le but d’avoir une solution robuste et sĂ©curisĂ©.

Contexte

J’ai mis en place cette solution dans le cadre d’un projet d’une semaine durant mon master. Le but Ă©tait le dĂ©ploiement d’une stack applicative dans le cloud via un workflow GitOps. Le projet est disponible ici.

Dans ce projet, un cluster Azure Kubernetes Service (AKS) était déployé via terraform avec la configuration suivante requise pour mettre en place la solution :

1
oidc_issuer_enabled = true

âŹ†ïž Permet d’activer l’Ă©metteur OIDC (OpenID Connect) du cluster AKS. Cela signifie que le cluster AKS gĂ©nĂšre une URL d’Ă©mission de token OIDC, essentiel pour la relation de confiance que je vous prĂ©sente plus tard dans cet article.

L’OIDC est un protocole d’authentification moderne qui repose sur le standard OAuth 2.0. Il permet Ă  des applications de vĂ©rifier l’identitĂ© d’un utilisateur en s’appuyant sur un fournisseur d’identitĂ© et de rĂ©cupĂ©rer des informations sur cet utilisateur de maniĂšre sĂ©curisĂ©e.

1
workload_identity_enabled = true

âŹ†ïž Active la fonctionnalitĂ© Azure Workload Identity, pour permettre aux pods Kubernetes d’accĂ©der aux ressources Azure en utilisant les identitĂ©s managĂ©es.

Composants

  • External Secret Operator (ESO) : OpĂ©rateur Kubernetes qui permet d’intĂ©grer un systĂšme de gestion des secrets externes.
  • Azure Key Vault : Service cloud Azure permettant de stocker les secrets et d’y accĂ©der en toute sĂ©curitĂ©.
  • Workload Identity : MĂ©thode pour s’authentifier Ă  une ressource Azure sans explicitement configurer des identifiants

Azure Key Vault

DĂšs que le cluster AKS est opĂ©rationnel, il faut dĂ©ployer la ressource Azure Key Vault. Pour ce faire, j’ai utilisĂ© terraform afin de pouvoir faire de l’IaC pour fiabiliser et automatiser mon dĂ©ploiement. Pour le vault ainsi que les autres ressources Azure, j’ai utilisĂ© le provider terraform azurerm.

Le code suivant va permettre la crĂ©ation du vault dans le resource group et la location dĂ©fini avec le RBAC (Role Based Access Control) activĂ© pour manager les accĂšs et le SKU (Stock Keeping Unit) sur standard. D’autres arguments sont disponibles, mais j’ai prĂ©fĂ©rĂ© simplifier au vu de la durĂ©e du projet afin d’avoir un POC rapidement.

1
2
3
4
5
6
7
8
9
resource "azurerm_key_vault" "vault" {
  name                        = join("-", [var.prj, var.org, "vault"])
  location                    = var.location
  resource_group_name         = azurerm_resource_group.aks.name
  tenant_id                   = data.azurerm_client_config.current.tenant_id

  sku_name                    = "standard"
  enable_rbac_authorization   = true
}

Une fois le vault dĂ©ployĂ©, on peut mettre ses secrets dedans via l’UI ou la CLI d’azure.

azure-vault-ui

Azure Vault UI

Managed Identity

Une fois le vault déployé, il va falloir associer le rÎle à la bonne identité afin de pouvoir accéder à nos secrets au travers de celle-ci.

Kubelet Identity

Lors de la crĂ©ation d’un cluster AKS, une managed identity de type user assigned va ĂȘtre crĂ©Ă©e dans le resource group, celui-ci est gĂ©rĂ© automatique par Azure et permet de stocker les ressources infrastructures rĂ©elles nĂ©cessaires au fonctionnement du cluster AKS. Cette identitĂ© managĂ©e se nomme kubelet_identity et elle va permettre Ă  kubelet prĂ©sent sur les nƓuds du cluster d’accĂ©der Ă  d’autre ressource Azure. C’est au travers de cette identitĂ© que je vais pouvoir accĂ©der au vault.

diagram-kubelete-identity

Interaction entre Kubelet Identity et les ressources Azure

J’ai assignĂ© Ă  cette identitĂ© les droits de lecture sur les secrets prĂ©sents dans le vault grĂące au rĂŽle Key Vault Secrets User:

1
2
3
4
5
resource "azurerm_role_assignment" "keyvault_secrets_user" {
  scope                = azurerm_key_vault.vault.id
  role_definition_name = "Key Vault Secrets User"
  principal_id         = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id
}

FĂ©dĂ©ration d’identiĂ©

Lorsque les bons droits sont assignés, il va falloir lier cette identité à un service account dans Kubernetes afin de pouvoir accéder aux données de mon vault dans Azure.

Pour ce faire, il faut utiliser une federated identity credential qui va permettre de dĂ©lĂ©guer l’authentification Ă  un fournisseur d’identitĂ© externe dans mon cas le cluster AKS et ainsi crĂ©er une relation de confiance entre AKS et l’identitĂ© managĂ©e dans Microsoft Entra ID.

1
2
3
4
5
6
7
8
resource "azurerm_federated_identity_credential" "identity" {
  name                = "kub-federated-identity"
  resource_group_name = azurerm_kubernetes_cluster.aks.node_resource_group
  audience            = ["api://AzureADTokenExchange"]
  issuer              = azurerm_kubernetes_cluster.aks.oidc_issuer_url
  parent_id           = azurerm_kubernetes_cluster.aks.kubelet_identity[0].user_assigned_identity_id
  subject             = "system:serviceaccount:default:workload-identity-sa"
}

Ici l’audience reprĂ©sente le destinataire prĂ©vu du jeton Ă©mis par l’Ă©metteur de l’OIDC, le subject correspond Ă  l’identitĂ© de l’entitĂ© (le service account dans mon cas) Ă  laquelle l’identitĂ© fĂ©dĂ©rĂ©e est associĂ©e et issuer est l’URL d’Ă©metteur OIDC du cluster AKS.

Diagramme de séquence

Voici un diagramme un peu plus précis sur le mécanisme de connexion au Vault via identité managée et fédération :

sequence-diagram-vault

Diagramme de séquence pour la connexion au Vault

External Secrets Operator

DĂ©sormais, il faut mettre en place l’opĂ©rateur Kubernetes, External Secrets Operator (ESO) afin de pouvoir effectuer la connexion au vault via le provider Azure Key Vault fourni par ESO. Pour se faire des Customs Resources Definitions (CRD) existe et elles vont permettre de dĂ©finir comment accĂ©der au vault (Secret Store) et quels sont les donnĂ©es Ă  rĂ©cupĂ©rer (External Secret).

Secret Store

Dans cette ressource, il faut spĂ©cifier l’URL du vault, l’id du tenant Azure, le type d’authentification et le service account associĂ©. C’est avec le secret store que je vais pouvoir me connecter Ă  Azure Key Vault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: azure-secret-store
spec:
  provider:
    azurekv:
      authType: WorkloadIdentity
      vaultUrl: ${azurerm_key_vault.vault.vault_uri}
      tenantId: ${azurerm_key_vault.vault.tenant_id}
      serviceAccountRef:
        name: workload-identity-sa

External Secret

Cette ressource va permettre de dĂ©finir quel secret j’ai besoin de synchroniser entre le vault et le secret Kubernetes. Il faut dĂ©finir le secret store Ă  utiliser, notre secret cible dans Kubernetes et les secrets Ă  rĂ©cupĂ©rer depuis le vault Azure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: my-secret
spec:
  refreshInterval: 30s
  secretStoreRef:
    name: azure-secret-store
    kind: SecretStore
  target:
    name: ocf-secret
  data:
  - secretKey: pgadmin-password
    remoteRef:
      key: pgadmin-password

Service Account

Il faut Ă©galement crĂ©er le service account en lui ajoutant l’annotation suivante afin de l’associer Ă  l’ID de l’identitĂ© : Kubelet Identity.

1
2
3
4
5
6
7
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    azure.workload.identity/client-id: "${azurerm_kubernetes_cluster.aks.kubelet_identity[0].client_id}"
  name: workload-identity-sa
  namespace: default

DĂ©ploiement

Pour la partie dĂ©ploiement, je suis aussi passĂ© par du terraform en utilisant le provider helm et kubectl. Ceci permet d’avoir une infrastructure unifiĂ©e et automatisĂ©e de bout en bout.

terraform-deployment

DĂ©ploiement avec terraform

ESO

Pour ESO, une chart helm est fourni dans la documentation, celle-ci est dĂ©ployĂ©e dans le namespace external-secrets. Cette ressource terraform attend la fin du dĂ©ploiement du cluster AKS pour ĂȘtre crĂ©Ă©e grĂące au depend_on = [azurerm_kubernetes_cluster.aks].

1
2
3
4
5
6
7
8
9
resource "helm_release" "eso" {
  depends_on       = [azurerm_kubernetes_cluster.aks]
  name             = "external-secrets"
  namespace        = "external-secrets"
  repository       = "https://charts.external-secrets.io"
  chart            = "external-secrets"
  create_namespace = true
  version          = "0.10.5"
}
eso-pod-deployment

DĂ©ploiement des pods ESO

Une fois ESO dĂ©ployĂ©, il faut crĂ©er nos CRD afin de configurer la connexion au vault et les secrets Ă  rĂ©cupĂ©rer mais Ă©galement le service account. Tout ceci Ă  l’aide de manifests Kubernetes qui permettent de dĂ©clarer les ressources en yaml.

CRD et Service Account

Pour les manifests, l’utilisation du provider terraform kubectl va me permettre d’utiliser des variables des ressources terraform directement dans les manifests pour avoir quelque chose de dynamique, comme on peut voir dans ce manifest. Ceci Ă©vite alors de mettre des informations sensibles en dur dans les manifests.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
resource "kubectl_manifest" "sa" {
  depends_on = [helm_release.eso]
  yaml_body  = <<YAML
apiVersion: v1
kind: ServiceAccount
.....
YAML
}

resource "kubectl_manifest" "secretstore" {
  depends_on = [kubectl_manifest.sa]
  yaml_body  = <<YAML
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
.....
YAML
}

resource "kubectl_manifest" "externalsecret" {
  depends_on = [kubectl_manifest.secretstore]
  yaml_body  = <<YAML
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
.....
YAML
}

Les 3 ressources terraform sont dĂ©clarĂ©es, elles correspondent aux 3 manifests / ressources Kubernetes qu’il faut crĂ©er dans le cluster pour configurer et utiliser ESO.

RĂ©sultat

La connexion à Azure Key Vault est validé. Ceci grùce à la ressource secret-store.

azure-secret-store

Connexion Ă  Azure Key Vault avec le secret store

Une fois connectĂ© au vault, la synchronisation des secrets va s’effectuer. On peut le voir sur la resource external-secret qui est dans l’Ă©tat SecretSynced. Ceci va donc rĂ©cupĂ©rer les secrets du vault et les mettre dans un secret Kubernetes.

secret-sync

Synchronisation des secrets en le vault et Kubernetes

Le secret a bien Ă©tĂ© crĂ©e et il est bien prĂ©sent dans Kubernetes comme on peut le voir. Pour cette dĂ©monstration les passwords sont tous les mĂȘmes, ce qui est bien sĂ»r Ă  ne pas faire dans un environnement de production.

diagram-kubelete-identity

Secret Kubernetes

Conclusion

La mise en place de cette solution sur un temps restreint a Ă©tĂ© un rĂ©el challenge pour moi, car je n’avais jamais rĂ©alisĂ© ceci auparavant. J’ai pu travailler et approfondir mes compĂ©tences sur Azure et plus spĂ©cifiquement les rĂŽles et identitĂ©s de ce cloud provider.

L’objectif a Ă©tĂ© atteint, et la complexitĂ© de la solution m’a motivĂ© Ă  rĂ©diger cet article, premiĂšrement afin d’avoir une trace de cette rĂ©alisation en faisant un retour d’expĂ©rience, mais Ă©galement dans le but de pouvoir aider les personnes qui tomberont tĂŽt ou tard dessus.

Généré avec Hugo
ThÚme Stack conçu par Jimmy