Skip to Content

Chapitre 11.2 — Accès & pg_hba.conf

⏱️ TL;DR — C’est le chapitre sécurité de la base. PostgreSQL contrôle qui se connecte en deux couches : listen_addresses dans postgresql.conf décide sur quelles interfaces réseau le serveur écoute (par défaut : local seulement, et on n’y touche pas sans raison), et pg_hba.conf décide qui peut se connecter, à quelle base, depuis quelle IP, avec quelle méthode. Le piège mortel : mettre listen_addresses = '*' et laisser le port 5432 ouvert sur Internet — c’est offrir tes données au premier scanner venu. La règle : app sur le même VPS → connexion locale, base jamais exposée. Base distante → tunnel SSH ou TLS + IP whitelistée, jamais le port nu.

🎯 Objectifs

  • Comprendre les deux couches de contrôle d’accès : listen_addresses puis pg_hba.conf.
  • Lire et écrire une règle pg_hba.conf (colonnes local/host, base, rôle, IP, méthode).
  • Distinguer les méthodes peer, scram-sha-256, md5, trust et savoir laquelle utiliser.
  • Ne jamais exposer le port de la base à Internet, et savoir pourquoi.
  • Choisir la bonne approche selon que l’app est locale ou distante.

Deux portes, dans l’ordre

Une tentative de connexion à PostgreSQL franchit deux contrôles successifs. D’abord, le serveur écoute-t-il seulement sur l’interface d’où vient la demande ? C’est listen_addresses. Ensuite, existe-t-il une règle qui autorise ce rôle, sur cette base, depuis cette IP ? C’est pg_hba.conf (HBA = Host-Based Authentication). Les deux doivent dire oui. On les prend dans l’ordre.

Couche 1 — listen_addresses : sur quelles interfaces

Le fichier postgresql.conf (souvent dans /etc/postgresql/<version>/main/) contient la directive qui décide des interfaces réseau d’écoute :

# /etc/postgresql/<version>/main/postgresql.conf # Valeur par defaut prudente : ecoute uniquement sur la boucle locale listen_addresses = 'localhost'

Avec localhost, le serveur n’accepte des connexions que depuis la machine elle-même (127.0.0.1 et la socket Unix). Une machine extérieure ne peut même pas atteindre le service — c’est parfait quand l’app tourne sur le même VPS.

⚠️ Piège — Mettre listen_addresses = '*' « pour que ça marche » quand une connexion échoue. Le * fait écouter le serveur sur toutes les interfaces, y compris l’IP publique. Combiné à un pare-feu mal réglé, ton port 5432 devient joignable depuis le monde entier. Les bots scannent ce port en permanence et testent des mots de passe. Ne change listen_addresses que si tu as une raison précise (une base réellement distante), et alors uniquement pour l’IP concernée, pas *.

Après toute modification de postgresql.conf, il faut recharger le service :

sudo systemctl restart postgresql # listen_addresses exige un redemarrage

Couche 2 — pg_hba.conf : qui, où, comment

C’est ici que se joue l’essentiel. Le fichier pg_hba.conf est une liste de règles, une par ligne, lue de haut en bas : PostgreSQL applique la première règle qui correspond et s’arrête. L’ordre compte énormément — une règle large placée trop haut peut court-circuiter une règle stricte placée en dessous.

Chaque règle a cette forme :

# TYPE BASE RÔLE ADRESSE MÉTHODE local all all peer host formacampus formacampus 127.0.0.1/32 scram-sha-256 host formacampus formacampus ::1/128 scram-sha-256

Colonne par colonne :

  • TYPE : local = connexion par socket Unix (même machine, sans réseau) ; host = connexion TCP/IP (avec une adresse). (hostssl = TCP chiffré obligatoire.)
  • BASE : la base visée (formacampus, ou all).
  • RÔLE : le rôle concerné (formacampus, ou all).
  • ADRESSE : pour host, l’IP ou le réseau autorisé en notation CIDR. 127.0.0.1/32 = cette machine uniquement (IPv4), ::1/128 = idem en IPv6.
  • MÉTHODE : comment prouver son identité (voir ci-dessous).

Ici, l’app locale se connecte en host sur 127.0.0.1 avec un mot de passe chiffré (scram-sha-256). Aucune règle n’autorise une IP publique : personne de l’extérieur ne peut se connecter, même si le réseau le permettait.

Les méthodes d’authentification

MéthodeCe qu’elle faitQuand l’utiliser
peerFait confiance à l’identité Linux de l’utilisateur (socket locale).Connexions local d’admin (sudo -u postgres psql).
scram-sha-256Vérifie un mot de passe via un hachage moderne et robuste.Le choix par défaut pour les connexions applicatives.
md5Mot de passe via un hachage ancien et faible.Hérité ; à remplacer par scram-sha-256.
trustAucune vérification : toute connexion est acceptée.Jamais en production. Danger absolu.

🔒 Sécurité — Bannis trust de toute base accessible autrement qu’en socket locale strictement contrôlée : il laisse entrer sans mot de passe. Préfère scram-sha-256 à md5 (plus sûr, standard actuel). Et rappelle-toi que pg_hba.conf est lu dans l’ordre : une ligne host all all 0.0.0.0/0 trust placée en haut ruinerait toute la sécurité en dessous. Relis toujours ton fichier de haut en bas comme le fait PostgreSQL.

Après modification de pg_hba.conf, un rechargement suffit (pas de redémarrage complet) :

sudo systemctl reload postgresql # recharge pg_hba.conf sans couper les connexions

Le piège mortel : exposer le port 5432

Répétons-le parce que c’est la faute qui coûte le plus cher. PostgreSQL écoute par défaut sur le port 5432. Le rendre joignable depuis Internet — via listen_addresses = '*' et un pare-feu qui laisse passer 5432 — revient à publier l’adresse de tes données. Les scanners automatisés trouvent ce port en minutes, puis tentent des connexions en boucle.

⚠️ Piège — « Ma base est protégée par un mot de passe, donc l’exposer n’est pas grave. » Faux. Un port ouvert, c’est une surface d’attaque : bruteforce du mot de passe, exploitation d’une faille du serveur, saturation. La défense n’est pas « un bon mot de passe », c’est ne pas être joignable du tout. Le pare-feu (UFW, Partie 5) doit bloquer 5432 en entrée : sudo ufw deny 5432 — ou, mieux, ne jamais l’ouvrir.

🐚 Au terminal — Vérifier que la base n’écoute qu’en local, et que le port n’est pas ouvert :

sudo ss -tulpn | grep 5432 # tu dois voir 127.0.0.1:5432 (et ::1) -- PAS 0.0.0.0:5432 sudo ufw status # 5432 ne doit apparaitre NULLE PART en "ALLOW" depuis l'exterieur

Si ss montre 0.0.0.0:5432, le serveur écoute sur toutes les interfaces : reviens à listen_addresses = 'localhost'. Le duo ss (qui écoute où) + ufw status (quels ports ouverts) est ton contrôle réflexe.

App locale vs base distante

Deux situations, deux stratégies.

L’app est sur le même VPS que la base (le cas recommandé, et celui de FormaCampus). Alors aucune exposition n’est nécessaire : l’app se connecte en localhost (ou par socket Unix), listen_addresses reste localhost, pg_hba.conf n’autorise que 127.0.0.1, et le pare-feu bloque 5432. C’est simple, rapide (pas de réseau), et inattaquable de l’extérieur.

La base est sur une autre machine (app et base séparées). Là, il faut bien que la connexion traverse un réseau — mais jamais en clair sur Internet. Deux options propres :

  • Tunnel SSH : la connexion base passe dans un canal SSH déjà chiffré et authentifié (ssh -L, voir Partie 4). Le port 5432 reste fermé au monde ; seul SSH est exposé. Simple et très sûr.
  • TLS + IP whitelistée : pg_hba.conf en hostssl (chiffrement obligatoire), et le pare-feu n’autorise 5432 que depuis l’IP fixe du serveur applicatif. Chiffrement en transit et filtrage réseau, les deux ensemble.

💡 Réflexe — Avant de séparer app et base sur deux machines, demande-toi si tu en as vraiment besoin. Pour la majorité des projets, tout sur un seul VPS est plus simple, plus rapide et plus sûr. On ne distribue que quand la charge ou l’architecture l’imposent — et alors on chiffre et on filtre systématiquement.

🧭 Sur FormaCampus — L’API Symfony et Postgres cohabitent sur le même VPS. Résultat : listen_addresses = 'localhost', un pg_hba.conf qui n’autorise que le rôle formacampus sur la base formacampus depuis 127.0.0.1 en scram-sha-256, et UFW qui bloque 5432 en entrée. La base de données d’apprenants n’est littéralement pas joignable depuis Internet. Le jour où l’équipe voudra un réplica de lecture sur une autre machine, elle passera par un tunnel SSH, jamais par le port nu.

✏️ Exercices

Exercice 1 — Lis la règle. Explique en français ce qu’autorise cette ligne, et si elle te semble sûre : host all all 0.0.0.0/0 md5

✅ Solution

Elle autorise n’importe quel rôle (all) à se connecter à n’importe quelle base (all) en TCP (host) depuis n’importe quelle IP au monde (0.0.0.0/0), avec un mot de passe haché en md5. C’est très dangereux : 0.0.0.0/0 ouvre à tout Internet, et md5 est un hachage faible. À proscrire. Une règle saine restreint la base, le rôle, l’IP (127.0.0.1/32) et utilise scram-sha-256.

Exercice 2 — Écris les règles. Ton app formacampus tourne sur le même VPS que la base. Écris les lignes pg_hba.conf qui autorisent uniquement ce rôle à joindre sa base en local (IPv4 et IPv6), par mot de passe moderne. Précise aussi le réglage listen_addresses associé.

✅ Solution

# TYPE BASE RÔLE ADRESSE MÉTHODE host formacampus formacampus 127.0.0.1/32 scram-sha-256 host formacampus formacampus ::1/128 scram-sha-256

Avec, dans postgresql.conf :

listen_addresses = 'localhost'

Ainsi le serveur n’écoute qu’en local, et seules les connexions du rôle formacampus vers sa base depuis la machine elle-même sont acceptées. Ne pas oublier sudo systemctl reload postgresql après avoir touché pg_hba.conf.

🧠 Quiz de révision

1. Quelles sont les deux couches qui contrôlent l’accès à PostgreSQL, et dans quel ordre ?

D’abord listen_addresses (postgresql.conf) : sur quelles interfaces réseau le serveur écoute. Ensuite pg_hba.conf : quel rôle, sur quelle base, depuis quelle IP, avec quelle méthode. Les deux doivent autoriser la connexion.

2. Pourquoi listen_addresses = '*' est-il dangereux ?

Le * fait écouter le serveur sur toutes les interfaces, dont l’IP publique. Si le pare-feu laisse passer 5432, la base devient joignable de tout Internet : scans et bruteforce garantis. On garde localhost sauf besoin précis, et jamais *.

3. Dans une règle pg_hba.conf, quelle est la différence entre local et host ?

local = connexion par socket Unix (même machine, sans passer par le réseau). host = connexion TCP/IP, avec une adresse dans la colonne suivante. hostssl impose en plus le chiffrement TLS.

4. Pourquoi préférer scram-sha-256 à md5, et ne jamais utiliser trust ?

scram-sha-256 est un mécanisme de mot de passe moderne et robuste ; md5 est un hachage ancien et faible. trust n’effectue aucune vérification : toute connexion correspondante est acceptée sans mot de passe — inacceptable en production.

5. L’app et la base sont sur le même VPS. Faut-il ouvrir le port 5432 dans le pare-feu ?

Non. La connexion se fait en local (localhost/socket), qui ne traverse pas le pare-feu. On bloque 5432 en entrée. Ouvrir ce port n’apporterait aucun bénéfice et créerait une surface d’attaque.


Chapitre suivant : MySQL / MariaDB — l’alternative à PostgreSQL, son geste de durcissement, et quand la préférer.

Last updated on