Zéro-confiance PG : verrou hostssl + détection de version robuste

- pg_hba hostssl (serveur_postgresql_tls_force) : refuse les connexions
  non-TLS du réseau. Posé après validation des 3 clients en verify-full.
- Fix : tls_dir sous /etc/postgresql collisionnait avec la détection de
  version (find|sort|last prenait 'tls') → filtre numérique ^[0-9]+$ +
  tls_dir déplacé sous /var/lib/postgresql/tls.

Prouvé : non-TLS rejeté (« aucun chiffrement »), TLS accepté, 3 apps 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-07-04 20:46:53 -04:00
parent d26651a432
commit 204910edbf
4 changed files with 25 additions and 3 deletions

View file

@ -2,7 +2,23 @@
## 2026-07-04
### Ajouté
- **Zéro-confiance : flux PostgreSQL entièrement chiffré et vérifié.** PG sert désormais son **cert
step-ca** (vérifiable contre root_ca) au lieu du snakeoil, et **refuse** toute connexion non-TLS
du réseau (`hostssl` dans pg_hba). Les 3 clients passent en **verify-full** : keycloak
(`db-url-properties sslmode=verify-full`), forgejo (`SSL_MODE=verify-full` + `PGSSLROOTCERT`),
IcingaDB (`tls: true` + `ca`). Prérequis posés : `client_pki` sur data-sql-01 (cert), et
**`root_ca.crt` en 0644** (cert public, requis par les clients TLS non-root). cert-sync PG
(motif `.path`, owned postgres) + reload de l'instance `postgresql@NN-main`. Vars :
`serveur_postgresql_tls_actif`/`_tls_force`, `serveur_*_db_sslmode`/`_ca`. Prouvé de bout en bout
(cert Set-OPS CA servi, apps 200, non-TLS rejeté « aucun chiffrement », TLS accepté).
### Corrigé
- **PG : détection de version robuste (collision avec un répertoire non-numérique).** Placer le
`tls_dir` sous `/etc/postgresql/` faisait choisir `tls` comme « version » de cluster
(`find | sort | last`) → configs déployées au mauvais endroit (verrou hostssl inopérant).
Corrigé : détection filtrée aux dossiers **numériques** (`^[0-9]+$`) + `tls_dir` déplacé sous
`/var/lib/postgresql/tls`.
- **Renouvellement de cert : recharger le VRAI consommateur (bug latent de flotte).** Le
`cert-renewer@.service` (client_pki) renouvelait le cert sur disque mais son `ExecStartPost`
rechargeait un service nommé *d'après le cert* (`%i` = FQDN), inexistant → **nginx (et postfix,

View file

@ -44,4 +44,8 @@ serveur_postgresql_tls_actif: false
serveur_postgresql_tls_source_cert: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.crt"
serveur_postgresql_tls_source_cle: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.key"
serveur_postgresql_tls_source_ca: "/etc/step/certs/root_ca.crt"
serveur_postgresql_tls_dir: "/etc/postgresql/tls"
serveur_postgresql_tls_dir: "/var/lib/postgresql/tls"
# Verrou zero-confiance : hostssl dans pg_hba => refuse toute connexion NON-TLS.
# N'activer qu'apres avoir confirme que TOUS les clients sont en TLS (sinon coupure).
serveur_postgresql_tls_force: false

View file

@ -17,7 +17,8 @@
ansible.builtin.set_fact:
serveur_postgresql_version_effective: >-
{{ serveur_postgresql_version
or (serveur_postgresql_clusters.files | map(attribute='path') | map('basename') | sort | last | default('')) }}
or (serveur_postgresql_clusters.files | map(attribute='path') | map('basename')
| select('match', '^[0-9]+$') | sort | last | default('')) }}
- name: Refuser si aucun cluster PostgreSQL n'est present
ansible.builtin.assert:

View file

@ -6,6 +6,7 @@ local all all peer
host all all 127.0.0.1/32 {{ serveur_postgresql_methode_auth }}
host all all ::1/128 {{ serveur_postgresql_methode_auth }}
# Reseaux internes autorises (clients applicatifs).
# tls_force => hostssl : SEULES les connexions TLS sont acceptees (zero-confiance).
{% for reseau in serveur_postgresql_reseaux_autorises %}
host all all {{ reseau }} {{ serveur_postgresql_methode_auth }}
{{ 'hostssl' if serveur_postgresql_tls_force | default(false) else 'host' }} all all {{ reseau }} {{ serveur_postgresql_methode_auth }}
{% endfor %}