Files
tools/hashicorp-vault/iac/modules
arcodangeandClaude Opus 5 ec71571b98
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Detect changed charts (pull_request) Successful in 16s
MinIO / Auth with gitea for vault (pull_request) Failing after 8m32s
MinIO / Tofu - minio IAC (pull_request) Has been skipped
MinIO / Auth with gitea for vault (push) Failing after 8m31s
MinIO / Tofu - minio IAC (push) Has been skipped
Helm Charts / Library charts tool (push) Has been cancelled
Helm Charts / Application charts pgcat (push) Has been cancelled
Hashicorp Vault / Auth with gitea for vault (push) Has been cancelled
Hashicorp Vault / Tofu - Vault IAC (push) Has been cancelled
Helm Charts / Library charts tool (pull_request) Has been skipped
Hashicorp Vault / Auth with gitea for vault (pull_request) Failing after 8m32s
Hashicorp Vault / Tofu - Vault IAC (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
refactor(minio) — chacun son périmètre : les buckets se déclarent depuis le dépôt de l'app
« Les buckets sont à déclarer dans le repo de kadans-api. On ne va pas modifier
le repo tools à chaque changement d'application. Chacun son périmètre. Tools
peut proposer un module pour standardiser la déclaration de buckets à la
limite, mais c'est tout. » (fondateur, 26/07)

C'est une erreur de fond de ma part : j'avais fait de `tools` le PROPRIÉTAIRE de
déclarations qui appartiennent aux applications. À ce rythme, chaque nouveau
bucket de n'importe quelle app devenait une PR sur l'infra partagée.

CE QUI CHANGE. `consumers.tf` disparaît, et la liste de buckets du chart se vide.
À la place, un module réutilisable `iac/modules/minio_app` : une app lui donne
son nom et ses buckets, et reçoit des buckets privés, un compte de service qui
ne peut rien toucher d'autre, et ses clés dans `kvv2/minio/<app>`.

L'OBSTACLE, ET SA RÉPONSE. Déclarer ses buckets depuis son propre dépôt suppose
des droits d'ADMINISTRATION sur MinIO. Confier le root serait absurde : il lit et
écrit tous les objets de toutes les apps. `tools` fournit donc un compte
PROVISIONNEUR aux droits minimaux — créer un bucket, une politique, un compte de
service — et AUCUN droit sur les objets. Une app compromise pourrait créer des
buckets (une nuisance), pas lire les vidéos d'une autre. Le root, lui, ne sort
toujours pas de ce pipeline.

Le rôle CI de chaque app gagne la lecture de `kvv2/data/minio/provisioner` dans
`app_policy` — générique, et c'est exactement le genre de standardisation qui
appartient au dépôt commun.

⚠ CE QUE JE N'AI PAS PU PROUVER : les noms d'actions d'administration MinIO de la
politique du provisionneur viennent de la documentation, pas d'un essai — je n'ai
pas d'identifiants admin en main. Le premier `apply` les confirmera ou les
corrigera. C'est le seul point non vérifié de cette PR, et il est signalé dans le
code à l'endroit exact.

tofu fmt propre · tofu validate réussi sur minio/iac ET hashicorp-vault/iac.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-26 10:07:05 +02:00
..
2025-12-09 12:14:57 +01:00

Modules

app_policy

Ce module à déclarer dans ce projet permet au projet subordonné de déclarer le module app_roles suivant.

Ce module Terraform associe un projet Git à un ensemble de ressources Vault :

  • Une policy -ops pour la CI/CD du projet (dépôt Git).
  • Une policy app pour le runtime applicatif (pods).
  • Un groupe Vault lié au projet. (pour ajouter les utilisateurs vault associé à leur compte gitea)
  • Un rôle JWT Vault lié à ton SCM (ex: Gitea).
  • Les droits nécessaires pour gérer les rôles Kubernetes et Postgres associés au projet.

🚀 Usage

module "webapp_vault" {
  source = "./modules/vault_project"
  name   = "webapp"

  gitea_app_id = "my-gitea-oauth-app-id" # secret récupéré via vault dans la CI
}

app_roles

Ce module Terraform configure les rôles Vault nécessaires pour quune application déployée dans Kubernetes puisse :

  • sauthentifier auprès de Vault via son ServiceAccount,
  • obtenir des identifiants Postgres dynamiques,
  • accéder à ses secrets dans Vault.

🚀 Usage

module "webapp_vault_app" {
  source = "./modules/vault_app"
  name   = "webapp"
  database = "mydb" # optionnel, par défaut = name
}

principe

                          +-----------------+
                          |   Dépôt Git     |
                          | (CI/CD Terraform|
                          +--------+--------+
                                   |
                          [Auth via Vault JWT Role]
                                   |
                        +----------v-----------+
                        | Vault (Policy -ops) |
                        |   - Peut gérer      |
                        |     - Roles K8s     |
                        |     - Roles Postgres|
                        |     - Secrets KV    |
                        +----------+-----------+
                                   |
                        [Token éphémère CI/CD]
                                   |
                  +----------------v----------------+
                  | Kubernetes API                  |
                  | - Applique CRDs / Secrets       |
                  | - Configure Longhorn / RBAC     |
                  +---------------------------------+


   --------------------------- Flux runtime ---------------------------

                          +-----------------+
                          |     Pod App     |
                          | (SA: webapp)    |
                          +--------+--------+
                                   |
                        [Auth via Vault K8s Role]
                                   |
                        +----------v-----------+
                        | Vault (Policy app)  |
                        |   - Peut lire       |
                        |     - kvv2/data/... |
                        |     - postgres/...  |
                        +---------------------+
                                   |
                        [Secrets dynamiques: PW DB, etc.]
                                   |
                          +--------v---------+
                          |   Postgres DB    |
                          +------------------+

documentation destinée aux dépots des applications:

🔑 Gestion des secrets avec Vault Secrets Operator (VSO)

Ce repository utilise Vault Secrets Operator pour gérer les secrets de lapplication (notamment les identifiants Postgres).
Lobjectif est d’éviter de stocker des credentials statiques, en déléguant la génération et la rotation à HashiCorp Vault.


⚙️ Architecture

  1. Terraform côté admin configure Vault :

    • un backend Postgres (postgres/) connecté à la base via pgbouncer,
    • un rôle Vault webapp (postgres/roles/webapp) qui définit la manière dont les credentials dynamiques sont créés,
    • un rôle Kubernetes webapp (auth/kubernetes/role/webapp) qui autorise le ServiceAccount webapp du namespace à sauthentifier auprès de Vault.
  2. Lapplication (dans ce repo) déclare :

    • un VaultAuth qui associe le ServiceAccount webapp au rôle Vault webapp,
    • un VaultDynamicSecret qui demande un secret dynamique (postgres/creds/webapp),
    • un Secret Kubernetes généré automatiquement par VSO (vso-db-credentials), injecté dans le Pod de lapplication.

🛠️ Ressources déployées

VaultConnection

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultConnection
metadata:
  finalizers:
  - vaultconnection.secrets.hashicorp.com/finalizer
  labels:
  name: default
  namespace: {{ .Release.Namespace }}
spec:
  address: http://hashicorp-vault.tools.svc.cluster.local:8200
  skipTLSVerify: false

VaultAuth

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
  name: auth
  namespace: {{ .Release.Namespace }}
spec:
  vaultConnectionRef: default
  method: kubernetes
  mount: kubernetes
  kubernetes:
    role: webapp
    serviceAccount: {{ include "webapp.serviceAccountName" . }}
    audiences:
      - vault

Permet à VSO (et donc à lapp) de sauthentifier auprès de Vault avec le rôle webapp.

VaultDynamicSecret

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
  name: vso-db
  namespace: {{ .Release.Namespace }}
spec:
  mount: postgres
  path: creds/webapp   # chemin du rôle dynamique Postgres
  destination:
    create: true
    name: vso-db-credentials
  rolloutRestartTargets:
  - kind: Deployment
    name: {{ include "webapp.fullname" . }}
  vaultAuthRef: auth

Demande un secret dynamique Postgres depuis Vault et le stocke dans un Secret Kubernetes nommé vso-db-credentials. Le Deployment de lapp est redémarré automatiquement à chaque rotation de credentials.

📦 Consommation du secret Une fois VSO en place, les credentials Postgres sont disponibles dans le Secret Kubernetes :

apiVersion: v1
kind: Pod
metadata:
  name: example
spec:
  containers:
  - name: app
    image: myapp:latest
    env:
      - name: DB_USERNAME
        valueFrom:
          secretKeyRef:
            name: vso-db-credentials
            key: username
      - name: DB_PASSWORD
        valueFrom:
          secretKeyRef:
            name: vso-db-credentials
            key: password

🔄 Rotation Vault génère des identifiants éphémères (par défaut TTL = 1h).

VSO renouvelle ou régénère automatiquement ces credentials.

Lorsquun nouveau secret est émis, le Deployment ciblé est redémarré pour recharger les variables denvironnement.

Résumé Pas de secrets stockés en clair dans Git ou Helm.

Rotation automatique des credentials Postgres.

Intégration fluide avec Kubernetes via ServiceAccounts.