> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Comment installer et configurer Vault Secrets Operator sur GKE avec Terraform et FluxCD
- URL: https://www.sfeir.dev/cloud/comment-installer-vault-secrets-operator-sur-kubernetes/
- Published: 2024-06-17T14:40:41.000Z
- Updated: 2024-06-18T09:52:00.000Z
- Description: Cet article explique comment installer et configurer Vault Secrets Operator sur un cluster GKE en utilisant Terraform et FluxCD.
- Author: Antoine Méausoone
- Tags: DevOps, Architecture, Cloud, Vault

Vault Secrets Operator est disponible depuis quelques mois. Il s'agit de l'opérateur Kubernetes officiel pour la synchronisation des secrets entre Vault et [Kubernetes](https://www.sfeir.dev/kubernetes-definition/). 

Dans cet article, nous allons voir comment installer et configurer Vault Secrets Operator sur Kubernetes et plus précisément: comment configurer l'authentification sur Vault, le déploiement de l'opérateur VSO, ainsi que les CRDs associés pour synchroniser des secrets Kubernetes. Les clusters GKE et Vault sont déjà déployés, nous allons utiliser FluxCD pour le déploiement des manifests Kubernetes et faire cela as code, avec l'aide de [Terraform](https://www.sfeir.dev/cloud/les-modules-terraform-dans-un-gros-projet-comment-nous-lavons-decompose/).

## Créer un secret dans Vault

Nous allons commencer par créer un *Secret Engine* de type *KVv2* (Key-Value v2)... 

```hcl
resource "vault_mount" "kvv2" {
  path        = "secret-kv"
  type        = "kv"
  options     = { version = "2" }
  description = "KV Version 2"
}
```

...et un secret dans Vault que l'on synchronisera dans Kubernetes.

```hcl
resource "vault_kv_secret_v2" "secret" {
  mount               = vault_mount.kvv2.path
  name                = "my-application/bdd-access"
  data_json           = toJson({user="username", password="secret-pass"})
  delete_all_versions = true
}

```

## Configurer l'authentification Vault

Pour que Kubernetes puisse s'authentifier sur Vault, il y a 2 méthodes (nommé *AuthMethod* dans le vocabulaire Vault) : via l'*AuthMethod* [kubernetes](https://developer.hashicorp.com/vault/docs/auth/kubernetes?ref=sfeir.dev) ou via l'*AuthMethod* [JWT/OIDC](https://developer.hashicorp.com/vault/docs/auth/jwt?ref=sfeir.dev). 

L'*AuthMethod* JWT présente plusieurs avantages : ne pas nécessiter de connexion depuis Vault vers l'api-server du cluster Kubernetes (*TokenReview*) et ne pas nécessiter de conserver de *credentials* côté Vault. 

Nous allons donc utiliser cette méthode d'authentification.

### 1er étape: récupérer la configuration OpenID du cluster GKE

Nous avons besoin des certificats publics du service OpenID Connect du cluster GKE. Ces informations sont disponibles sur un [endpoint](https://cloud.google.com/kubernetes-engine/docs/reference/rest?ref=sfeir.dev#rest-resource:-v1.projects.locations.clusters.well-known) de Google Cloud. Mais il n'y a actuellement pas de ressource Terraform dans le provider Google qui permette de récupérer ces informations. Il y a d'ailleurs une [issue ouverte](https://github.com/hashicorp/terraform-provider-google/issues/10603?ref=sfeir.dev) à ce sujet.

Solution : nous avons développé un provider *custom* pour récupérer ces informations, qui va lire le certificat (au format JWKS) et le transformer dans le format attendu par Vault (PEM).

Vous pouvez trouver ce provider sur la registry publique sous le nom : [alex-ikse/wellknownoidc](https://registry.terraform.io/providers/alex-ikse/wellknownoidc/latest?ref=sfeir.dev)

```hcl
data "wellknownoidc_document" "k8s" {
  discovery_url = "https://container.googleapis.com/v1/projects/${var.gcp_project_id}/locations/${var.gke_region}/clusters/${var.gke_cluster_name}"
}

data "wellknownoidc_jwks" "k8s" {
  jwks_uri = data.wellknownoidc_document.k8s.jwks_uri
}
```

### Configurer la connexion dans Vault

Avec ces informations, nous allons donc créer une authentification de type JWT sur Vault, en reprenant les certificats publics de notre service OpenID Connect.

```hcl
resource "vault_jwt_auth_backend" "kubernetes_jwt" {
  path      = "jwt/kubernetes/gke-cluster"
  tune {
    default_lease_ttl = "1m"
    max_lease_ttl     = "1m"
    token_type        = "batch"
  }
  jwt_validation_pubkeys = data.wellknownopenidconfiguration_jwks.k8s.pem
}
```

Nous allons créer une policy qui va indiquer quels sont les droits sur Vault pour notre *service account* *kubernetes*. Ici, des droits en lecture seule (`read`), dans le *secret engine* (de type key-value) `secret-kv` sous le chemin `my-application` et tous les secrets en dessous.

```hcl
resource "vault_policy" "app_policy" {
  name = "my-application-policy"
  policy = <<EOT
  path "secret-kv/data/my-application/*" {
    capabilities = ["read"]
  }
  EOT
}
```

Nous allons finalement créer un rôle qui va faire le liant entre l'authentification JWT que nous avons créé précédemment, la *policy* en *read-only*, l'*audience* que nous allons spécifier avec l'authentification et le *subject* qui sera spécifier par le service OpenID Connect de GKE lors de la génération du JWT.

```hcl
resource "vault_jwt_auth_backend_role" "role" {
  backend         = vault_jwt_auth_backend.kubernetes_jwt.path
  role_name       = "my-application/vault-secrets-syncer"
  token_policies  = ["my-application-policy"]
  # TODO changer perimeter
  bound_audiences = [var.perimeter]
  bound_subject   = "system:serviceaccount:my-application:vault-secrets-syncer"
  user_claim      = "sub"
  role_type       = "jwt"
}
```

## Déployer l'opérateur Vault Secrets Operator dans GKE

Vault Secrets Operator est disponible depuis quelques mois, la dernière version étant la [v0.7.1](https://github.com/hashicorp/vault-secrets-operator/releases/tag/v0.7.1?ref=sfeir.dev). La documentation est disponible ici: [developer.hashicorp.com/vault/docs/platform/k8s/vso](https://developer.hashicorp.com/vault/docs/platform/k8s/vso?ref=sfeir.dev). 

Pour FluxCD, nous allons référencer le repository Helm de Hashicorp : 

```yaml
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: vso
  namespace: vault-system
spec:
  interval: 60m
  url: https://helm.releases.hashicorp.com
```

Puis nous allons déployer l'opérateur : 

```yaml
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: vso
spec:
  releaseName: vso
  targetNamespace: vault-system
  timeout: 10m
  interval: 10m
  chart:
    spec:
      chart: vault-secrets-operator
      version: 0.4.3
      sourceRef:
        kind: HelmRepository
        name: vso
        namespace: vault-system
      interval: 1m
  values:
    fullnameOverride: vso
    defaultVaultConnection:
      enabled: true
      address: https://vault.mycompany.com/
```

## Configurer l'authentification sur Vault depuis Kubernetes

Une fois notre opérateur déployé, nous allons configurer comment Kubernetes va concrètement s'authentifier sur Vault.

Une fois authentifié sur Vault, il est nécessaire d'avoir un rôle pour y associer des policies, donc nous allons d'abord créer un rôle sur Vault : 

Il nous faut d'abord un service account Kubernetes, qui va être l'identité utilisée pour se connecter à Vault.

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: vault-secrets-syncer
  namespace: my-application
```

Que nous allons utiliser dans la resource `VaultAuth` qui va indiquer à l'opérateur Vault comment s'authentifier au serveur Vault.

```yaml
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: my-application-vault-auth
  namespace: my-application
spec:
  method: jwt
  mount: jwt/kubernetes/gke-cluster
  namespace: my-application
  jwt:
    role: my-application/vault-secrets-syncer
    serviceAccount: vault-secrets-syncer
    audiences:
    #TODO corrigé 
      - {{ gitops_repo.perimeter }}
    tokenExpirationSeconds: 600
```

Et finalement, nous allons créer la resource `VaultSecrets` qui va faire concrètement la synchronisation du secret entre Vault et GKE.

```yaml
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
  name: user-pg
  namespace: my-application
spec:
  type: kv-v2
  refreshAfter: 30s
  # Let to true to detect drift detection
  hmacSecretData: true
  # The name of the authentication used to connect to vault,
  vaultAuthRef: my-application-vault-auth
  mount: secret-kv
  path: my-application/bdd-access
  # The destination of the secret
  destination:
    name: my-secret-bdd-user
    create: true
  # It's possible to restart your application automatically once the secret has roll out.
  rolloutRestartTargets:
    - kind: Deployment
      name: my-application-deployment
```

### Et voilà un schéma qui résume toute la procédure

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2024/06/image-1.png)

Schéma résumant la procédure à suivre

Cet article explique comment installer et configurer Vault Secrets Operator sur un cluster GKE en utilisant Terraform et FluxCD. Il couvre la configuration de l'authentification via JWT, le déploiement de l'opérateur VSO, et la synchronisation des secrets entre Vault et Kubernetes. Grâce à cette méthode, vous pouvez gérer vos secrets de manière sécurisée et automatisée, assurant ainsi une meilleure sécurité et efficacité des déploiements sur Kubernetes.