refactor(minio) — le BUCKET est la seule déclaration : plus de liste à tenir
Helm Charts / Detect changed charts (push) Successful in 14s
Helm Charts / Detect changed charts (pull_request) Successful in 14s
Helm Charts / Application charts pgcat (push) Has been cancelled
Helm Charts / Library charts tool (push) Has been cancelled
MinIO / Tofu - minio IAC (push) Has been cancelled
MinIO / Auth with gitea for vault (push) Has been cancelled
MinIO / Auth with gitea for vault (pull_request) Failing after 8m31s
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
Helm Charts / Detect changed charts (push) Successful in 14s
Helm Charts / Detect changed charts (pull_request) Successful in 14s
Helm Charts / Application charts pgcat (push) Has been cancelled
Helm Charts / Library charts tool (push) Has been cancelled
MinIO / Tofu - minio IAC (push) Has been cancelled
MinIO / Auth with gitea for vault (push) Has been cancelled
MinIO / Auth with gitea for vault (pull_request) Failing after 8m31s
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
« Je ne vois pas le mal à donner la permission de lire sur un chemin qui n'existe pas. Je préfère ne pas m'embêter avec consumers ou autre. » (fondateur, 26/07) `var.consumers` disparaît. Le plan LIT `values.yaml` du chart — le même fichier qu'Helm consomme — et provisionne un compte de service par bucket. Créer un bucket EST la déclaration : il devient impossible d'avoir un bucket sans son compte, ou un compte sans son bucket. Une liste de plus aurait été une liste à tenir synchronisée, donc une liste à oublier. La convention qui rend ça possible : UN BUCKET PAR APP, NOMMÉ COMME ELLE. Le bucket passe donc de `kadans-videos` à `kadans`. Il est VIDE aujourd'hui — le renommer maintenant ne coûte rien ; dans un mois ce serait une migration. Tout en découle sans être écrit ailleurs : le compte `<app>-app` borné à ce seul bucket, le secret `kvv2/minio/<app>`, et la lecture que `app_policy` accorde déjà à toute app sur `kvv2/data/minio/<son nom>`. Vérifié plutôt que supposé : `yamldecode` lit bien ce values.yaml, ancres YAML comprises (testé en isolation avant d'écrire le plan). tofu fmt propre, tofu validate réussi. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
This commit is contained in:
+26
-27
@@ -25,7 +25,7 @@ application vivent avec cette application.
|
||||
| Ressources | requests 512 Mi / 100 m · limit 2 Gi — la limite protège les voisins de `tools`, pas MinIO |
|
||||
| API S3 | `s3.arcodange.lab` (interne) **et `s3.arcodange.fr`** (public, tunnel Cloudflare → entrypoint `web` + crowdsec) — voir « Pourquoi une exposition publique » |
|
||||
| Console | `minio.arcodange.lab` (Traefik) |
|
||||
| Bucket | `kadans-videos`, **privé** — l'accès passe par des URL signées (ADR-0002 du dossier produit) |
|
||||
| Buckets | **un par app, nommé comme elle** (`kadans`…), tous **privés** — l'accès passe par des URL signées (ADR-0002 du dossier produit). Le bucket est la SEULE déclaration : compte de service et droits Vault en découlent |
|
||||
| Identifiants | **jamais dans le dépôt** : `iac/` les génère dans Vault (`kvv2/minio/config`), le Vault Secrets Operator les matérialise en secret `minio-config`, le chart les lit via `existingSecret` |
|
||||
|
||||
Le ServiceAccount du pod est nommé `minio` (et non le `minio-sa` par défaut du
|
||||
@@ -96,43 +96,42 @@ une phrase claire, qu'échouer au milieu d'un téléversement.
|
||||
|
||||
## Donner à une app l'accès au stockage
|
||||
|
||||
Le motif tient en **trois pièces**, et il est générique — ajouter une app ne
|
||||
demande aucune modification des modules Vault centraux.
|
||||
**Une seule chose à faire** : ajouter son bucket dans `values.yaml`, **nommé
|
||||
comme l'app**.
|
||||
|
||||
1. **Le bucket** — dans `values.yaml` de ce chart (bloc `buckets`), privé.
|
||||
2. **Le compte de service** — une entrée dans `var.consumers` de `iac/consumers.tf` :
|
||||
```hcl
|
||||
{ app = "mon-app", bucket = "mon-app-fichiers" }
|
||||
```
|
||||
Le plan crée une politique MinIO **bornée à ce bucket**, un compte de service,
|
||||
et écrit ses clés dans `kvv2/minio/mon-app`.
|
||||
3. **La lecture** — *rien à faire.* Le module central `app_policy` accorde à
|
||||
**toute** app la lecture de `kvv2/data/minio/<son nom>`. La règle est
|
||||
inconditionnelle et c'est voulu : le chemin porte le nom de l'app, donc elle
|
||||
ne peut jamais exposer que ses propres clés ; une app qui ne stocke rien lit
|
||||
un chemin qui n'existe pas.
|
||||
```yaml
|
||||
buckets:
|
||||
- name: mon-app
|
||||
policy: none # privé : l'accès passe par des URL signées
|
||||
```
|
||||
|
||||
Puis, côté app : une `VaultStaticSecret` sur `kvv2/minio/<app>` et l'injection
|
||||
des variables dans le Deployment.
|
||||
Tout le reste en découle, sans autre déclaration nulle part :
|
||||
|
||||
> **Un seul endroit déclare un consommateur** : `var.consumers`, ici. Rien à
|
||||
> synchroniser dans le tfvars central, donc rien à oublier. C'est la raison pour
|
||||
> laquelle la règle vit dans le module plutôt que dans `kv_read_paths` — cette
|
||||
> dernière est la trappe pour lire un secret appartenant à une AUTRE app (les
|
||||
> creds GCS de Longhorn pour l'ERP) ; y ranger un motif standard le rendrait
|
||||
> invisible et obligerait à le redéclarer à chaque fois.
|
||||
- `iac/consumers.tf` **lit ce même fichier** et crée un compte de service
|
||||
`mon-app-app`, borné à ce seul bucket, dont les clés atterrissent dans
|
||||
`kvv2/minio/mon-app` ;
|
||||
- le module Vault central `app_policy` accorde **déjà** à toute app la lecture de
|
||||
`kvv2/data/minio/<son nom>` — inconditionnellement, parce que le chemin porte
|
||||
le nom de l'app et ne peut donc jamais exposer que ses propres clés. Une app
|
||||
qui ne stocke rien y lit un chemin qui n'existe pas : une règle inerte.
|
||||
|
||||
Côté app, il reste à écrire une `VaultStaticSecret` sur `kvv2/minio/<app>` et à
|
||||
injecter les variables dans son Deployment (voir `kadans-api` pour l'exemple).
|
||||
|
||||
> **Il n'y a volontairement AUCUNE liste de consommateurs.** Une liste de plus
|
||||
> serait une liste à tenir synchronisée avec les buckets — donc une liste à
|
||||
> oublier. Le bucket fait foi.
|
||||
|
||||
### Pourquoi les clés vivent ICI et pas chez l'app
|
||||
|
||||
Seul ce pipeline possède les identifiants **root** de MinIO. 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, et l'app ne reçoit qu'une
|
||||
clé qui **ne peut rien lire d'autre que son bucket** : ni les autres buckets, ni
|
||||
l'administration. Un compte de service qui fuite ne donne accès qu'aux objets
|
||||
qu'il gérait déjà.
|
||||
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à.
|
||||
|
||||
### Rotation
|
||||
|
||||
Détruire `random_password.app["<app>"]` et relancer le plan suffit : la clé
|
||||
change, `force_destroy = false` garde le compte et les objets déjà déposés
|
||||
change, `force_destroy = false` garde le compte, et les objets déjà déposés
|
||||
conservent leur propriétaire.
|
||||
|
||||
Reference in New Issue
Block a user