Commit Graph
32 Commits
Author SHA1 Message Date
arcodangeandClaude Opus 5 1dd905dc5f fix(pgbouncer,vault) — ce qu'un client laisse sur une connexion, le suivant n'en hérite plus
Helm Charts / Detect changed charts (pull_request) Successful in 58s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Un pgbouncer partagé n'a qu'UNE barrière entre deux clients d'un même pool : le
`server_reset_query`. La nôtre ne nettoyait que les requêtes préparées. Tout le
reste de l'état de session — variables, LISTEN, tables TEMP, et le rôle
courant — traversait la déconnexion et tombait dans les mains du client suivant.

CE QUI A ÉTÉ MESURÉ, PAS SUPPOSÉ

pgbouncer 1.25.2 (la version qui tourne), monté avec NOTRE configuration :
`pool_mode = session`, `server_reset_query = DEALLOCATE ALL`,
`server_reset_query_always = 1`, `default_pool_size = 1`. Le client 1 pose son
état puis se déconnecte ; le client 2, qui n'a rien demandé, arrive.

  DEALLOCATE ALL (l'existant)   client 2 hérite : work_mem=17MB, 1 LISTEN,
                                la table TEMP du client 1, et son SET ROLE —
                                au point de créer des tables appartenant à un
                                rôle qui n'est pas le sien.
  DISCARD ALL (ce commit)       client 2 obtient work_mem=4MB, 0 LISTEN, pas
                                de table TEMP, et son PROPRE rôle.

POURQUOI `DISCARD ALL` NE PEUT RIEN CASSER

C'est le défaut de pgbouncer, et un sur-ensemble STRICT des deux valeurs qui
l'ont précédé ici : il contient `DEALLOCATE ALL` — donc le correctif crowdsec de
07e2c6d (« prepared statement already exists ») est conservé, et c'est vérifié :
deux clients successifs préparent le même nom sans erreur — et il contient
`SELECT pg_advisory_unlock_all()`, la valeur que pose le sous-chart.

Et il ne touche jamais un client vivant : en `pool_mode = session` la connexion
serveur n'est rendue qu'à la déconnexion, donc le reset ne court pas entre deux
requêtes d'une même session. Vérifié : table TEMP, `SET work_mem` et `LISTEN`
d'un client VIVANT survivent intacts.

PORTÉE DE LA FUITE — ce qu'elle est, et ce qu'elle n'est pas

Les pools de pgbouncer sont partitionnés par (base, utilisateur) : 210 pools
mesurés sur l'instance, aucun ne mélange deux bases ni deux comptes. Un rôle
posé par kadans ne peut donc PAS atterrir chez crowdsec ou plausible : le seul
héritier possible est un client de la même base avec le même identifiant, donc
l'application elle-même. Ce n'est pas une élévation de privilège entre
applications — c'est un défaut d'hygiène, et il est déjà là aujourd'hui pour
n'importe quel `SET` de n'importe quelle application.

LA CEINTURE, CÔTÉ VAULT

`ALTER ROLE "{{name}}" SET ROLE <app>_role` dans les creation_statements fait de
l'endossement un défaut de CONNEXION, immune au `pool_mode` comme au
`server_reset_query`, et valable pour les clients qui ne sont pas l'application
(le psql d'un job). Elle n'apporte aucun privilège : le `GRANT` de la ligne
précédente rend déjà le rôle éphémère membre du rôle stable — d'où le fait
qu'elle ne peut pas échouer là où le GRANT réussit.

Elle règle à la racine ce que le CronJob `pg-fix-table-ownership` rattrape tous
les jours à 03:00 : les objets naissent chez le rôle stable au lieu d'être
réattribués après coup. ⚠ Elle ne vaut que pour les identifiants créés APRÈS
l'apply — elle ne protège donc PAS ce soir ; c'est `DISCARD ALL` qui protège ce
soir.

Mesuré (PostgreSQL 16, compte CREATEROLE non-superutilisateur comme celui de
Vault) : l'instruction passe, le login donne bien `current_role` = rôle stable
avec `session_user` = rôle éphémère, un `ALTER ROLE … RESET role` la retire, et
elle SURVIT à `RESET ALL` / `DISCARD ALL` — les deux mesures composent au lieu
de s'annuler.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GdUCA5Uz8QyMwa2P4Pg2hK
2026-07-28 22:48:49 +02:00
arcodangeandClaude Opus 5 7074a94d7e docs(minio) — le raisonnement part dans l'ADR, le code garde ce qui protège
Helm Charts / Detect changed charts (push) Successful in 22s
Helm Charts / Detect changed charts (pull_request) Successful in 16s
MinIO / Auth with gitea for vault (push) Failing after 8m33s
MinIO / Tofu - minio IAC (push) Has been skipped
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 (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Hashicorp Vault / Auth with gitea for vault (push) Failing after 8m31s
Hashicorp Vault / Tofu - Vault IAC (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Les décisions de conception (qui déclare, qui détient, pourquoi les octets ne
passent pas par l'API) vivent désormais dans
`factory/doc/adr/20260726-stockage-objet-minio.md`.

Le code ne garde que ce qu'un relecteur ne peut pas deviner et qui l'empêcherait
de casser quelque chose : l'absence VOLONTAIRE de s3:GetObject/PutObject dans la
politique du provisionneur, l'absence VOLONTAIRE de basic-auth sur l'ingress
S3, le caractère inconditionnel de la règle Vault, et l'avertissement sur les
noms d'actions MinIO non éprouvés. Chaque fichier pointe l'ADR.

283 → 230 lignes sur minio/iac. tofu fmt propre, tofu validate réussi sur les
deux racines.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-26 10:19:28 +02:00
arcodangeandClaude Opus 5 ec71571b98 refactor(minio) — chacun son périmètre : les buckets se déclarent depuis le dépôt de l'app
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
« 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
arcodangeandClaude Opus 5 91a0f09b49 refactor(vault) — lire ses identifiants MinIO devient une propriété de la plateforme
Helm Charts / Detect changed charts (pull_request) Successful in 15s
Helm Charts / Detect changed charts (push) Successful in 15s
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) Failing after 8m35s
Hashicorp Vault / Tofu - Vault IAC (push) Has been skipped
MinIO / Auth with gitea for vault (pull_request) Failing after 8m32s
MinIO / Tofu - minio IAC (pull_request) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Hashicorp Vault / Auth with gitea for vault (pull_request) Failing after 8m36s
Hashicorp Vault / Tofu - Vault IAC (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Retour fondateur : « je pensais que tools#21 contribuerait à app_policy pour une
policy kvv2/minio/<app name> ». Il a raison, et mon choix initial était le plus
faible des deux.

Mon objection — ne donner le droit qu'aux apps qui en ont besoin — ne tient pas
à l'examen : la règle porte le NOM de l'app, donc elle ne peut jamais exposer
que ses propres clés. Il n'y a aucun privilège à préserver. Une app qui ne
stocke rien lit un chemin qui n'existe pas : une règle inerte, pas un droit.

Son argument, lui, porte : savoir lire ses propres identifiants de stockage est
une propriété de la PLATEFORME, pas une exception par application. Et
`kv_read_paths` est documenté comme la trappe pour un secret appartenant à une
AUTRE app (les creds GCS de Longhorn pour l'ERP) — y ranger un motif standard
l'aurait rendu invisible et aurait obligé à le redéclarer à chaque app.

La règle passe donc dans `app_policy`, en prod ET pour chaque instance non-prod
(symétrie stricte), sur deux chemins : le document `kvv2/data/minio/<app>` et
ses descendants.

Un cran plus loin que la demande : la règle est INCONDITIONNELLE, sans drapeau.
Conséquence — déclarer un consommateur MinIO se fait désormais à UN SEUL
endroit, `var.consumers` du pipeline minio. Aucune synchronisation à tenir entre
deux fichiers, donc rien à oublier. Le `kv_read_paths` que j'avais ajouté à
kadans est retiré : il faisait double emploi.

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

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-26 09:26:05 +02:00
arcodangeandClaude Opus 5 4ca4a05370 feat(minio) — un compte de service par app consommatrice, borné à son bucket
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
2026-07-26 09:12:09 +02:00
arcodangeandClaude Opus 5 d146affbcd fix(minio) — déclarer minio dans la liste centrale des applications Vault
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 1m6s
Helm Charts / Detect changed charts (pull_request) Successful in 24s
Hashicorp Vault / Auth with gitea for vault (push) Failing after 8m38s
Hashicorp Vault / Tofu - Vault IAC (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Library charts tool (push) Has been skipped
Hashicorp Vault / Tofu - Vault IAC (pull_request) Has been skipped
Hashicorp Vault / Auth with gitea for vault (pull_request) Failing after 8m40s
Helm Charts / Application charts pgcat (push) Has been skipped
CI en échec sur le workflow MinIO : role "gitea_cicd_minio" could not be found.

Diagnostic : les rôles CI gitea_cicd_<app> ne naissent PAS dans l'IaC de
l'application — ils viennent du module app_policy, appliqué centralement par
hashicorp-vault/iac pour chaque entrée de terraform.tfvars. J'avais posé
minio/iac (qui s'authentifie AVEC ce rôle) sans alimenter la liste : le run
tentait donc de s'authentifier avec un rôle que personne n'avait créé. Amorçage
circulaire, entièrement de mon fait.

- hashicorp-vault/iac/terraform.tfvars : minio ajouté aux applications, avec
  service_account_namespaces = ["tools"] comme crowdsec et plausible ;
- .gitea/workflows/vault.yaml : les triggers couvrent désormais *.tfvars en
  plus de *.tf. C'est là que vit la liste des applications : sans ça, ajouter
  une app ne déclenchait jamais la création de son rôle — le piège qui vient
  de mordre. Les ancres YAML des triggers sont retirées au passage (une ancre
  dans un trigger Gitea Actions fait taire push ET pull_request en silence,
  vécu sur arcodange/kadans, issues 113→117 ; c'est probablement pourquoi ce
  workflow ne partait qu'à la main) ;
- minio/README.md : l'ordre de mise en service dit maintenant les DEUX étapes
  et nomme l'erreur exacte à laquelle on s'expose en les inversant.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-25 18:23:02 +02:00
arcodange 65ff6fcc34 feat: ajouter kadans à vault
Helm Charts / Detect changed charts (push) Successful in 1m2s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-07-13 18:55:26 +02:00
arcodangeandClaude Opus 4.8 714e2bc2ab feat(alerting): livraison Telegram des alertes via Alertmanager
Helm Charts / Detect changed charts (push) Successful in 14s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Detect changed charts (pull_request) Successful in 14s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Les règles d'alerte `prospection` s'évaluaient déjà dans Prometheus mais ne
notifiaient nulle part. On câble Alertmanager pour livrer les alertes sur le bot
Telegram de prospection, via `telegram_configs` natif d'Alertmanager.

- iac Vault : policy read-only `alertmanager-telegram` sur
  kvv2/data/prospection/telegram + rôle k8s `alertmanager` (SA
  prometheus-alertmanager, ns tools).
- VSO : VaultAuth + VaultStaticSecret resynchronisent kvv2/prospection/telegram
  vers un Secret `alertmanager-telegram` dans le ns tools (le Secret prospection
  est namespace-scoped, non réutilisable). rolloutRestartTargets sur le
  StatefulSet Alertmanager.
- prometheus values : lien server -> Alertmanager (prometheus-alertmanager:9093),
  route + receiver `telegram` (bot_token_file monté, chat_id inline, parse_mode
  HTML, send_resolved), et montage du Secret via extraSecretMounts.

Additif : ni grafana ni les règles d'alerte existantes ne sont touchés.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 23:20:00 +02:00
arcodange b4f945c310 Merge pull request 'feat(vault): onboard prospection (gitea_cicd role + ops policy)' (#6) from arcodange/onboard-prospection into main
Helm Charts / Detect changed charts (push) Successful in 46s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-07-08 15:39:57 +02:00
arcodangeandClaude Opus 4.8 31a66884d6 feat(vault): onboard prospection (gitea_cicd role + ops policy)
Helm Charts / Detect changed charts (push) Successful in 5m32s
Helm Charts / Detect changed charts (pull_request) Successful in 1m2s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Ajoute prospection à la liste app_policies → crée le rôle JWT gitea_cicd_prospection
et la policy prospection-ops, requis par le workflow vault.yaml du repo prospection
(qui provisionne le rôle k8s-auth + la policy de lecture kvv2/prospection/*).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 15:37:44 +02:00
arcodangeandClaude Opus 4.7 2953ec3202 feat(vault): erp prod runtime may read the shared GCS backup creds (kv_read_paths)
Helm Charts / Detect changed charts (push) Successful in 21s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Detect changed charts (pull_request) Successful in 14s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Adds an optional kv_read_paths list to the app_policy module (default []) so an
app's env=prod runtime policy can read extra kvv2 data paths — e.g. a shared
backup-creds path owned by another app. Plumbed through the root applications
schema + module call (dynamic rule, read+list).

Set for erp: kv_read_paths = ["kvv2/data/longhorn/gcs-backup"], so the dedicated
Dolibarr backup CronJob (erp chart, gated) can read the existing GCS HMAC creds
via its own VaultStaticSecret instead of borrowing the Longhorn secret
cross-namespace or duplicating credentials.

No-op for every other app (default []). Only the `erp` runtime policy gains one
read+list rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-06-30 16:29:15 +02:00
arcodangeandClaude Opus 4.7 3170a341d1 fix(vault): rename applications.policies field to ops_policies (cms CI was silently missing its R2 policy)
Helm Charts / Detect changed charts (pull_request) Successful in 19s
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) Failing after 13m59s
Helm Charts / Library charts tool (push) Has been cancelled
Helm Charts / Application charts pgcat (push) Has been cancelled
The `applications` object field was declared `policies` in variables.tf, but
the cms tfvars entry, the runbook (doc/runbooks/new-web-app/03-vault-platform.md),
the guidebook (vibe/guidebooks/tools/secrets-and-vso.md) and the module input
(modules/app_policy variable `ops_policies`) all use the name `ops_policies`.

Because Terraform silently drops unknown attributes when converting a value to
an object() type, cms's `ops_policies = ["factory__cf_r2_arcodange_tf"]` was
discarded and `each.value.policies` fell back to [] — so gitea_cicd_cms never
received the `factory__cf_r2_arcodange_tf` token policy (read on
kvv1/cloudflare/r2/arcodange-tf + kvv1/zoho/self_client, defined in
factory iac/cloudflare.tf). cms CI was missing its Cloudflare R2 Terraform-state
permissions.

Fix at the root: rename the schema field `policies` -> `ops_policies` (and its
single reference main.tf:82 `each.value.policies` -> `each.value.ops_policies`),
aligning the whole chain. This is lower-churn than renaming the tfvars key (the
chosen alternative would also have required fixing the runbook + guidebook, which
both already document `ops_policies`) and prevents the next app created from the
runbook from re-introducing the same silently-dropped key.

Behavioural change: gitea_cicd_cms gains `factory__cf_r2_arcodange_tf` in its
token_policies. No other app sets this field (all default []), so no other role
changes. Reviewer: confirm the R2 policy is the intended grant for cms CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-06-28 19:18:06 +02:00
arcodangeandClaude Opus 4.7 25569eb29d feat(multi-env): Phase D2 — Vault policies for erp-sandbox
Helm Charts / Detect changed charts (pull_request) Failing after 11m29s
Helm Charts / Detect changed charts (push) Failing after 12m7s
Helm Charts / Library charts tool (push) Has been cancelled
Helm Charts / Application charts pgcat (push) Has been cancelled
Helm Charts / Library charts tool (pull_request) Has been cancelled
Helm Charts / Application charts pgcat (pull_request) Has been cancelled
ADR-0002 Phase D, Vault layer. `erp` gains `envs = ["prod", "sandbox"]`,
which flows into the app_policy module (main.tf:81 `envs = each.value.envs`).
For erp the module now resolves instances = ["erp", "erp-sandbox"], so the
apply:
  - ADDS  vault_policy.app_non_prod["erp-sandbox"] — the runtime policy
          named `erp-sandbox` (read kvv2/data/erp-sandbox/* +
          postgres/creds/erp-sandbox*), consumed by the sandbox pod's VSO.
  - UPDATES vault_policy.ops["erp"] in place — the `erp-ops` CI policy
          gains the erp-sandbox kvv2 data/delete/undelete/destroy/metadata
          rules + the erp-sandbox values in the k8s-role allowed_parameter
          lists, so CI can manage the sandbox instance. The glob rules
          (postgres/roles/erp*, kvv1/cloudflare/erp*, auth/kubernetes/role/erp*)
          already covered erp-sandbox, so they don't change.

No destroy/replace. prod `erp` runtime policy + every other app render
byte-identical (their envs still default to ["prod"]).

Diff kept to the single erp line — the pre-existing cms/crowdsec/plausible
alignment is left as-is on main (not reformatting unrelated entries).

D2 of Phase D. D1 (postgres DB+role) = factory#17 (merged). D3 (erp iac
creds + KV) and D4 (ArgoCD) follow.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-06-28 17:14:53 +02:00
arcodangeandClaude Opus 4.7 a3e121b468 modules: add env/envs parameter to app_roles + app_policy (multi-env)
Helm Charts / Detect changed charts (push) Successful in 23s
Helm Charts / Detect changed charts (pull_request) Successful in 22s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Phase A of the multi-environment evolution agreed in the erp repo design
thread. Both modules gain an optional env coordinate that defaults to
"prod"; by the elision rule, env=prod produces the existing single-env
derived names character-for-character, so every existing app's tofu plan
is a no-op.

app_roles (per-instance module — caller iterates over envs):
- variables.tf: add optional env = "prod"
- main.tf: compute local.instance via elision rule + local.owner_role
  (snake-case <name>_<env>_role for the Postgres owner). The name/env/
  database locals are grouped so fmt keeps the existing `name` alignment
  (no whitespace churn on unchanged keys).
- main.tf: substitute local.name -> local.instance / local.owner_role in
  the dynamic role name, k8s role name, SA bindings, token_policies
- outputs.tf: add env + instance outputs; kvv2_path_prefix derives from
  local.instance (== local.name when env=prod → backwards-compat)

app_policy (per-repo module — accepts list of envs):
- variables.tf: add optional envs = ["prod"]
- main.tf: compute local.instances + local.non_prod_instances; remove the
  now-dead bound_service_account_* alias locals (the allowed_parameter
  blocks build their values from per_instance_sa_* maps instead)
- main.tf: kvv2 ops rules become dynamic blocks iterating local.instances
  in the original order (data, delete, undelete, destroy, metadata), so a
  prod-only app renders a byte-identical policy document
- main.tf: allowed_parameter for bound_service_account_* + token_policies
  use comprehensions over local.instances (1-element → identical to old
  static values for prod-only apps)
- main.tf: keep vault_policy.app (env=prod runtime policy) at its original
  address; add vault_policy.app_non_prod via for_each over non_prod_instances
  (empty set for prod-only apps → no new resources)

Top-level wiring:
- iac/variables.tf: add envs = optional(list(string), ["prod"]) to the
  applications set(object) type
- iac/main.tf: pass envs = each.value.envs to app_policies

Verified: `tofu fmt -check` clean on all touched files, `tofu validate`
passes. Backwards-compat reasoning for the no-op plan is in the PR body.

Phase B (factory postgres iac + argocd + runbook docs) and Phase D
(erp iac/main.tf for_each + activate sandbox) follow in their own PRs.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-06-15 14:29:11 +02:00
arcodange 023cee3447 🤖 ci(vault): declare dance-lessons-coach JWT role + ops policy (#1)
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 11s
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2026-05-06 12:55:26 +02:00
arcodange 02322e9a24 use internal .lab instead of failing duckdns.org
Helm Charts / Detect changed charts (push) Successful in 22s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Failing after 34s
2025-12-31 17:54:36 +01:00
arcodange a8c497a5da try plausible CE for web analytics 2025-12-10 15:00:47 +01:00
arcodange a5338ac6f7 TODO: 1 vault_database_secret_backend_connection per database 2025-12-09 12:58:59 +01:00
arcodange 2903f70e9f fixes
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-09 12:14:57 +01:00
arcodange 859057be66 configure postgresql for crowdsec
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-03 18:08:53 +01:00
arcodange 2d5ec8a859 allow a SA from factory project (ansible orchestrator) to read cms cloudflare turnstile values for crowdsec captcha
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 23s
2025-12-03 15:18:20 +01:00
arcodange c490d37fd7 add ops_ prefix to policies applied to cicd role 2025-12-03 15:16:46 +01:00
arcodange 50f8ea95be allow several k8s SA to take an app policy
Helm Charts / Detect changed charts (push) Successful in 15s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-11-27 23:24:47 +01:00
arcodange 98395dbe5d vault kvv1/ovh/<app> permission
Helm Charts / Detect changed charts (push) Successful in 20s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-11-04 10:11:05 +01:00
arcodange 24c3d92522 enable per app role list of policies
Helm Charts / Detect changed charts (push) Successful in 18s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-10-30 10:05:25 +01:00
arcodange ea9e41ff1a tofu fmt -recursive and kvv1/cloudflare permission for cms project
Helm Charts / Detect changed charts (push) Successful in 55s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-10-24 18:00:16 +02:00
arcodange be6e6135d7 documentation and fmt
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-08-31 11:33:27 +02:00
arcodange 784c014224 add app_roles terraform module for vault and declare erp app 2024-11-08 19:01:22 +01:00
arcodange bbb0bc7d5f configure vault secrets operator 2024-10-30 11:21:48 +01:00
arcodange 3a506543ce apply vault config from CI 2024-10-05 23:58:24 +02:00
arcodange 7a640d104c experiment with vault configuration 2024-09-27 12:22:36 +02:00
arcodange 042e5b8767 add hashicorp vault 2024-09-05 19:45:42 +02:00