Skip to content

Latest commit

 

History

History
653 lines (465 loc) · 19.1 KB

File metadata and controls

653 lines (465 loc) · 19.1 KB

🔝 Retour au Sommaire

19.6.1. Hardening Sécurité

Introduction

Le hardening (durcissement en français) est l'ensemble des pratiques visant à renforcer la sécurité d'un système en réduisant sa surface d'attaque. Pour PostgreSQL en production, cela signifie configurer et maintenir votre base de données de manière à minimiser les risques de compromission, de fuite de données ou d'accès non autorisé.

Cette section vous guidera à travers les mesures essentielles de sécurisation d'une instance PostgreSQL, que vous soyez développeur ou DevOps débutant dans l'administration de bases de données.

Principe fondamental : La sécurité repose sur une approche en défense en profondeur (defense in depth) - plusieurs couches de protection pour qu'une défaillance unique ne compromette pas l'ensemble du système.


Les Couches de Sécurité PostgreSQL

PostgreSQL offre plusieurs niveaux de protection :

  1. Réseau : Qui peut accéder au serveur ?
  2. Authentification : Qui êtes-vous ?
  3. Autorisation : Qu'avez-vous le droit de faire ?
  4. Chiffrement : Les données sont-elles protégées en transit et au repos ?
  5. Audit : Pouvons-nous tracer les actions ?
  6. Maintenance : Le système est-il à jour et surveillé ?

Chaque couche doit être configurée correctement pour garantir une sécurité optimale.


1. Sécurité Réseau

1.1. Limitation de l'Écoute Réseau

Par défaut, PostgreSQL écoute sur toutes les interfaces réseau. En production, vous devez restreindre cela.

Fichier : postgresql.conf

# ❌ Mauvaise pratique (par défaut dans certaines configs)
listen_addresses = '*'

# ✅ Bonne pratique : écouter uniquement sur localhost
listen_addresses = 'localhost'

# ✅ Ou spécifier les IPs autorisées
listen_addresses = '10.0.1.5,127.0.0.1'

Explication :

  • '*' : Accepte les connexions depuis n'importe quelle interface réseau (dangereux)
  • 'localhost' : Limite aux connexions locales uniquement
  • IPs spécifiques : Permet un contrôle granulaire

1.2. Configuration du Firewall

Ne vous reposez pas uniquement sur PostgreSQL - utilisez un firewall système (iptables, firewalld, nftables, ou les Security Groups en cloud).

Exemple avec firewalld (RHEL/CentOS) :

# Autoriser PostgreSQL uniquement depuis un réseau privé
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="10.0.1.0/24"
  port protocol="tcp" port="5432"
  accept'
sudo firewall-cmd --reload

Principe : Bloquez le port PostgreSQL (5432 par défaut) pour tout le monde, sauf les IPs/réseaux autorisés.

1.3. Modification du Port par Défaut (Optionnel)

Bien que la sécurité par l'obscurité ne soit pas une défense robuste, changer le port par défaut peut réduire le bruit des scans automatisés.

# postgresql.conf
port = 5433  # Au lieu de 5432

⚠️ Note : Ce n'est pas une mesure de sécurité forte, mais un complément. Ne vous y fiez jamais comme protection principale.


2. Authentification Robuste

2.1. Le Fichier pg_hba.conf

Le fichier pg_hba.conf (Host-Based Authentication) contrôle qui peut se connecter, depuis où, et comment.

Structure :

# TYPE  DATABASE  USER  ADDRESS      METHOD

2.2. Désactiver la Méthode "trust"

La méthode trust autorise les connexions sans mot de passe. Elle ne doit JAMAIS être utilisée en production.

# ❌ DANGEREUX - Jamais en production !
local   all       all                trust

# ✅ Bon - Exiger une authentification
local   all       all                scram-sha-256

2.3. Utiliser SCRAM-SHA-256

PostgreSQL 18 et versions récentes : MD5 est obsolète et déprécié. Utilisez SCRAM-SHA-256.

Configuration :

# postgresql.conf
password_encryption = scram-sha-256

pg_hba.conf :

# Connexions locales
local   all       all                scram-sha-256

# Connexions depuis le réseau interne
host    all       all   10.0.1.0/24  scram-sha-256

# Connexions SSL obligatoires depuis l'extérieur
hostssl all       all   0.0.0.0/0    scram-sha-256

Migration depuis MD5 :

-- Régénérer les mots de passe pour utiliser SCRAM
ALTER USER mon_user WITH PASSWORD 'nouveau_mot_de_passe';

2.4. Authentification OAuth 2.0 (Nouveauté PostgreSQL 18)

Pour les environnements modernes, PostgreSQL 18 introduit le support d'OAuth 2.0.

# pg_hba.conf
host all all 0.0.0.0/0 oauth issuer="https://auth.example.com"

Avantages :

  • Centralisation de l'authentification (IdP)
  • Support de l'authentification multi-facteurs (MFA)
  • Gestion simplifiée des identités

2.5. Authentification par Certificat Client

Pour les connexions automatisées (applications, réplication), utilisez des certificats SSL/TLS.

# pg_hba.conf
hostssl all app_user 0.0.0.0/0 cert clientcert=verify-full

Configuration :

  1. Générer un certificat client
  2. Configurer PostgreSQL pour vérifier le certificat
  3. L'application présente son certificat lors de la connexion

3. Principe du Moindre Privilège

3.1. Ne Pas Utiliser le Superutilisateur

Le rôle postgres (superutilisateur) a tous les droits. Ne l'utilisez jamais pour les applications.

Mauvaise pratique :

-- ❌ Application connectée en superutilisateur
GRANT ALL ON DATABASE myapp TO postgres;

Bonne pratique :

-- ✅ Créer un utilisateur dédié avec droits minimaux
CREATE ROLE app_user WITH LOGIN PASSWORD 'secure_password';  
GRANT CONNECT ON DATABASE myapp TO app_user;  
GRANT USAGE ON SCHEMA public TO app_user;  
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;  

3.2. Rôles Spécialisés

Créez des rôles pour chaque fonction :

-- Rôle lecture seule (reporting, analytics)
CREATE ROLE readonly;  
GRANT CONNECT ON DATABASE myapp TO readonly;  
GRANT USAGE ON SCHEMA public TO readonly;  
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;  
ALTER DEFAULT PRIVILEGES IN SCHEMA public  
  GRANT SELECT ON TABLES TO readonly;

-- Utilisateur de reporting
CREATE ROLE report_user LOGIN PASSWORD 'secure_password' IN ROLE readonly;

-- Rôle application (lecture/écriture limitée)
CREATE ROLE app_rw;  
GRANT CONNECT ON DATABASE myapp TO app_rw;  
GRANT USAGE ON SCHEMA public TO app_rw;  
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_rw;  

-- Utilisateur application
CREATE ROLE app_user LOGIN PASSWORD 'secure_password' IN ROLE app_rw;

3.3. Révocation des Privilèges par Défaut

PostgreSQL donne des droits par défaut sur le schéma public. Révoquez-les :

-- Révoquer les privilèges publics
REVOKE CREATE ON SCHEMA public FROM PUBLIC;  
REVOKE ALL ON DATABASE myapp FROM PUBLIC;  

3.4. Row-Level Security (RLS)

Pour aller plus loin, implémentez des politiques de sécurité au niveau des lignes.

-- Activer RLS sur une table
ALTER TABLE users ENABLE ROW LEVEL SECURITY;

-- Politique : chaque utilisateur ne voit que ses propres données
CREATE POLICY user_isolation ON users
  FOR ALL
  TO app_user
  USING (user_id = current_user::integer);

4. Chiffrement des Données

4.1. Chiffrement en Transit (SSL/TLS)

Obligatoire en production : Toutes les connexions doivent être chiffrées.

Configuration SSL :

  1. Générer les certificats :
# Certificat auto-signé (développement)
openssl req -new -x509 -days 365 -nodes -text \
  -out server.crt -keyout server.key \
  -subj "/CN=pgserver.example.com"

chmod 600 server.key  
chown postgres:postgres server.key server.crt  
  1. Configurer PostgreSQL :
# postgresql.conf
ssl = on  
ssl_cert_file = '/path/to/server.crt'  
ssl_key_file = '/path/to/server.key'  
ssl_min_protocol_version = 'TLSv1.3'  # PostgreSQL 18+  
  1. Forcer SSL dans pg_hba.conf :
# Seules les connexions SSL sont acceptées
hostssl all all 0.0.0.0/0 scram-sha-256

Nouveauté PostgreSQL 18 : Configuration TLS 1.3 avancée

# postgresql.conf
ssl_tls13_ciphers = 'TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256'

4.2. Mode FIPS (PostgreSQL 18)

Pour les environnements gouvernementaux ou réglementés (santé, finance) :

# postgresql.conf
ssl_fips_mode = on

FIPS (Federal Information Processing Standard) garantit l'utilisation d'algorithmes cryptographiques certifiés.

4.3. Chiffrement au Repos

PostgreSQL ne chiffre pas les données sur disque par défaut. Options :

  1. Chiffrement du système de fichiers :

    • LUKS (Linux)
    • BitLocker (Windows)
    • dm-crypt
  2. Transparent Data Encryption (TDE) :

    • Solutions commerciales (EnterpriseDB, Percona)
    • Extension pgcrypto pour chiffrement au niveau colonne (limité)
  3. Chiffrement Cloud natif :

    • AWS RDS : Encryption at rest
    • Azure : Transparent Data Encryption
    • GCP : Automatic encryption

Exemple pgcrypto (chiffrement colonnes sensibles) :

CREATE EXTENSION pgcrypto;

-- Chiffrer une donnée
INSERT INTO users (email, ssn_encrypted)  
VALUES ('user@example.com', pgp_sym_encrypt('123-45-6789', 'secret_key'));  

-- Déchiffrer
SELECT email, pgp_sym_decrypt(ssn_encrypted, 'secret_key') AS ssn  
FROM users;  

⚠️ Limitation : pgcrypto chiffre au niveau application, pas transparent, et n'est pas adapté pour tout le dataset.


5. Audit et Logging

5.1. Configuration des Logs

Activez un logging détaillé pour tracer les activités suspectes.

# postgresql.conf

# Activer le logging
logging_collector = on  
log_directory = 'log'  
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'  
log_rotation_age = 1d  
log_rotation_size = 100MB  

# Que logger ?
log_connections = on  
log_disconnections = on  
log_duration = off  # Attention, verbeux  
log_statement = 'ddl'  # DDL uniquement (CREATE, ALTER, DROP)  

# Log des erreurs et warnings
log_min_messages = warning  
log_min_error_statement = error  

# Durée des requêtes lentes
log_min_duration_statement = 1000  # Log si > 1 seconde

# Format du log (préfixe enrichi)
log_line_prefix = '%t [%p]: user=%u,db=%d,app=%a,client=%h '

Explication des paramètres :

  • log_connections/disconnections : Tracer qui se connecte
  • log_statement = 'ddl' : Auditer les modifications de schéma
  • log_min_duration_statement : Identifier les requêtes lentes
  • log_line_prefix : Enrichir les logs avec contexte (user, db, IP)

5.2. Extension pgAudit

Pour un audit plus fin (conformité SOX, PCI-DSS, GDPR) :

CREATE EXTENSION pgaudit;

Configuration :

# postgresql.conf
pgaudit.log = 'write, ddl'  # Auditer les écritures et DDL  
pgaudit.log_catalog = off   # Exclure les tables système  
pgaudit.log_parameter = on  # Logger les paramètres des requêtes  

Types d'audit :

  • READ : SELECT
  • WRITE : INSERT, UPDATE, DELETE, TRUNCATE
  • DDL : CREATE, ALTER, DROP
  • ROLE : GRANT, REVOKE
  • FUNCTION : Exécution de fonctions

5.3. Centralisation des Logs

Envoyez les logs vers un système centralisé (SIEM) :

  • Syslog : Configuration dans postgresql.conf

    log_destination = 'syslog'
    syslog_facility = 'LOCAL0'
    syslog_ident = 'postgres'
    
  • Solutions modernes :

    • ELK Stack (Elasticsearch, Logstash, Kibana)
    • Splunk
    • Datadog
    • AWS CloudWatch / Azure Monitor

6. Data Checksums (Intégrité des Données)

6.1. Activation des Checksums

Nouveauté PostgreSQL 18 : Les checksums de données sont activés par défaut lors de l'initialisation (initdb).

Pourquoi c'est important :

  • Détecte la corruption de données sur disque
  • Alerte en cas de problème matériel
  • Garantit l'intégrité physique

Vérifier l'état :

SHOW data_checksums;
-- Résultat attendu : on

Si désactivé (anciennes versions ou --no-data-checksums utilisé) :

  • Pour activer : Nécessite un pg_checksums en offline (cluster arrêté)
  • Ou recréer le cluster avec initdb --data-checksums

⚠️ Coût : Les checksums ont un léger impact performance (1-5%), mais c'est négligeable face au gain en détection d'erreurs.


7. Protection Contre les Attaques Courantes

7.1. Injection SQL (SQL Injection)

Bien que ce soit une responsabilité applicative, configurez PostgreSQL pour limiter les dégâts.

Côté PostgreSQL :

  • Limiter les permissions (voir section 3)
  • Désactiver les fonctions dangereuses pour les utilisateurs non admin

Côté application (rappel) :

  • Toujours utiliser des requêtes préparées (Prepared Statements)
  • Jamais de concaténation de chaînes pour construire du SQL

Exemple sécurisé (Python/psycopg3) :

# ✅ Bon - Requête préparée
cursor.execute(
    "SELECT * FROM users WHERE email = %s",
    (user_input,)
)

# ❌ Dangereux - Vulnérable à l'injection
cursor.execute(
    f"SELECT * FROM users WHERE email = '{user_input}'"
)

7.2. Limitation des Ressources par Utilisateur

Empêchez un utilisateur malveillant (ou buggé) de saturer le serveur.

-- Limiter les connexions par rôle
ALTER ROLE app_user CONNECTION LIMIT 10;

-- Timeout des requêtes (au niveau base ou rôle)
ALTER DATABASE myapp SET statement_timeout = '30s';  
ALTER ROLE app_user SET statement_timeout = '30s';  

-- Limiter la mémoire de travail
ALTER ROLE app_user SET work_mem = '64MB';

7.3. Désactiver les Fonctions Dangereuses

Certaines fonctions permettent l'exécution de code système.

-- Révoquer l'accès aux fonctions système sensibles
REVOKE EXECUTE ON FUNCTION pg_read_file(text) FROM PUBLIC;  
REVOKE EXECUTE ON FUNCTION pg_ls_dir(text) FROM PUBLIC;  

8. Maintenance Sécurité Régulière

8.1. Mises à Jour (Patches)

PostgreSQL publie des mises à jour de sécurité régulièrement.

Bonnes pratiques :

Exemple de stratégie :

  • Critique (CVE high) : Appliquer sous 7 jours
  • Important (CVE medium) : Appliquer sous 30 jours
  • Mineures : Appliquer au prochain cycle de maintenance

8.2. Revue des Comptes et Permissions

Audit régulier (mensuel ou trimestriel) :

-- Lister tous les rôles et leurs privilèges
\du

-- Lister les superutilisateurs
SELECT rolname FROM pg_roles WHERE rolsuper = true;

-- Vérifier les rôles sans mot de passe
SELECT rolname FROM pg_authid WHERE rolpassword IS NULL AND rolcanlogin = true;

-- Permissions sur les tables sensibles
SELECT grantee, privilege_type  
FROM information_schema.table_privileges  
WHERE table_name = 'users';  

Actions :

  • Désactiver les comptes inutilisés
  • Supprimer les permissions obsolètes
  • Forcer le renouvellement des mots de passe

8.3. Rotation des Mots de Passe

Imposez une politique de rotation :

-- Expiration du mot de passe
ALTER ROLE app_user VALID UNTIL '2026-03-01';

-- Forcer le changement au prochain login (via application)
ALTER ROLE app_user PASSWORD 'new_password' VALID UNTIL '2026-03-01';

Note : PostgreSQL ne force pas automatiquement le changement de mot de passe. C'est à gérer au niveau applicatif ou via un système IAM.

8.4. Surveillance des Vulnérabilités

Utilisez des outils de scan de vulnérabilités :

  • Lynis : Audit de sécurité système
  • OpenVAS : Scanner de vulnérabilités réseau
  • CloudWatch / Defender for SQL (Cloud) : Détection d'anomalies

9. Checklist de Hardening Sécurité

Voici une checklist récapitulative à valider avant la mise en production :

✅ Réseau

  • listen_addresses limité (pas '*')
  • Firewall configuré (seules IPs autorisées)
  • Port modifié si pertinent
  • Accès via VPN ou bastion host pour administration

✅ Authentification

  • Méthode trust désactivée dans pg_hba.conf
  • SCRAM-SHA-256 activé (pas MD5)
  • SSL/TLS obligatoire pour connexions externes
  • Certificats SSL valides et à jour
  • TLS 1.3 configuré (PostgreSQL 18)
  • OAuth 2.0 configuré si applicable

✅ Autorisation

  • Pas de connexions applicatives en superutilisateur
  • Rôles dédiés par fonction (app, readonly, admin)
  • Principe du moindre privilège appliqué
  • Privilèges PUBLIC révoqués
  • Row-Level Security (RLS) implémenté si nécessaire

✅ Chiffrement

  • SSL activé pour toutes les connexions
  • Certificats SSL valides (pas auto-signés en prod)
  • Chiffrement au repos (filesystem ou TDE)
  • Mode FIPS activé si requis

✅ Audit et Logging

  • Logging activé (connections, disconnections, DDL)
  • Logs centralisés (syslog, ELK, SIEM)
  • pgAudit installé et configuré (si conformité)
  • Rotation des logs configurée
  • Alertes configurées sur logs critiques

✅ Intégrité

  • Data checksums activés
  • Sauvegardes régulières et testées
  • Réplication configurée (HA)

✅ Protection Applicative

  • Requêtes préparées utilisées (pas de concaténation)
  • Timeouts configurés (statement_timeout)
  • Limites de connexions par rôle
  • Fonctions système désactivées pour users non-admin

✅ Maintenance

  • Process de mise à jour de sécurité défini
  • Audit des comptes et permissions mensuel
  • Rotation des mots de passe planifiée
  • Monitoring de sécurité actif
  • Documentation à jour (runbook sécurité)

10. Ressources Complémentaires

Documentation Officielle

Outils et Scripts

Standards de Sécurité

  • CIS PostgreSQL Benchmark : Guide de hardening
  • NIST Cybersecurity Framework
  • OWASP Database Security Cheat Sheet

Communauté


Conclusion

Le hardening sécurité n'est pas une étape unique, mais un processus continu :

  1. Configuration initiale : Appliquer les mesures de base
  2. Audit régulier : Vérifier les permissions, logs, mises à jour
  3. Adaptation : Ajuster en fonction des nouvelles menaces et besoins

Principe clé : Une sécurité efficace repose sur la défense en profondeur. Aucune mesure unique ne suffit - c'est la combinaison de toutes ces pratiques qui protège réellement votre base de données.

En suivant cette checklist et en maintenant une vigilance constante, vous réduisez considérablement la surface d'attaque de votre instance PostgreSQL et assurez la protection des données confiées à votre système.


Prochaine section : 19.6.2. Configuration optimale

⏭️ Configuration optimale