Dans l'article sur les accès, on a posé la base des accès ainsi que la gestion des rôles . Et dans l'article sur le masquage dynamique, on a ajouté une deuxième couche avec la quelle tu peux laisser un SELECT, mais contrôler ce que la personne a le droit de voir dans les colonnes sensibles.

Sauf qu'en vrai, tôt ou tard tu tombes sur ce cas un peu différent.

Tu veux bien donner accès à la table, tu veux même laisser toutes les colonnes visibles, mais tu ne veux pas que tout le monde voie toutes les lignes. Typiquement une table multi-pays, multi-filiales, ou multi-clients. Et là, si tu n'as pas de contrôle au niveau ligne, tu finis souvent par bricoler des vues filtrées, des copies de tables, ou des filtres côté BI. Ça marche, mais c'est rarement propre et pas top.

C'est exactement là que les Row Access Policies entrent en jeu.

⚠️
Nb : Comme le masquage dynamique, le Row Access Policies est une fonctionnalité qui est disponible que sur Enterprise Edition (ou +).

Le modèle à retenir

C'est simple, tu peux voir la sécurité Snowflake comme trois couches qui se complètent.

La première couche, c'est l'accès à l'objet et elle repend aux questions est-ce que tu peux faire un SELECT sur la table, est-ce que tu as USAGE sur la base, ou est-ce que tu as un warehouse utilisable etc.... C'est le monde des rôles et privilèges.

La deuxième couche, c'est ce que tu vois dans les colonnes, donc tu lis la table, mais certaines colonnes sont masquées selon ton rôle. C'est le Dynamic Data Masking.

La troisième couche, c'est quelles lignes tu as le droit de voir. Tu as accès à la table, tu peux même avoir accès à toutes les colonnes en clair, mais Snowflake va filtrer le résultat automatiquement selon une règle. C'est la Row Access Policy.

Et le point important, c’est que la policy ne supprime aucune donnée et ne change rien à ce qui est stocké. Elle s’applique au moment où tu exécutes la requête, un peu comme le dynamic masking. Si tu viens du monde Qlik, tu peux le voir comme une Section Access donc Snowflake évalue la règle à l’exécution et décide si la ligne est visible ou non.

Exemple complet

On part sur une table de ventes. Chaque ligne a un COUNTRY_CODE. L'objectif est simple. Le rôle France ne voit que la France, le rôle US ne voit que les US, et un rôle admin voit tout.

1) Table de test

CREATE DATABASE IF NOT EXISTS SALES_DB;
CREATE SCHEMA IF NOT EXISTS SALES_DB.MART_SALES;

CREATE OR REPLACE TABLE SALES_DB.MART_SALES.SALES (
  SALE_ID       NUMBER,
  COUNTRY_CODE  STRING,
  AMOUNT        NUMBER
);

INSERT INTO SALES_DB.MART_SALES.SALES VALUES
  (1, 'FR', 100),
  (2, 'US', 250),
  (3, 'DE', 180),
  (4, 'FR', 90);

2) Rôles

USE ROLE USERADMIN;

CREATE ROLE IF NOT EXISTS SALES_READ_FR;
CREATE ROLE IF NOT EXISTS SALES_READ_US;
CREATE ROLE IF NOT EXISTS SALES_RLS_ADMIN;
CREATE ROLE IF NOT EXISTS SALES_FULL_ACCESS;

Ensuite tu accordes la lecture sur la table aux rôles de lecture. Ici je ne réécris pas tout le modèle d'accès (tu l'as déjà détaillé dans ton article), mais l'idée reste la même : USAGE sur database et schema, SELECT sur table, et USAGE sur un warehouse si tu veux exécuter des requêtes.

3) Un schéma SECURITY pour les policies

USE ROLE SECURITYADMIN;

CREATE SCHEMA IF NOT EXISTS SALES_DB.SECURITY;

GRANT USAGE ON DATABASE SALES_DB TO ROLE SALES_RLS_ADMIN;
GRANT USAGE ON SCHEMA SALES_DB.SECURITY TO ROLE SALES_RLS_ADMIN;

GRANT CREATE ROW ACCESS POLICY ON SCHEMA SALES_DB.SECURITY TO ROLE SALES_RLS_ADMIN;
GRANT APPLY ROW ACCESS POLICY ON ACCOUNT TO ROLE SALES_RLS_ADMIN;

NB : Avoir un rôle admin dédié aux policies est recommandé. Ça te permet de le séparer des rôles métiers et d’éviter pas mal de dérives. Tu centralises la création et l’application des policies dans un rôle contrôlé, et tu limites le nombre de personnes qui peuvent toucher à la sécurité.

4) La Row Access Policy

Une Row Access Policy prend des paramètres (souvent une ou plusieurs colonnes) et renvoie un booléen. Si ça renvoie TRUE, la ligne est visible. Si ça renvoie FALSE, elle disparaît du résultat.

USE ROLE SALES_RLS_ADMIN;

CREATE OR REPLACE ROW ACCESS POLICY SALES_DB.SECURITY.ACCESS_ROWS_BY_COUNTRY
AS (country_code STRING)
RETURNS BOOLEAN ->
  CASE
    WHEN IS_ROLE_IN_SESSION('SALES_FULL_ACCESS') THEN TRUE
    WHEN IS_ROLE_IN_SESSION('SALES_READ_FR') AND country_code = 'FR' THEN TRUE
    WHEN IS_ROLE_IN_SESSION('SALES_READ_US') AND country_code = 'US' THEN TRUE
    ELSE FALSE
  END;

Petite astuce : utiliser IS_ROLE_IN_SESSION('...') te protège quand tu as des hiérarchies de rôles et des rôles "parents/enfants". Ça évite l'effet "j'ai le bon rôle quelque part mais ça ne match pas comme je pensais".

5) Appliquer la policy sur la table

USE ROLE SALES_RLS_ADMIN;

ALTER TABLE SALES_DB.MART_SALES.SALES
ADD ROW ACCESS POLICY SALES_DB.SECURITY.ACCESS_ROWS_BY_COUNTRY ON (COUNTRY_CODE);

6) Tester

Voir les données FR :

USE ROLE SALES_READ_FR;

SELECT * FROM SALES_DB.MART_SALES.SALES ORDER BY SALE_ID;

Voir les données US :

USE ROLE SALES_READ_US;

SELECT * FROM SALES_DB.MART_SALES.SALES ORDER BY SALE_ID;

Voir toutes les données :

USE ROLE SALES_FULL_ACCESS;

SELECT * FROM SALES_DB.MART_SALES.SALES ORDER BY SALE_ID;

Le piège qui revient tout le temps

Le piège classique, c'est de commencer simple, puis d'ajouter des conditions partout dans la policy, jusqu'à ce que ça devienne une usine à gaz très compliqué à maintenir.

Quand tu arrives à des règles du type “tel rôle voit tel ensemble de clients, sauf exceptions, sauf période, sauf produit, sauf région”, tu as intérêt à changer de stratégie. La bonne approche, c'est de mettre les droits dans une table de mapping claire (par exemple rôle → pays autorisés, ou rôle → liste de clients), et de garder la policy la plus lisible possible.

Row Access Policy et masquage dynamique

C'est un point important parce que beaucoup mélangent les deux.

Une Row Access Policy répond à "est-ce que tu vois cette ligne". Le masquage dynamique répond à "si tu vois la ligne, est-ce que tu vois la valeur réelle de cette colonne". Dans certain cas, tu as besoin des deux en même temps, et c'est justement là que Snowflake est puissant, tu empiles les couches selon le besoin plutôt que de bricoler une seule règle qui fait tout.

Aller plus loin : Formation Snowflake

J'ai regroupé tous mes articles Snowflake dans un parcours complet.

👉 Découvrir le parcours complet (Snowflake)

Vous voulez que je vous accompagne sur votre projet data (Snowflake, ingestion, modélisation, performance, coûts, gouvernance) ?
👉 Réserver un appel de 30 minutes