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
Vault
- Les playbooks ansible configurent la base de données postgres et le minimum requis pour permetre au dépot "tools" d'appliquer via un workflow gitea action une configuration vault via tofu.
- Configuration des backend d'authentification et des roles pour postgres et kubernetes. Définition de rôles "${app}-ops" pour permettre au dépot d'une application de définir ses propres dépendances dans vault. Rotation de credentials postgres pour les applications.
- Le dépot de l'application webapp gère l'obtention de ses crédentials pour postgres.
flowchart LR
classDef playbook stroke:#0f0,fill:#440,stroke-width: 1px
classDef tofu stroke:#f00,fill:#404,stroke-width: 2px
classDef argocd stroke:#00f,fill:#044,stroke-width: 3px
classDef database stroke:#bb0,fill:#ff0,stroke-width: 5px,color: black
classDef secret stroke:#f00,fill:#f00,stroke-width: 5px,color: yellow
classDef secretOperator stroke:#f00,fill:DarkRed,stroke-width: 5px,color: Orange
subgraph git_code[factory.git]
subgraph ansible_collection
setup_playbook[playbook arcodange.factory.setup]:::playbook
tools_playbook[playbook arcodange.factory.tools]:::playbook
end
git_code_tofu_vault{{tofu}}:::tofu
end
subgraph git_tools[tools.git]
argocd_tools{{Argo CD Apps}}:::argocd
git_tools_tofu_vault{{tofu}}:::tofu
end
subgraph git_webapp[webapp.git]
webapp["Go(lang) web app"]
argocd_webapp{{Argo CD App}}:::argocd
git_webapp_tofu_vault{{tofu}}:::tofu
end
subgraph servers
subgraph k3s
subgraph k3s_ns_tools[ns:tools]
argocd{{Argo CD}}:::argocd
pgbouncer
subgraph vault
subgraph vault_auth[auth]
subgraph vault_auth_openid[openid]
end
vault_auth_jwt[jwt]
vault_auth_k8s[kubernetes]
vault_auth_jwt_role_gitea_cicd[gitea_cicd role]
vault_auth_jwt_role_gitea_cicd_webapp_ops[gitea_cicd_webapp ops role]
vault_auth_k8s_role_vso[vault-secret-operator role]
vault_auth_k8s_role_webapp[webapp role]
subgraph policies
policy_default[default]
policy_webapp[webapp]
policy_webapp_ops[webapp ops]
policy_admin[admin]
policy_vso[edit-vso-client-cache]
end
end
subgraph vault_secrets[secrets]
subgraph kvv2
google/credentials
webapp/config
end
end
subgraph vault_postgres[postgres]
creds/creds-editor
creds/webapp
end
subgraph vault_transit[transit]
end
end
vault-secret-operator:::secretOperator
end
subgraph k3s_ns_webapp[ns:webapp]
webapp_deployment[deployment:webapp]
webapp_postgres_creds_secret[secret:postgres creds]:::secret
webapp_config_secret[secret:config]:::secret
webapp_service_account[sa:webapp]
end
end
subgraph postgres
root_credentials
postgres_db[(postgres)]:::database
webapp_credentials:::secret
webapp_db[(webpp)]:::database
vault_creds_editor_role{{credentials_editor}}
end
end
setup_playbook -. setup postgres .-> postgres
tools_playbook -.-o git_code_tofu_vault
git_code_tofu_vault -..-> vault_auth_openid
git_code_tofu_vault -..-> vault_auth_jwt -- tofu:factory --- vault_auth_jwt_role_gitea_cicd
git_code_tofu_vault -..-> kvv2
git_code_tofu_vault -..-> google/credentials
linkStyle 0,1 stroke:#ff3,stroke-width:1px,color:DarkKhaki;
linkStyle 2,3,5,6 stroke:#f3f,stroke-width:2px,color:DarkOrange;
git_tools -.-o argocd_tools
argocd_tools -.-> pgbouncer
argocd_tools -.-> vault
argocd_tools -.-> vault-secret-operator
argocd_tools o--o argocd
linkStyle 7,8,9,10,11 stroke:#3ff,stroke-width:3px,color:DarkSlateBlue;
git_tools_tofu_vault -..-> vault_auth_k8s -- sa:vso --- vault_auth_k8s_role_vso
git_tools_tofu_vault -..-> webapp/config
git_tools_tofu_vault -..-> vault_transit
git_tools_tofu_vault -..-> vault_postgres
vault_auth_k8s ---> k3s
vault_postgres --> pgbouncer x==> postgres; webapp_deployment --> pgbouncer
linkStyle 12,14,15,16 stroke:#f3f,stroke-width:2px,color:DarkOrange;
linkStyle 18,19,20 stroke:gold,stroke-width:2px;
vault_transit x---x vault-secret-operator
vault-secret-operator x---x vault_auth_k8s_role_vso
vault_auth_jwt_role_gitea_cicd x--x policy_default
vault_auth_k8s_role_vso x--x policy_vso
creds/webapp -.-> webapp_credentials
creds/webapp -.-> vault-secret-operator
vault-secret-operator -.-> webapp_postgres_creds_secret
webapp/config -.-> vault-secret-operator
vault-secret-operator -.-> webapp_config_secret
argocd_webapp -.-> k3s_ns_webapp
webapp --o webapp_deployment
webapp_postgres_creds_secret --o webapp_deployment
webapp_deployment --> webapp_service_account
vault_auth_jwt -- tofu:tools --- vault_auth_jwt_role_gitea_cicd_webapp_ops
vault_auth_jwt_role_gitea_cicd_webapp_ops x--x policy_webapp_ops
vault_auth_k8s -- sa:webapp --- vault_auth_k8s_role_webapp x-- tofu:webapp --x policy_webapp
git_webapp_tofu_vault -.-> vault_auth_k8s_role_webapp
git_webapp_tofu_vault -.-> creds/webapp
root_credentials x--x postgres_db
webapp_credentials x--x webapp_db
tools_playbook --> vault_creds_editor_role
vault_creds_editor_role -. change password .-> webapp_credentials
vault_postgres x--x vault_creds_editor_role