Deux mécanismes prétendent rendre au rôle stable ce qu'un rôle éphémère a créé. Aucun ne fonctionne complètement.
1. Le REASSIGN de Vault ne tourne pas dans la bonne base
hashicorp-vault/iac/modules/app_roles/main.tf :
revocation_statements=["REASSIGN OWNED BY \"{{name}}\" TO ${local.owner_role};", # reassign must be executed in the
# database where the reassigned
# objects are - TODO
]
Le rôle Vault est lié à db_name = "postgres" : une seule connexion, vers la base postgres. Or REASSIGN OWNED BY n'agit que dans la base courante. Les objets de kadans, crowdsec, plausible… ne sont jamais réattribués. Le TODO l'avoue ; il est toujours là.
2. Le CronJob pg-fix-table-ownership ne regarde que pg_tables
Deux extensions de la base kadans appartiennent à un rôle éphémère que le CronJob ne verra jamais. Conséquence limitée aujourd'hui (le propriétaire d'une extension ne compte que pour ALTER/DROP EXTENSION) — mais c'est la démonstration que le filet a des trous, et une future migration créant une vue ou une séquence tomberait dedans avec des conséquences, elles, immédiates.
Ce rôle fait par ailleurs partie des 997 qui ne sont jamais DROPés (issue #26) : personne ne le supprimera, donc personne ne butera sur l'erreur qui révélerait le problème.
Le filet complet
REASSIGN OWNED BY <éphémère> TO <app>_role exécuté dans la base de l'application — une seule instruction qui couvre tout ce que le ALTER TABLE en boucle rate.
Deux voies, non exclusives :
Vault : une vault_database_secret_backend_connection par base applicative, pour que la révocation puisse jouer le REASSIGN au bon endroit. C'est la voie propre (au moment du bail, pas 24 h après) mais elle touche le module partagé par les cinq apps.
Le CronJob : remplacer la boucle pg_tables par un REASSIGN OWNED BY sur chaque rôle v-kubernet-% encore existant, dans chaque base. Plus simple, mais reste un rattrapage a posteriori.
⚠ Cadeau du PR #25 : ALTER ROLE "{{name}}" SET ROLE <app>_role fait naître les nouveaux objets directement chez le rôle stable. Une fois les baux renouvelés, le CronJob et le REASSIGN deviennent des filets pour l'existant, plus des béquilles pour le quotidien. Cette issue reste ouverte pour l'existant et pour les clients qui n'obtiennent pas leurs identifiants de Vault.
Le CronJob vit dans le dépôt factory (playbook Ansible), pas ici : sa correction se déploie par un run Ansible, d'où l'issue plutôt qu'un commit.
## Le constat
Deux mécanismes prétendent rendre au rôle stable ce qu'un rôle éphémère a créé. **Aucun ne fonctionne complètement.**
### 1. Le `REASSIGN` de Vault ne tourne pas dans la bonne base
`hashicorp-vault/iac/modules/app_roles/main.tf` :
```hcl
revocation_statements = [
"REASSIGN OWNED BY \"{{name}}\" TO ${local.owner_role};", # reassign must be executed in the
# database where the reassigned
# objects are - TODO
]
```
Le rôle Vault est lié à `db_name = "postgres"` : une seule connexion, vers la base `postgres`. Or `REASSIGN OWNED BY` n'agit **que dans la base courante**. Les objets de `kadans`, `crowdsec`, `plausible`… ne sont jamais réattribués. Le `TODO` l'avoue ; il est toujours là.
### 2. Le CronJob `pg-fix-table-ownership` ne regarde que `pg_tables`
(`kube-system`, 03:00 — source : dépôt `factory`, `ansible/arcodange/factory/playbooks/setup/postgres.yml`)
```sql
FOR r IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
LOOP EXECUTE format('ALTER TABLE public.%I OWNER TO %I', r.tablename, '$role');
```
Vues, vues matérialisées, séquences autonomes, types, fonctions, schémas et **extensions** lui échappent.
## L'angle mort n'est pas théorique — il est déjà occupé
Recensement de toutes les bases le 2026-07-28 (pg_class + pg_proc + pg_type + pg_namespace + pg_extension) :
```
crowdsec : RIEN
dance-lessons-coach : RIEN
erp : RIEN
erp-sandbox : RIEN
gitea : RIEN
kadans : extension=2 (v-kubernet-kadans-4t59i0edKizfogcwiaXn-1784895219)
plausible : RIEN
webapp : RIEN
```
```
citext | v-kubernet-kadans-4t59i0edKizfogcwiaXn-1784895219
pgcrypto | v-kubernet-kadans-4t59i0edKizfogcwiaXn-1784895219
plpgsql | postgres
```
Deux extensions de la base `kadans` appartiennent à un rôle éphémère que le CronJob ne verra jamais. Conséquence limitée aujourd'hui (le propriétaire d'une extension ne compte que pour `ALTER`/`DROP EXTENSION`) — mais c'est la démonstration que le filet a des trous, et une future migration créant une **vue** ou une **séquence** tomberait dedans avec des conséquences, elles, immédiates.
Ce rôle fait par ailleurs partie des 997 qui ne sont jamais `DROP`és (issue #26) : personne ne le supprimera, donc personne ne butera sur l'erreur qui révélerait le problème.
## Le filet complet
`REASSIGN OWNED BY <éphémère> TO <app>_role` exécuté **dans la base de l'application** — une seule instruction qui couvre tout ce que le `ALTER TABLE` en boucle rate.
Deux voies, non exclusives :
1. **Vault** : une `vault_database_secret_backend_connection` par base applicative, pour que la révocation puisse jouer le `REASSIGN` au bon endroit. C'est la voie propre (au moment du bail, pas 24 h après) mais elle touche le module partagé par les cinq apps.
2. **Le CronJob** : remplacer la boucle `pg_tables` par un `REASSIGN OWNED BY` sur chaque rôle `v-kubernet-%` encore existant, dans chaque base. Plus simple, mais reste un rattrapage a posteriori.
⚠ **Cadeau du PR #25** : `ALTER ROLE "{{name}}" SET ROLE <app>_role` fait naître les nouveaux objets **directement** chez le rôle stable. Une fois les baux renouvelés, le CronJob et le `REASSIGN` deviennent des filets pour l'existant, plus des béquilles pour le quotidien. Cette issue reste ouverte pour l'existant et pour les clients qui n'obtiennent pas leurs identifiants de Vault.
Le CronJob vit dans le dépôt `factory` (playbook Ansible), pas ici : sa correction se déploie par un run Ansible, d'où l'issue plutôt qu'un commit.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Le constat
Deux mécanismes prétendent rendre au rôle stable ce qu'un rôle éphémère a créé. Aucun ne fonctionne complètement.
1. Le
REASSIGNde Vault ne tourne pas dans la bonne basehashicorp-vault/iac/modules/app_roles/main.tf:Le rôle Vault est lié à
db_name = "postgres": une seule connexion, vers la basepostgres. OrREASSIGN OWNED BYn'agit que dans la base courante. Les objets dekadans,crowdsec,plausible… ne sont jamais réattribués. LeTODOl'avoue ; il est toujours là.2. Le CronJob
pg-fix-table-ownershipne regarde quepg_tables(
kube-system, 03:00 — source : dépôtfactory,ansible/arcodange/factory/playbooks/setup/postgres.yml)Vues, vues matérialisées, séquences autonomes, types, fonctions, schémas et extensions lui échappent.
L'angle mort n'est pas théorique — il est déjà occupé
Recensement de toutes les bases le 2026-07-28 (pg_class + pg_proc + pg_type + pg_namespace + pg_extension) :
Deux extensions de la base
kadansappartiennent à un rôle éphémère que le CronJob ne verra jamais. Conséquence limitée aujourd'hui (le propriétaire d'une extension ne compte que pourALTER/DROP EXTENSION) — mais c'est la démonstration que le filet a des trous, et une future migration créant une vue ou une séquence tomberait dedans avec des conséquences, elles, immédiates.Ce rôle fait par ailleurs partie des 997 qui ne sont jamais
DROPés (issue #26) : personne ne le supprimera, donc personne ne butera sur l'erreur qui révélerait le problème.Le filet complet
REASSIGN OWNED BY <éphémère> TO <app>_roleexécuté dans la base de l'application — une seule instruction qui couvre tout ce que leALTER TABLEen boucle rate.Deux voies, non exclusives :
vault_database_secret_backend_connectionpar base applicative, pour que la révocation puisse jouer leREASSIGNau bon endroit. C'est la voie propre (au moment du bail, pas 24 h après) mais elle touche le module partagé par les cinq apps.pg_tablespar unREASSIGN OWNED BYsur chaque rôlev-kubernet-%encore existant, dans chaque base. Plus simple, mais reste un rattrapage a posteriori.⚠ Cadeau du PR #25 :
ALTER ROLE "{{name}}" SET ROLE <app>_rolefait naître les nouveaux objets directement chez le rôle stable. Une fois les baux renouvelés, le CronJob et leREASSIGNdeviennent des filets pour l'existant, plus des béquilles pour le quotidien. Cette issue reste ouverte pour l'existant et pour les clients qui n'obtiennent pas leurs identifiants de Vault.Le CronJob vit dans le dépôt
factory(playbook Ansible), pas ici : sa correction se déploie par un run Ansible, d'où l'issue plutôt qu'un commit.