Helm Charts / Detect changed charts (push) Successful in 57s
MinIO / Auth with gitea for vault (push) Failing after 8m34s
MinIO / Tofu - minio IAC (push) Has been skipped
Hashicorp Vault / Auth with gitea for vault (push) Failing after 8m33s
Hashicorp Vault / Tofu - Vault IAC (push) Has been skipped
Helm Charts / Detect changed charts (pull_request) Successful in 1m1s
Helm Charts / Library charts tool (push) Has been cancelled
Helm Charts / Application charts pgcat (push) Has been cancelled
MinIO / Auth with gitea for vault (pull_request) Failing after 8m32s
MinIO / Tofu - minio IAC (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 / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
« On peut adopter ce pattern à toutes les apps qui pourraient avoir besoin de MinIO, et ainsi modifier les app roles / app policy générique. » (fondateur, 26/07) Bonne nouvelle : les modules centraux n'ont PAS eu à changer. `kv_read_paths` existe déjà dans `app_policy` et fait exactement ça — l'ERP s'en sert pour lire les creds GCS de Longhorn. Le motif générique était donc à moitié construit ; il manquait la moitié MinIO. CE QUI EST AJOUTÉ : `minio/iac/consumers.tf` provisionne, pour chaque app déclarée dans `var.consumers`, une politique MinIO bornée à SON bucket (GetObject/PutObject/DeleteObject sur les objets, ListBucket sur le bucket seul — ni les autres buckets, ni l'administration), un compte de service, et écrit ses clés dans `kvv2/minio/<app>`. POURQUOI LES CLÉS VIVENT CHEZ MINIO ET PAS CHEZ L'APP : seul ce pipeline possède les identifiants ROOT. Si chaque app créait son propre compte de service, il faudrait donner ce root à chaque rôle CI — c'est-à-dire à tout le monde. Ici il ne sort jamais d'ici, et l'app ne reçoit qu'une clé qui ne peut rien lire d'autre que son bucket. Un compte de service qui fuite ne donne accès qu'aux objets qu'il gérait déjà. Ajouter une app = trois lignes déclaratives, documentées au README : son bucket dans values.yaml, son entrée dans `var.consumers`, son `kv_read_paths` au tfvars central. Aucun module à toucher. Le provider parle à `s3.arcodange.fr` — l'endpoint PUBLIC, parce que le runner CI n'est pas dans le LAN et que `.lab` ne s'y résout pas. C'est l'exposition HTTPS mergée ce matin qui rend ce plan applicable. ⚠ Erreur attrapée par le validateur, et corrigée : je relisais `kvv2/minio/config` alors que `local.config` de main.tf porte déjà les identifiants root — une lecture qui aurait créé une dépendance circulaire avec l'écriture faite par ce même plan. Vérifié : `tofu fmt` propre, `tofu validate` réussi (avec TERRAFORM_VAULT_AUTH_JWT posé — sans lui, le provider Vault échoue déjà sur main, ce n'est pas mon fait). Je n'ai lancé AUCUN apply : c'est le workflow qui le fera, et la revue t'appartient. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
82 lines
3.4 KiB
Terraform
82 lines
3.4 KiB
Terraform
# ── Les apps qui STOCKENT des objets dans MinIO ──────────────────────────────
|
|
#
|
|
# Le motif, générique, en trois pièces :
|
|
# 1. ICI : un compte de service MinIO par app, borné à SON bucket, dont les
|
|
# clés sont écrites dans `kvv2/minio/<app>` ;
|
|
# 2. côté Vault central : l'app déclare `kv_read_paths = ["kvv2/data/minio/<app>"]`
|
|
# dans `hashicorp-vault/iac/terraform.tfvars` — le mécanisme existait DÉJÀ
|
|
# (même recette que `kvv2/data/longhorn/gcs-backup` pour l'ERP), donc aucun
|
|
# module central n'a eu besoin d'être modifié ;
|
|
# 3. côté app : une VaultStaticSecret qui matérialise ce chemin en Secret k8s.
|
|
#
|
|
# POURQUOI les clés vivent chez MINIO et pas chez l'app : seul ce pipeline-ci
|
|
# possède les identifiants ROOT. Si chaque app créait son propre compte de
|
|
# service, il faudrait donner le root de MinIO à chaque rôle CI — c'est-à-dire
|
|
# à tout le monde. Ici il ne sort jamais d'ici, et l'app ne reçoit qu'une clé
|
|
# qui ne peut rien lire d'autre que son bucket.
|
|
#
|
|
# AJOUTER UNE APP = deux lignes : une entrée dans `var.consumers` ci-dessous
|
|
# (avec son bucket, qui doit exister dans `values.yaml` du chart), et un
|
|
# `kv_read_paths` dans le tfvars central.
|
|
|
|
# La politique d'accès : LE bucket de l'app, rien d'autre. Ni listing des autres
|
|
# buckets, ni administration — un compte de service qui fuite ne donne accès
|
|
# qu'aux objets qu'il gérait déjà.
|
|
resource "minio_iam_policy" "app" {
|
|
for_each = { for c in var.consumers : c.app => c }
|
|
name = "${each.key}-app"
|
|
policy = jsonencode({
|
|
Version = "2012-10-17"
|
|
Statement = [
|
|
{
|
|
Effect = "Allow"
|
|
Action = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"]
|
|
Resource = ["arn:aws:s3:::${each.value.bucket}/*"]
|
|
},
|
|
{
|
|
# Nécessaire pour qu'un client S3 puisse vérifier l'existence du bucket
|
|
# et lister SES objets — jamais ceux d'un autre.
|
|
Effect = "Allow"
|
|
Action = ["s3:ListBucket", "s3:GetBucketLocation"]
|
|
Resource = ["arn:aws:s3:::${each.value.bucket}"]
|
|
},
|
|
]
|
|
})
|
|
}
|
|
|
|
resource "minio_iam_user" "app" {
|
|
for_each = { for c in var.consumers : c.app => c }
|
|
name = "${each.key}-app"
|
|
# Le mot de passe EST la clé secrète S3 : généré ici, jamais choisi.
|
|
secret = random_password.app[each.key].result
|
|
# `false` = on ne recrée pas l'utilisateur à chaque rotation du mot de passe :
|
|
# les objets déjà déposés gardent leur propriétaire.
|
|
force_destroy = false
|
|
}
|
|
|
|
resource "random_password" "app" {
|
|
for_each = { for c in var.consumers : c.app => c }
|
|
length = 40
|
|
special = false # les outils S3 transportent mal certains caractères en URL
|
|
}
|
|
|
|
resource "minio_iam_user_policy_attachment" "app" {
|
|
for_each = { for c in var.consumers : c.app => c }
|
|
user_name = minio_iam_user.app[each.key].id
|
|
policy_name = minio_iam_policy.app[each.key].id
|
|
}
|
|
|
|
# Les clés, déposées dans l'espace Vault de MINIO — l'app y accède par le
|
|
# `kv_read_paths` déclaré au tfvars central (pièce 2 du motif, ci-dessus).
|
|
resource "vault_kv_secret_v2" "app" {
|
|
for_each = { for c in var.consumers : c.app => c }
|
|
mount = "kvv2"
|
|
name = "minio/${each.key}"
|
|
data_json = jsonencode({
|
|
MINIO_ENDPOINT = var.minio_endpoint
|
|
MINIO_BUCKET = each.value.bucket
|
|
MINIO_ACCESS_KEY = minio_iam_user.app[each.key].id
|
|
MINIO_SECRET_KEY = random_password.app[each.key].result
|
|
})
|
|
}
|