🔝 Retour au Sommaire
Imaginez cette situation frustrante : vous accordez soigneusement des permissions à un utilisateur sur toutes les tables existantes. Tout fonctionne parfaitement. Puis, quelques jours plus tard, une nouvelle table est créée dans la base de données. Soudain, votre utilisateur ne peut plus y accéder car il n'a pas de permissions sur cette nouvelle table !
C'est exactement le problème que résout ALTER DEFAULT PRIVILEGES : cette commande permet de définir des permissions par défaut qui seront automatiquement appliquées à tous les nouveaux objets créés dans le futur.
Cette section explique comment utiliser cette fonctionnalité puissante pour automatiser la gestion des permissions et éviter les oublis.
Voici une situation typique qui cause des problèmes :
-- Étape 1 : Configuration initiale
CREATE SCHEMA app_data;
CREATE TABLE app_data.users (
id SERIAL PRIMARY KEY,
username VARCHAR(50)
);
CREATE ROLE app_backend LOGIN PASSWORD 'secure_pass';
-- Étape 2 : Accorder les permissions
GRANT USAGE ON SCHEMA app_data TO app_backend;
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA app_data TO app_backend;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA app_data TO app_backend;
-- ✅ Tout fonctionne : app_backend peut accéder à la table usersQuelques jours plus tard, un développeur crée une nouvelle table :
-- Nouvelle table créée par postgres (superuser)
CREATE TABLE app_data.orders (
id SERIAL PRIMARY KEY,
user_id INTEGER,
total NUMERIC
);Et maintenant, l'application rencontre une erreur :
-- L'application essaie d'accéder à la nouvelle table
SELECT * FROM app_data.orders;
-- ❌ Erreur : permission denied for table ordersPourquoi ? Parce que les permissions accordées avec GRANT ... ON ALL TABLES ne s'appliquent qu'aux tables existantes au moment de la commande. Les nouvelles tables n'héritent pas automatiquement de ces permissions.
Une solution serait de ré-exécuter les GRANT à chaque fois qu'une nouvelle table est créée :
-- Après chaque CREATE TABLE...
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA app_data TO app_backend;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA app_data TO app_backend; ❌ Problèmes :
- Fastidieux et répétitif
- Facile à oublier
- Erreurs garanties en production
- Ne s'intègre pas bien dans les pipelines d'automatisation
-- Configuration des permissions par défaut
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_backend; Maintenant, toutes les nouvelles tables et séquences créées dans app_data auront automatiquement ces permissions accordées à app_backend ! 🎉
ALTER DEFAULT PRIVILEGES
[ FOR ROLE role_name ]
[ IN SCHEMA schema_name ]
abbreviated_grant_or_revoke;Composants :
- FOR ROLE : Spécifie le rôle qui créera les objets (optionnel)
- IN SCHEMA : Limite aux objets créés dans un schéma spécifique (optionnel)
- abbreviated_grant_or_revoke : GRANT ou REVOKE habituel, mais sans nommer d'objet spécifique
ALTER DEFAULT PRIVILEGES [ FOR ROLE creating_role ] [ IN SCHEMA schema_name ]
GRANT { privilege [, ...] | ALL [ PRIVILEGES ] }
ON { TABLES | SEQUENCES | FUNCTIONS | TYPES | SCHEMAS }
TO { role_name | PUBLIC } [, ...]
[ WITH GRANT OPTION ];ALTER DEFAULT PRIVILEGES fonctionne pour :
| Type d'Objet | Permissions Applicables | Exemple d'Usage |
|---|---|---|
| TABLES | SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, ALL | Tables et vues |
| SEQUENCES | USAGE, SELECT, UPDATE, ALL | Séquences (SERIAL, IDENTITY) |
| FUNCTIONS | EXECUTE | Fonctions et procédures stockées |
| TYPES | USAGE | Types personnalisés |
| SCHEMAS | USAGE, CREATE | Schémas (rarement utilisé) |
Configuration complète pour une application avec lecture/écriture :
-- 1. Créer le schéma
CREATE SCHEMA app_data;
-- 2. Créer le rôle
CREATE ROLE app_backend LOGIN PASSWORD 'secure_password';
-- 3. Permissions sur le schéma
GRANT USAGE ON SCHEMA app_data TO app_backend;
-- 4. Permissions sur les objets EXISTANTS
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app_data TO app_backend;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA app_data TO app_backend;
-- 5. 🌟 Permissions par DÉFAUT sur les FUTURS objets
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_backend; Test :
-- Créer une nouvelle table
CREATE TABLE app_data.products (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
-- app_backend a AUTOMATIQUEMENT les permissions !
-- (se connecter en tant que app_backend pour tester)
SELECT * FROM app_data.products; -- ✅ Fonctionne !
INSERT INTO app_data.products (name) VALUES ('Test'); -- ✅ Fonctionne ! Pour un utilisateur qui doit uniquement consulter les données :
-- Créer le rôle
CREATE ROLE app_readonly LOGIN PASSWORD 'secure_password';
-- Permission sur le schéma
GRANT USAGE ON SCHEMA app_data TO app_readonly;
-- Permissions sur les tables existantes
GRANT SELECT ON ALL TABLES IN SCHEMA app_data TO app_readonly;
-- 🌟 Permissions par défaut sur les futures tables
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_readonly; Maintenant, chaque nouvelle table sera automatiquement accessible en lecture à app_readonly.
Par défaut, ALTER DEFAULT PRIVILEGES s'applique aux objets créés par l'utilisateur qui exécute la commande. Pour spécifier un autre créateur, utilisez FOR ROLE :
-- Imaginons que "developpeur" crée les tables
CREATE ROLE developpeur LOGIN PASSWORD 'pass';
GRANT CREATE ON SCHEMA app_data TO developpeur;
-- Configuration des permissions par défaut pour les objets créés par "developpeur"
ALTER DEFAULT PRIVILEGES FOR ROLE developpeur IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE developpeur IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_readonly; Explication :
- Quand
developpeurcrée une table dansapp_data, elle aura automatiquement :- SELECT, INSERT, UPDATE pour
app_backend - SELECT pour
app_readonly
- SELECT, INSERT, UPDATE pour
Pour appliquer les mêmes permissions à plusieurs schémas, il faut répéter la commande :
-- Configuration pour le schéma app_data
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE ON TABLES TO app_backend;
-- Configuration pour le schéma app_logs
ALTER DEFAULT PRIVILEGES IN SCHEMA app_logs
GRANT SELECT, INSERT, UPDATE ON TABLES TO app_backend;
-- Configuration pour le schéma app_cache
ALTER DEFAULT PRIVILEGES IN SCHEMA app_cache
GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON TABLES TO app_backend; Les fonctions ont un comportement par défaut particulier : elles sont exécutables par PUBLIC. Pour le changer :
-- Révoquer l'accès public par défaut sur les nouvelles fonctions
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
-- Accorder uniquement à app_backend
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT EXECUTE ON FUNCTIONS TO app_backend; Maintenant, les nouvelles fonctions créées dans app_data ne seront exécutables que par app_backend.
Pour accorder toutes les permissions possibles :
-- Administrateur avec tous les droits sur les futures tables
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT ALL PRIVILEGES ON TABLES TO admin_role;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT ALL PRIVILEGES ON SEQUENCES TO admin_role;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT ALL PRIVILEGES ON FUNCTIONS TO admin_role; Tout comme on peut GRANT par défaut, on peut aussi REVOKE par défaut.
-- Révoquer SELECT par défaut
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
REVOKE SELECT ON TABLES FROM app_readonly;
-- Révoquer EXECUTE sur les fonctions de PUBLIC
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC; Par défaut, PostgreSQL accorde EXECUTE sur les nouvelles fonctions à PUBLIC. Pour une sécurité maximale :
-- Révoquer l'accès public par défaut
ALTER DEFAULT PRIVILEGES
REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
-- Dans chaque schéma aussi
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
-- Puis accorder explicitement selon les besoins
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT EXECUTE ON FUNCTIONS TO app_backend; La commande \ddp affiche les default privileges configurés :
\ddpRésultat exemple :
Default access privileges
Owner | Schema | Type | Access privileges
--------+----------+----------+-------------------
postgres | app_data | table | app_backend=arwd/postgres
app_readonly=r/postgres
postgres | app_data | sequence | app_backend=rU/postgres
\ddp app_dataPour une analyse plus détaillée, interrogez la table système pg_default_acl :
SELECT
pg_get_userbyid(d.defaclrole) AS owner,
n.nspname AS schema,
CASE d.defaclobjtype
WHEN 'r' THEN 'table'
WHEN 'S' THEN 'sequence'
WHEN 'f' THEN 'function'
WHEN 'T' THEN 'type'
WHEN 'n' THEN 'schema'
END AS object_type,
d.defaclacl AS default_acl
FROM pg_default_acl d
LEFT JOIN pg_namespace n ON d.defaclnamespace = n.oid
WHERE n.nspname = 'app_data' -- Filtrer par schéma
OR d.defaclnamespace = 0; -- ou global (pas de schéma spécifique)SELECT
pg_get_userbyid(d.defaclrole) AS "Owner/Creator",
COALESCE(n.nspname, 'ALL SCHEMAS') AS "Schema",
CASE d.defaclobjtype
WHEN 'r' THEN 'Tables'
WHEN 'S' THEN 'Sequences'
WHEN 'f' THEN 'Functions'
WHEN 'T' THEN 'Types'
END AS "Object Type",
(aclexplode(d.defaclacl)).grantee::regrole AS "Grantee",
(aclexplode(d.defaclacl)).privilege_type AS "Privilege"
FROM pg_default_acl d
LEFT JOIN pg_namespace n ON d.defaclnamespace = n.oid
ORDER BY 1, 2, 3, 4; Résultat exemple :
Owner/Creator | Schema | Object Type | Grantee | Privilege
---------------+----------+-------------+--------------+-----------
postgres | app_data | Tables | app_backend | INSERT
postgres | app_data | Tables | app_backend | SELECT
postgres | app_data | Tables | app_backend | UPDATE
postgres | app_data | Tables | app_readonly | SELECT
postgres | app_data | Sequences | app_backend | USAGE
-- En dev, les développeurs ont tous les droits
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL PRIVILEGES ON TABLES TO developpeurs;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL PRIVILEGES ON SEQUENCES TO developpeurs;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT ALL PRIVILEGES ON FUNCTIONS TO developpeurs; -- En prod, séparation stricte des rôles
-- Application : seulement ce qui est nécessaire
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE ON TABLES TO app_production;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_production;
-- Lecture seule : analystes et reporting
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO readonly_group;
-- Admin : tous les droits pour maintenance
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT ALL PRIVILEGES ON TABLES TO admin_production; Chaque client a son propre schéma, avec des permissions automatiques :
-- Fonction pour créer un nouveau tenant avec default privileges
CREATE OR REPLACE FUNCTION create_tenant(tenant_name TEXT)
RETURNS VOID AS $$
DECLARE
schema_name TEXT;
app_role TEXT;
admin_role TEXT;
BEGIN
schema_name := 'tenant_' || tenant_name;
app_role := 'app_' || tenant_name;
admin_role := 'admin_' || tenant_name;
-- Créer le schéma
EXECUTE format('CREATE SCHEMA %I', schema_name);
-- Créer les rôles
EXECUTE format('CREATE ROLE %I LOGIN PASSWORD ''changeme''', app_role);
EXECUTE format('CREATE ROLE %I LOGIN PASSWORD ''changeme''', admin_role);
-- Permissions sur le schéma
EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', schema_name, app_role);
EXECUTE format('GRANT ALL ON SCHEMA %I TO %I', schema_name, admin_role);
-- 🌟 Default privileges pour l'application
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT SELECT, INSERT, UPDATE ON TABLES TO %I',
schema_name, app_role);
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT USAGE ON SEQUENCES TO %I',
schema_name, app_role);
-- 🌟 Default privileges pour l'admin
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL PRIVILEGES ON TABLES TO %I',
schema_name, admin_role);
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL PRIVILEGES ON SEQUENCES TO %I',
schema_name, admin_role);
RAISE NOTICE 'Tenant % créé avec succès', tenant_name;
END;
$$ LANGUAGE plpgsql;
-- Utilisation
SELECT create_tenant('acme_corp');
SELECT create_tenant('globex'); Maintenant, chaque fois qu'une nouvelle table est créée dans le schéma d'un tenant, les permissions sont automatiquement configurées !
Dans un pipeline CI/CD moderne avec des migrations de base de données (Flyway, Liquibase, Alembic) :
-- Script d'initialisation (exécuté une fois)
-- init_permissions.sql
-- Rôle qui exécute les migrations
CREATE ROLE migration_runner LOGIN PASSWORD 'secure_pass';
GRANT CREATE ON SCHEMA app_data TO migration_runner;
-- Rôle de l'application
CREATE ROLE app_backend LOGIN PASSWORD 'secure_pass';
GRANT USAGE ON SCHEMA app_data TO app_backend;
-- 🌟 Default privileges : les objets créés par migration_runner
-- seront automatiquement accessibles à app_backend
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_data
GRANT EXECUTE ON FUNCTIONS TO app_backend; Workflow :
- Le pipeline CI/CD se connecte avec
migration_runner - Il crée des tables, fonctions, etc.
app_backenda automatiquement accès à tout ce qui est créé- Pas besoin de GRANT manuels dans chaque migration !
Dans une grande organisation avec plusieurs équipes :
-- Équipe Backend crée des tables applicatives
CREATE ROLE equipe_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE equipe_backend IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_production;
-- Équipe Analytics crée des tables de reporting
CREATE ROLE equipe_analytics;
ALTER DEFAULT PRIVILEGES FOR ROLE equipe_analytics IN SCHEMA reporting
GRANT SELECT ON TABLES TO data_scientists;
-- Équipe DevOps crée des tables de monitoring
CREATE ROLE equipe_devops;
ALTER DEFAULT PRIVILEGES FOR ROLE equipe_devops IN SCHEMA monitoring
GRANT SELECT ON TABLES TO grafana_user; ❌ Erreur courante :
-- En tant que postgres (superuser)
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend;
-- Un développeur crée une table
-- (connecté en tant que developpeur, pas postgres)
CREATE TABLE app_data.new_table (id INTEGER);
-- app_backend n'a PAS les permissions ! 😱Pourquoi ? Les default privileges s'appliquent au rôle qui exécute ALTER DEFAULT PRIVILEGES, pas à tous les créateurs potentiels.
✅ Solution :
-- Spécifier explicitement FOR ROLE
ALTER DEFAULT PRIVILEGES FOR ROLE developpeur IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend;
-- Ou, en tant que postgres, pour soi-même
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend; ALTER DEFAULT PRIVILEGES ne s'applique qu'aux futurs objets, pas aux existants.
❌ Erreur :
-- Des tables existent déjà
CREATE TABLE app_data.old_table (id INTEGER);
-- Configuration des default privileges
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend;
-- app_backend ne peut PAS accéder à old_table ! 😱✅ Solution : Toujours combiner avec GRANT pour les objets existants :
-- Permissions sur les objets EXISTANTS
GRANT SELECT ON ALL TABLES IN SCHEMA app_data TO app_backend;
-- Permissions sur les FUTURS objets
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend; Les colonnes SERIAL/IDENTITY créent des séquences. Il faut configurer les default privileges pour les séquences aussi :
❌ Erreur :
-- Seulement les tables
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT ON TABLES TO app_backend;
-- Nouvelle table avec SERIAL
CREATE TABLE app_data.orders (
id SERIAL PRIMARY KEY, -- Crée une séquence !
total NUMERIC
);
-- INSERT échoue !
INSERT INTO app_data.orders (total) VALUES (100);
-- ❌ Erreur : permission denied for sequence orders_id_seq✅ Solution :
-- Toujours inclure les séquences
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_backend; -- ✅ ALTER DEFAULT PRIVILEGES s'applique par schéma. Si vous utilisez plusieurs schémas, répétez la configuration :
-- Configuration pour CHAQUE schéma
ALTER DEFAULT PRIVILEGES IN SCHEMA schema1
GRANT SELECT ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA schema2
GRANT SELECT ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA schema3
GRANT SELECT ON TABLES TO app_backend;
-- Ou créer une fonction helper pour éviter la répétition
CREATE OR REPLACE FUNCTION setup_default_privileges(schema_name TEXT, role_name TEXT)
RETURNS VOID AS $$
BEGIN
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT SELECT, INSERT, UPDATE ON TABLES TO %I',
schema_name, role_name);
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT USAGE ON SEQUENCES TO %I',
schema_name, role_name);
END;
$$ LANGUAGE plpgsql;
-- Utilisation
SELECT setup_default_privileges('schema1', 'app_backend');
SELECT setup_default_privileges('schema2', 'app_backend'); Meilleur moment : Lors de la création de la base de données et des schémas.
-- Template de configuration initiale
CREATE DATABASE nouvelle_app;
\c nouvelle_app
-- Sécurisation
REVOKE ALL ON DATABASE nouvelle_app FROM PUBLIC;
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
-- Schémas
CREATE SCHEMA app_data;
CREATE SCHEMA app_logs;
-- Rôles
CREATE ROLE app_backend LOGIN PASSWORD 'secure_pass';
CREATE ROLE app_readonly LOGIN PASSWORD 'secure_pass';
-- Permissions schéma
GRANT USAGE ON SCHEMA app_data, app_logs TO app_backend, app_readonly;
-- 🌟 Default privileges (dès le début !)
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_logs
GRANT SELECT, INSERT ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES IN SCHEMA app_logs
GRANT USAGE ON SEQUENCES TO app_backend; Commentez vos configurations :
-- ==================================================
-- DEFAULT PRIVILEGES CONFIGURATION
-- Appliqué par: DBA Team
-- Date: 2024-01-15
-- Raison: Automatiser les permissions pour CI/CD
-- ==================================================
-- Application backend : lecture/écriture complète
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_backend;
-- Analystes : lecture seule
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_data
GRANT SELECT ON TABLES TO analytics_team;
-- ==================================================Spécifiez toujours FOR ROLE pour être explicite, même si c'est pour votre propre rôle :
-- ✅ Explicite et clair
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend;
-- ❌ Ambigu (s'applique au rôle courant, mais lequel ?)
ALTER DEFAULT PRIVILEGES IN SCHEMA app_data
GRANT SELECT ON TABLES TO app_backend; Créez un script pour vérifier que les default privileges sont correctement configurés :
-- verify_default_privileges.sql
DO $$
DECLARE
expected_count INTEGER;
actual_count INTEGER;
BEGIN
RAISE NOTICE '=== VERIFICATION DEFAULT PRIVILEGES ===';
-- Vérifier les default privileges sur les tables dans app_data
SELECT COUNT(*) INTO actual_count
FROM pg_default_acl d
JOIN pg_namespace n ON d.defaclnamespace = n.oid
WHERE n.nspname = 'app_data'
AND d.defaclobjtype = 'r'; -- 'r' = tables
expected_count := 1; -- On attend 1 configuration
IF actual_count >= expected_count THEN
RAISE NOTICE '✓ Default privileges configurés sur tables: % configurations', actual_count;
ELSE
RAISE WARNING '✗ Default privileges MANQUANTS sur tables ! Trouvé: %, Attendu: au moins %',
actual_count, expected_count;
END IF;
-- Vérifier les séquences
SELECT COUNT(*) INTO actual_count
FROM pg_default_acl d
JOIN pg_namespace n ON d.defaclnamespace = n.oid
WHERE n.nspname = 'app_data'
AND d.defaclobjtype = 'S'; -- 'S' = sequences
IF actual_count >= 1 THEN
RAISE NOTICE '✓ Default privileges configurés sur séquences';
ELSE
RAISE WARNING '✗ Default privileges MANQUANTS sur séquences !';
END IF;
END $$;Intégrez ALTER DEFAULT PRIVILEGES dans vos scripts d'infrastructure as code :
-- migrations/V001__init_database.sql (Flyway)
-- Création des structures
CREATE SCHEMA app_data;
CREATE ROLE app_backend LOGIN PASSWORD '${APP_PASSWORD}';
-- Permissions de base
GRANT USAGE ON SCHEMA app_data TO app_backend;
-- Default privileges pour le futur
ALTER DEFAULT PRIVILEGES FOR ROLE ${MIGRATION_USER} IN SCHEMA app_data
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE ${MIGRATION_USER} IN SCHEMA app_data
GRANT USAGE ON SEQUENCES TO app_backend; Vérifiez régulièrement que les default privileges sont toujours pertinents :
-- Lister tous les default privileges configurés
SELECT
pg_get_userbyid(d.defaclrole) AS creator,
COALESCE(n.nspname, 'ALL') AS schema,
CASE d.defaclobjtype
WHEN 'r' THEN 'tables'
WHEN 'S' THEN 'sequences'
WHEN 'f' THEN 'functions'
END AS type,
d.defaclacl AS acl
FROM pg_default_acl d
LEFT JOIN pg_namespace n ON d.defaclnamespace = n.oid
ORDER BY 1, 2, 3; Si vous souhaitez supprimer complètement une configuration de default privileges :
-- Révoquer tous les default privileges d'un rôle sur les tables
ALTER DEFAULT PRIVILEGES FOR ROLE developpeur IN SCHEMA app_data
REVOKE ALL PRIVILEGES ON TABLES FROM app_backend;
-- Révoquer pour les séquences
ALTER DEFAULT PRIVILEGES FOR ROLE developpeur IN SCHEMA app_data
REVOKE ALL PRIVILEGES ON SEQUENCES FROM app_backend; -- Vérifier qu'il n'y a plus de default privileges
\ddp app_data| Aspect | GRANT | ALTER DEFAULT PRIVILEGES |
|---|---|---|
| Cible | Objets existants | Futurs objets |
| Moment d'application | Immédiat | À la création de l'objet |
| Durée | Permanent (jusqu'à REVOKE) | Permanent (règle pour le futur) |
| Modification rétroactive | Oui (affecte immédiatement) | Non (pas d'effet sur l'existant) |
| Cas d'usage | Corriger les permissions | Automatiser les permissions |
Conclusion : Utilisez LES DEUX :
- GRANT pour les objets qui existent déjà
- ALTER DEFAULT PRIVILEGES pour les objets qui seront créés
Voici un exemple complet de configuration pour un environnement de production :
-- ========================================
-- CONFIGURATION PRODUCTION
-- Database: app_production
-- ========================================
-- Connexion
\c app_production
-- ----------------------------------------
-- 1. SÉCURISATION DE BASE
-- ----------------------------------------
REVOKE ALL ON DATABASE app_production FROM PUBLIC;
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
-- ----------------------------------------
-- 2. CRÉATION DES SCHÉMAS
-- ----------------------------------------
CREATE SCHEMA app_core; -- Tables métier principales
CREATE SCHEMA app_analytics; -- Tables analytiques
CREATE SCHEMA app_audit; -- Logs d'audit
-- ----------------------------------------
-- 3. CRÉATION DES RÔLES
-- ----------------------------------------
-- Application principale
CREATE ROLE app_backend LOGIN PASSWORD 'CHANGE_ME_IN_PROD';
-- Service de reporting
CREATE ROLE app_reporting LOGIN PASSWORD 'CHANGE_ME_IN_PROD';
-- Équipe data science
CREATE ROLE data_scientists;
-- Rôle pour les migrations (utilisé par CI/CD)
CREATE ROLE migration_runner LOGIN PASSWORD 'CHANGE_ME_IN_PROD';
-- ----------------------------------------
-- 4. PERMISSIONS SUR LES SCHÉMAS
-- ----------------------------------------
GRANT USAGE ON SCHEMA app_core TO app_backend, app_reporting, data_scientists;
GRANT CREATE ON SCHEMA app_core TO migration_runner;
GRANT USAGE ON SCHEMA app_analytics TO app_reporting, data_scientists;
GRANT CREATE ON SCHEMA app_analytics TO migration_runner;
GRANT USAGE ON SCHEMA app_audit TO app_backend;
GRANT CREATE ON SCHEMA app_audit TO app_backend;
-- ----------------------------------------
-- 5. PERMISSIONS SUR OBJETS EXISTANTS
-- ----------------------------------------
-- (Au cas où des tables existent déjà)
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app_core TO app_backend;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA app_core TO app_backend;
GRANT SELECT ON ALL TABLES IN SCHEMA app_core TO app_reporting;
GRANT SELECT ON ALL TABLES IN SCHEMA app_analytics TO app_reporting, data_scientists;
-- ----------------------------------------
-- 6. 🌟 DEFAULT PRIVILEGES (Le cœur !)
-- ----------------------------------------
-- Tables créées par migration_runner dans app_core
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_core
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_core
GRANT SELECT ON TABLES TO app_reporting;
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_core
GRANT USAGE ON SEQUENCES TO app_backend;
-- Tables créées par migration_runner dans app_analytics
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_analytics
GRANT SELECT ON TABLES TO app_reporting, data_scientists;
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_analytics
GRANT USAGE ON SEQUENCES TO app_reporting;
-- Tables d'audit créées par l'application elle-même
ALTER DEFAULT PRIVILEGES FOR ROLE app_backend IN SCHEMA app_audit
GRANT SELECT, INSERT ON TABLES TO app_backend;
ALTER DEFAULT PRIVILEGES FOR ROLE app_backend IN SCHEMA app_audit
GRANT USAGE ON SEQUENCES TO app_backend;
-- Fonctions : sécurité maximale
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_core
REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
ALTER DEFAULT PRIVILEGES FOR ROLE migration_runner IN SCHEMA app_core
GRANT EXECUTE ON FUNCTIONS TO app_backend;
-- ----------------------------------------
-- 7. VÉRIFICATION
-- ----------------------------------------
\echo '=== Vérification Default Privileges ==='
\ddp app_core
\ddp app_analytics
\ddp app_audit
\echo '=== Configuration terminée ==='ALTER DEFAULT PRIVILEGES est une fonctionnalité essentielle pour :
- ✅ Automatiser : Plus besoin de GRANT à chaque création d'objet
- ✅ Sécuriser : Les permissions sont consistantes et prédictibles
- ✅ Simplifier : Moins d'erreurs humaines et de permissions manquantes
- ✅ Intégrer : S'intègre parfaitement dans les pipelines CI/CD
- ✅ Maintenir : Configuration centralisée et documentée
- Utilisez TOUJOURS ALTER DEFAULT PRIVILEGES dans vos bases de production
- Combinez avec GRANT pour couvrir les objets existants ET futurs
- Spécifiez FOR ROLE pour être explicite sur qui crée les objets
- N'oubliez pas les séquences (SERIAL/IDENTITY)
- Configurez dès le début de votre projet
- Documentez vos choix de configuration
- Vérifiez régulièrement avec
\ddpou des requêtes SQL
ALTER DEFAULT PRIVILEGES transforme la gestion des permissions d'un processus manuel et source d'erreurs en un système automatisé et fiable. C'est un investissement minimal pour un gain énorme en robustesse et en sérénité ! 🎯