Eymoutiers, le 20 octobre 2025
Nouvel épisode de notre série dédiée à l’industrialisation de PostgreSQL : après le déploiement d’instances Postgres à grande échelle et la gestion homogène des sauvegardes Postgres avec pglift, nous allons cette fois nous pencher sur la question de la sécurité.
Les bases de données sont les cibles ultimes des attaques informatiques
Les bases de données contiennent les informations les plus précieuses d’une organisation : données personnelles, informations financières, secrets commerciaux, dossiers médicaux, etc. Elles représentent donc le point névralgique et un bastion à protéger au cœur de chaque système d’information.
PostgreSQL propose bien sûr un large panel de mesures internes pour la sécurité :
un controle des accès très fin avec le fichier pg_hba.conf, le chiffrement
TLS des communications, un système de roles/permissions sophitiqué ou encore
les règles RLS pour filtrer les lectures lignes par lignes.
Mais qu’en est-il de l’environnement dans lequel PostgreSQL évolue ? En particulier, comment protéger l’instance PostgreSQL depuis l’extérieur ?

SELinux est le standard de l’industrie
SELinux (pour “Security-Enhanced Linux”) répond à cette question en ajoutant
une couche de sécurité supplémentaire au-delà du système de permissions
traditionnel. Développé initialement par la NSA, SELinux applique des politiques
de sécurité strictes qui définissent précisément quels processus peuvent accéder
à quelles ressources (fichiers, ports réseau, etc.). Chaque processus est ainsi
isolé et confiné dans un contexte spécifique. Concrètement, si un utilisateur
(non privilégié) se voit accorder des privilèges sudo, il peut contourner ces
restrictions : le mode Mandatory Access Control (MAC) est alors contourné, et
la sécurité des services en cours d’exécution ne peut plus être garantie.
Concernant PostgreSQL, bien qu’il ne soit pas lancé en root, un accès privilégié
(via sudo) est souvent nécessaire pour gérer (activer, démarrer, stopper,…) les
services liés aux instances via systemd. Définir une politique SELinux devient
alors complexe, surtout avec les autres composants de la stack PostgreSQL, comme
pgBackRest ou Patroni. Cela soulève la question du juste équilibre entre permettre
aux DBA de gérer PostgreSQL (et les services annexes), tout en préservant la sécurité
globale du système.
Voir notre article ci-dessous pour un exemple concret:
https://blog.dalibo.com/2014/10/06/Confiner_PostgreSQL_avec_SELinux.html
Ansible augmente la surface d’attaque
La difficulté augmente également lorsque l’on passe à l’échelle supérieure et que l’on veut piloter un parc d’instances avec un outil d’orchestration comme Ansible.
Pour gérer chaque instance PostgreSQL, le nœud de contrôle Ansible va se connecter en SSH à chaque serveur et devra acquérir les privilèges superutilisateur pour certaines opérations, notamment pour manipuler le service Postgres.
Par exemple:
- name: Enabling postgresql services
become: true
ansible.builtin.service:
name: postgresql
state: started
enabled: true
Ici la ligne become: true permet de devenir root le temps de réaliser la tâche
pour vérifier l’état du service et de l’activer et démarrer si nécessaire.
Cette simple ligne semble anodine, mais implique que l’utilisateur lançant le playbook
peut acquérir les droits superutilisateur à tout moment sur un nœud distant.
Concrètement, cela signifie que l’utilisateur pilotant les playbooks Ansible est
de facto root sur l’ensemble du parc d’instances Postgres.

C’est en cela qu’Ansible peut élargir la surface d’attaque vers PostgreSQL. En effet, le nœud de contrôle est une cible de choix pour les attaquants : plutôt que d’attaquer directement les bases de données qui sont généralement les éléments les plus protégés, ils tenteront d’accéder indirectement aux instances en passant par des points d’entrées moins bien sécurisés et plus facile d’accès.
Bien sûr, il est possible de restreindre les commandes accessibles via des solutions d’élévation
de privilèges comme sudo, doas ou d’autres mécanismes similaires, notamment en configurant
leurs fichiers de contrôle (par exemple /etc/sudoers pour sudo). Cependant, cela ajoute une
couche supplémentaire de complexité et augmente le risque d’erreur de configuration.
Séparer les rôles pour mieux confiner Postgres
La solution consiste à revenir à la racine du problème. Dans le cycle de vie d’une instance Postgres, 2 types d’intervenant sont impliqués.
- Un rôle “sysadmin” chargé de préparer la machine qui hébergera PostgreSQL en installant tous les paquets logiciels nécessaires.
- Un rôle “dba” chargé de créer les instances Postgres et garantir leur bon fonctionnement.
Pour chacun de ces deux rôles, on assigne un et un seul utilisateur système.
Le rôle “sysadmin” aura les droits de l’utilisateur root, tandis que
le rôle dba se limitera à des droits restreints nécessaires à la gestion des instances
PostgreSQL. Dans les exemples qui suivent, nous utiliserons l’utilisateur postgres.
Concrètement cela signifie que l’on veut interdire aux DBA d’acquérir les
privilèges root via sudo et lui interdire d’utiliser become: true
dans ses playbooks Ansible !
Les services utilisateur de Systemd : un trésor caché
Mais cela semble impossible puisque le service Postgres est lancé en tant
que root via une commande du type sudo systemctl start postgresql ?
C’est ici qu’entre en jeu le “mode user” de systemd, un mode de fonctionnement
largement méconnu et sous-estimé. En effet, la commande systemctl --user
permet à chaque utilisateur de démarrer/arrêter/activer/désactiver ses propres
services.
Dans le cas de PostgreSQL, on fera généralement tourner le service avec
l’utilisateur système postgres mais il est possible d’utiliser n’importe
quel autre utilisateur. On stockera les données (PGDATA) dans le dossier $HOME
de l’utilisateur plutot que dans le dossier traditionnel /var/lib/postgres.
Enfin il est nécessaire d’activer la fonction lingering pour l’utilisateur,
qui permet au service de continuer à tourner, même après la déconnexion de
l’utilisateur. Cette fonction est activée par la commande ci-dessous:
loginctl enable-linger <utilisateur>
pglift : la sécurité par défaut
En tant qu’outil de déploiement, pglift tire pleinement partie de systemd et
de ce mode utilisateur.
Lorsque systemd est activé, pglift utilise le mode utilisateur par défaut.
Concrètement la commande pglift instance create initialise une nouvelle instance
et crée une unité de service systemd pour l’utilisateur postgres.
Désormais, l’utilisateur postgres peut manipuler son instance sans utiliser
la commande sudo. De même, il peut créer une instance avec un playbook
Ansible sans utiliser become: true.
Par exemple :
- name: Create and configure my postgresql instances
hosts: localhost
tasks:
- name: Create production instance
dalibo.pglift.instance:
name: prod
state: started
port: ""
settings:
max_connections: 100
shared_buffers: 1GB
unix_socket_directories: /tmp
shared_preload_libraries: pg_stat_statements, passwordcheck
Atout majeur de ce confinement du service postgres : cela rend l’activation de
SELinux complètement trivial ! Puisque le processus PostgreSQL tourne dans
le contexte de l’utilisateur système postgres, les accès aux ressources sont
déjà encadrés par les droits d’accès standard.
En d’autres termes, si un attaquant arrive à compromettre une instance
PostgreSQL créée avec pglift, il ne pourra pas “sortir” du rôle postgres
et n’aura pas accès à des ressources non-autorisées.
Cette approche permet également d’isoler plusieurs instances PostgreSQL exécutées sous des comptes utilisateurs distincts. Chaque instance dispose de son propre répertoire de données, accessible uniquement à l’utilisateur qui l’exécute. Ainsi, les données ne sont ni accessibles ni modifiables par d’autres comptes, y compris l’utilisateur postgres. Ce cloisonnement, basé sur les permissions classiques du système de fichiers, assure une séparation stricte et efficace des environnements basée sur des mécanismes éprouvés.
Etablir une politique de sécurité à grande échelle
En résumé, pglift vous permet facilement et par défaut de:
- Séparer clairement les rôles “sysadmin” et “dba”
- Activer SELinux sans configuration complexe
- Interdire
sudoà l’utilisateurpostgres - Éradiquer la clause
become: truedes playbooks PostgreSQL
Il existe évidement d’autres mesures de sécurité à mettre en place pour compléter l’arsenal de protection de vos bases de données. On peut notamment citer :
- Imposer les accès nominatifs avec un annuaire externe et ldap2pg
- Anonymiser les données sur les environnements secondaires (dev, testing) avec PostgreSQL Anonymizer
- Tracer toutes les interactions des utilisateurs avec pgaudit
- Compartimenter les processus et les ressources de PostgreSQL grace espaces de noms (“namespaces”) de Linux
De vastes sujets, que nous arborderons peut-être à l’occasion d’un prochain article !
Crédit Photo: Pew Nguyen