pgbouncer: &pgbouncer_config nodeSelector: kubernetes.io/hostname: pi2 # close to postgres instance config: adminUser: "admin" adminPassword: "admin" authUser: &authUser pgbouncer_auth authPassword: *authUser databases: "*": host: "192.168.1.202" # kubernetes.io/hostname=pi2 ip port: 5432 pgbouncer: auth_type: scram-sha-256 auth_query: SELECT uname, phash FROM user_lookup($1) ignore_startup_parameters: extra_float_digits # unsupported jdbc extra_float_digits=2 argument # Ce pgbouncer est PARTAGÉ (crowdsec, plausible, kadans, + le compte que # Vault utilise sur la base `postgres`). Ce qu'un client laisse derrière # lui sur une connexion serveur, le client SUIVANT en hérite : le reset # est la SEULE barrière entre deux clients d'un même pool. # # `DEALLOCATE ALL` ne nettoie QUE les requêtes préparées — d'où sa mise en # place (07e2c6d, « prepared statement already exists » de crowdsec). # Tout le reste de l'état de session passait au suivant. MESURÉ contre un # pgbouncer **1.23.1** — la version RÉELLEMENT déployée (image # ghcr.io/icoretech/pgbouncer-docker:1.23.1-fixed, chart pgbouncer-2.3.1), # montée avec CETTE configuration extraite du cluster (session, # pool_size=1) : le client 2, qui n'avait rien demandé, héritait de # `work_mem=17MB`, du `LISTEN canal_test` du client 1, de sa table TEMP — # et de son `SET ROLE`, au point de créer des tables appartenant à un # autre rôle que le sien. # # Portée de la fuite, mesurée et non supposée : les pools sont partitionnés # par (base, utilisateur) — 210 pools, aucun ne mélange deux bases ni deux # comptes. Le seul héritier possible d'un `SET ROLE` posé par kadans-api # est un client de la base `kadans` avec le MÊME identifiant éphémère, # c'est-à-dire kadans-api elle-même. Défaut d'hygiène, pas brèche # inter-applications. # # `DISCARD ALL` est le défaut de pgbouncer, et c'est un SUR-ENSEMBLE strict # des deux valeurs qui l'ont précédé ici : il contient `DEALLOCATE ALL` # (donc le correctif crowdsec est conservé — vérifié : deux clients # successifs préparent le même nom sans erreur) ET # `SELECT pg_advisory_unlock_all()` (la valeur que pose le sous-chart). # # Il ne peut RIEN casser pour un client vivant : en `pool_mode = session` # la connexion serveur n'est rendue qu'à la déconnexion du client, donc le # reset ne court jamais entre deux requêtes d'une même session. Vérifié : # table TEMP, `SET work_mem` et `LISTEN` d'un client VIVANT survivent. # # ⚠⚠ CE QUE CETTE LIGNE REND FRAGILE — et c'est l'inverse de ce qu'on croit. # # `pool_mode` n'est PAS déclaré ici, donc il vaut `session`, le défaut. # C'est ce qui rend `DISCARD ALL` sans danger. **Le jour où quelqu'un # écrira `pool_mode: transaction`, il cassera kadans-api en silence** : # son `SET ROLE` est posé UNE FOIS à l'ouverture (`AfterConnect`, db.go), # et en transaction pooling `DISCARD ALL` court ENTRE deux transactions — # donc le rôle est effacé avant les migrations suivantes. MESURÉ, les # quatre combinaisons, propriétaire de la table créée : # # session + DEALLOCATE ALL → rôle stable ✅ (mais la fuite reste) # session + DISCARD ALL → rôle stable ✅ ← ce qu'on déploie # transaction + DEALLOCATE ALL → rôle stable ✅ (par ACCIDENT : la fuite # qu'on referme est ce qui le sauvait) # transaction + DISCARD ALL → rôle ÉPHÉMÈRE ❌ le défaut du 28/07, # qui a mis l'API à terre une demi-journée # # Et `poserRoleProprietaire` ne peut pas le voir : sa relecture de # `current_role` a lieu à l'ouverture, où le rôle est encore correct. # Ce qui couvre ce cas, c'est la ceinture Vault (`ALTER ROLE … SET ROLE`, # module app_roles) : un défaut de rôle survit à `DISCARD ALL`. **Avant de # passer en transaction pooling, vérifier que les baux Vault ont tourné.** server_reset_query: DISCARD ALL # défaut pgbouncer — ⚠ ne pas réduire : voir ci-dessus server_idle_timeout: 7200 pgbouncerExporter: enabled: false tool: # kind: 'SubChart' or 'HelmChart', if subchart then uncomment Chart.yaml dependency, else comment and use tool library with helm chart template kind: 'SubChart' repo: https://icoretech.github.io/helm chart: pgbouncer version: 2.3.1 values: *pgbouncer_config