Le RBAC Snowflake échoue rarement parce qu'il manque des rôles. Il échoue parce qu'il y en a trop, et que personne ne sait qui a accès à quoi.
GRANT direct aux utilisateurs_DEV, _PRD, _RCT)ACCOUNTADMIN réservé aux opérations exceptionnellesLe modèle fonctionne en trois couches :
FR_DATA_ENGINEER_DEV)AR_BRZ_RAW_READ_DEV)
Les Access Roles portent uniquement des privilèges techniques sur des objets. Ils ne sont jamais assignés directement à un utilisateur.
-- Lecture sur les tables brutes du bronze
CREATE ROLE AR_BRZ_RAW_READ_DEV;
GRANT USAGE ON DATABASE BRONZE_DEV TO ROLE AR_BRZ_RAW_READ_DEV;
GRANT USAGE ON SCHEMA BRONZE_DEV.RAW TO ROLE AR_BRZ_RAW_READ_DEV;
GRANT SELECT ON ALL TABLES IN SCHEMA BRONZE_DEV.RAW
TO ROLE AR_BRZ_RAW_READ_DEV;
-- Écriture dans le silver (Data Engineer uniquement)
CREATE ROLE AR_SLV_RAW_WRITE_DEV;
GRANT USAGE ON DATABASE SILVER_DEV TO ROLE AR_SLV_RAW_WRITE_DEV;
GRANT USAGE ON SCHEMA SILVER_DEV.RAW TO ROLE AR_SLV_RAW_WRITE_DEV;
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA SILVER_DEV.RAW
TO ROLE AR_SLV_RAW_WRITE_DEV;
Convention de nommage : AR_<SCHEMA>_<OBJET>_<PRIVILEGE>_<ENV>.
Sans Future Grants, chaque nouvelle table créée doit être GRANT-ée à la main. Avec, Snowflake applique automatiquement les privilèges à tout futur objet du schéma.
-- Toute nouvelle table du bronze sera lisible par AR_BRZ_RAW_READ_DEV
GRANT SELECT ON FUTURE TABLES IN SCHEMA BRONZE_DEV.RAW
TO ROLE AR_BRZ_RAW_READ_DEV;
-- Idem pour les vues
GRANT SELECT ON FUTURE VIEWS IN SCHEMA BRONZE_DEV.RAW
TO ROLE AR_BRZ_RAW_READ_DEV;
-- Toute nouvelle table du silver sera insérable par AR_SLV_RAW_WRITE_DEV
GRANT SELECT, INSERT, UPDATE, DELETE
ON FUTURE TABLES IN SCHEMA SILVER_DEV.RAW
TO ROLE AR_SLV_RAW_WRITE_DEV;
Les Functional Roles représentent des profils métier : un Data Engineer n'a pas les mêmes accès qu'un Analyste. Ils héritent des Access Roles, jamais l'inverse.
CREATE ROLE FR_DATA_ENGINEER_DEV;
CREATE ROLE FR_DATA_ANALYST_DEV;
-- Data Engineer : lecture bronze + écriture silver + lecture gold
GRANT ROLE AR_BRZ_RAW_READ_DEV TO ROLE FR_DATA_ENGINEER_DEV;
GRANT ROLE AR_SLV_RAW_WRITE_DEV TO ROLE FR_DATA_ENGINEER_DEV;
GRANT ROLE AR_GLD_REPORT_READ_DEV TO ROLE FR_DATA_ENGINEER_DEV;
-- Analyste : lecture seule sur gold (pas d'accès au bronze)
GRANT ROLE AR_GLD_REPORT_READ_DEV TO ROLE FR_DATA_ANALYST_DEV;
Convention : FR_<PROFIL>_<ENV>. Un Data Engineer DEV ne doit jamais hériter de droits d'un Data Engineer PRD.
L'utilisateur reçoit un seul Functional Role. Snowflake résout la chaîne d'héritage automatiquement.
-- ✅ Bon : un seul rôle, héritage automatique
GRANT ROLE FR_DATA_ENGINEER_DEV TO USER mikael.paulhiout;
GRANT ROLE FR_DATA_ANALYST_DEV TO USER alice.duval;
-- ⛔ Mauvais : grants directs sur la personne = impossible à auditer
GRANT SELECT ON TABLE BRONZE_DEV.RAW.SALES
TO USER mikael.paulhiout; -- 🚫 à proscrire
Pour qu'un utilisateur puisse se connecter, il faut aussi lui donner un rôle par défaut :
ALTER USER mikael.paulhiout
SET DEFAULT_ROLE = FR_DATA_ENGINEER_DEV;
Pour les plateformes à fort volume, ajouter :
-- Par défaut, le propriétaire d'un schéma peut GRANT à qui il veut.
-- En Managed Access, seul le propriétaire du schéma (souvent un rôle de plateforme)
-- peut accorder des droits, pas le propriétaire de la table.
ALTER SCHEMA SILVER_DEV.RAW
SET MANAGED ACCESS;
Après ça, seul SYSADMIN (ou un rôle technique avec OWNERSHIP sur le schéma) peut faire des GRANT dans ce schéma. Les CREATE TABLE continuent de fonctionner, mais le créateur de la table n'en devient pas propriétaire.
-- Un Database Role "DATA_ENGINEER" portable cross-database
CREATE DATABASE ROLE ANALYTICS_DEV.DR_DATA_ENGINEER;
-- Grant sur tous les warehouses techniques
GRANT USAGE ON WAREHOUSE DEV_DEN_WH
TO DATABASE ROLE ANALYTICS_DEV.DR_DATA_ENGINEER;
-- Un seul grant à faire évoluer quand un nouveau domaine est ajouté
GRANT DATABASE ROLE ANALYTICS_DEV.DR_DATA_ENGINEER
TO ROLE FR_DATA_ENGINEER_DEV;
# access_role.tf
resource "snowflake_role" "ar_brz_raw_read_dev" {
name = "AR_BRZ_RAW_READ_DEV"
}
resource "snowflake_grant_privileges_to_role" "ar_brz_raw_read_dev" {
role_name = snowflake_role.ar_brz_raw_read_dev.name
on_schema_object {
future {
object_type_plural = "TABLES"
in_schema = "BRONZE_DEV.RAW"
}
privileges = ["SELECT"]
}
}
# functional_role.tf
resource "snowflake_role" "fr_data_engineer_dev" {
name = "FR_DATA_ENGINEER_DEV"
}
resource "snowflake_role_grants" "fr_data_engineer_dev" {
role_name = snowflake_role.fr_data_engineer_dev.name
roles = [
snowflake_role.ar_brz_raw_read_dev.name,
snowflake_role.ar_slv_raw_write_dev.name,
snowflake_role.ar_gld_report_read_dev.name,
]
}
terraform plan devient votre audit d'accès. Un git log vous dit qui a changé quoi et quand.
Le RBAC n'est pas une contrainte. C'est ce qui permet à votre plateforme de scaler : ajouter un nouveau domaine = créer un nouveau schéma + un Access Role, jamais de GRANT à la main. Et le jour où l'audit SOC2 demande "qui a accès à quoi ?", la réponse tient en une requête.