Dans l'article précédent sur les droits d'accès, on a posé les bases de la gestion des accès.

Sauf qu'en vrai, tôt ou tard tu tombes sur ce cas :

  • Tu veux laisser SELECT sur une table mais tu ne veux pas que tout le monde voie l'email, le téléphone, l'IBAN, le salaire, etc.

C'est là que le masquage dynamique (Dynamic Data Masking) entre en jeu et règle cette problématique.

Nb : c'est une fonctionnalité qui est disponible que dans l'edition Enterprise (ou +)

Le modèle à retenir

C'est simple, tu as deux couches :

  1. Droits d'accès : “est-ce que tu as le droit de lire l'objet ?”
  2. Masking : “ok tu lis la table… mais qu'est-ce que tu as le droit de voir la colonne des salaires ?”

Nb : Snowflake ne modifie pas la donnée stockée. Il réécrit la requête “à la volée” au moment du SELECT, en appliquant la policy.

Exemple complet

Comme d'habitude dans les articles de la formation, y'a pas mieux d'un exemple pour comprendre le concept. On reprend le même exemple que l'article des accès avec un rôle d'accès en lecture, et un rôle spécial pour voir les données sensibles.

  • Table : FINANCE_DB.MART_FINANCE.EMPLOYEES
  • Schéma des policies : FINANCE_DB.SECURITY
  • Rôles :
    • FINANCE_ANALYST : peut voir la table, mais pas les colonnes masquées
    • PAYROLL_PII : peut tout voir
    • MASKING_ADMIN : Admin qui peut créer et appliquer les policies

1) Table de test

CREATE DATABASE IF NOT EXISTS FINANCE_DB;
CREATE SCHEMA IF NOT EXISTS FINANCE_DB.MART_FINANCE;

CREATE OR REPLACE TABLE FINANCE_DB.MART_FINANCE.EMPLOYEES (
  EMP_ID     NUMBER,
  FULL_NAME  STRING,
  EMAIL      STRING,
  IBAN       STRING,
  SALARY     NUMBER
);

INSERT INTO FINANCE_DB.MART_FINANCE.EMPLOYEES VALUES
  (1, 'Alice Martin', 'alice.martin@corp.com', 'FR7630006000011234567890189', 85000),
  (2, 'Sam Dupont',   'sam.dupont@corp.com',   'FR7612345987650000000000123', 62000);

2) Rôles

USE ROLE USERADMIN;

CREATE ROLE IF NOT EXISTS FINANCE_ANALYST;
CREATE ROLE IF NOT EXISTS PAYROLL_PII;
CREATE ROLE IF NOT EXISTS MASKING_ADMIN;

Donner le droit de lecture à l'analyst :

USE ROLE SECURITYADMIN;

GRANT USAGE ON DATABASE FINANCE_DB TO ROLE FINANCE_ANALYST;
GRANT USAGE ON SCHEMA FINANCE_DB.MART_FINANCE TO ROLE FINANCE_ANALYST;
GRANT SELECT ON TABLE FINANCE_DB.MART_FINANCE.EMPLOYEES TO ROLE FINANCE_ANALYST;

3) Créer un schéma “SECURITY” pour les policies

USE ROLE SECURITYADMIN;

CREATE SCHEMA IF NOT EXISTS FINANCE_DB.SECURITY;

GRANT USAGE ON DATABASE FINANCE_DB TO ROLE MASKING_ADMIN;
GRANT USAGE ON SCHEMA FINANCE_DB.SECURITY TO ROLE MASKING_ADMIN;

GRANT CREATE MASKING POLICY ON SCHEMA FINANCE_DB.SECURITY TO ROLE MASKING_ADMIN;
GRANT APPLY MASKING POLICY ON ACCOUNT TO ROLE MASKING_ADMIN;

4) Créer les masking policies

Pour faire simple, on partira du principe que :

  • si tu as le rôle PAYROLL_PII → accès à tout les champs en clair
  • sinon → masquer les champs sensibles
Petite astuce : IS_ROLE_IN_SESSION('...') évite pas mal de surprises quand tu as des rôles “parents/enfants”.

Email (partiel)

USE ROLE MASKING_ADMIN;

CREATE OR REPLACE MASKING POLICY FINANCE_DB.SECURITY.MASK_EMAIL
AS (val STRING) RETURNS STRING ->
  CASE
    WHEN val IS NULL THEN NULL
    WHEN IS_ROLE_IN_SESSION('PAYROLL_PII') THEN val
    ELSE REGEXP_REPLACE(val, '(^.).*(@.*$)', '\\1***\\2')
  END;

IBAN (garder les 4 derniers)

CREATE OR REPLACE MASKING POLICY FINANCE_DB.SECURITY.MASK_IBAN
AS (val STRING) RETURNS STRING ->
  CASE
    WHEN val IS NULL THEN NULL
    WHEN IS_ROLE_IN_SESSION('PAYROLL_PII') THEN val
    ELSE CONCAT('**** **** **** **** ', RIGHT(val, 4))
  END;

Salaire (NULL)

CREATE OR REPLACE MASKING POLICY FINANCE_DB.SECURITY.MASK_SALARY
AS (val NUMBER) RETURNS NUMBER ->
  CASE
    WHEN val IS NULL THEN NULL
    WHEN IS_ROLE_IN_SESSION('PAYROLL_PII') THEN val
    ELSE NULL
  END;

5) Appliquer les policies sur les colonnes

USE ROLE MASKING_ADMIN;

ALTER TABLE FINANCE_DB.MART_FINANCE.EMPLOYEES
  ALTER COLUMN EMAIL  SET MASKING POLICY FINANCE_DB.SECURITY.MASK_EMAIL;

ALTER TABLE FINANCE_DB.MART_FINANCE.EMPLOYEES
  ALTER COLUMN IBAN   SET MASKING POLICY FINANCE_DB.SECURITY.MASK_IBAN;

ALTER TABLE FINANCE_DB.MART_FINANCE.EMPLOYEES
  ALTER COLUMN SALARY SET MASKING POLICY FINANCE_DB.SECURITY.MASK_SALARY;

6) Tester les policies

En mode analyst

USE ROLE FINANCE_ANALYST;

SELECT EMP_ID, FULL_NAME, EMAIL, IBAN, SALARY
FROM FINANCE_DB.MART_FINANCE.PAYROLL_EMPLOYEES;

On peut voir :

  • Email masqué (a***@corp.com)
  • Iban masqué (avec juste les 4 derniers)
  • Salary = NULL

Avec le rôle PII

USE ROLE PAYROLL_PII;

SELECT EMP_ID, FULL_NAME, EMAIL, IBAN, SALARY
FROM FINANCE_DB.MART_FINANCE.PAYROLL_EMPLOYEES;

Là tu vois tout en clair.

Avec le rôle PII

Aller plus loin : Formation Snowflake

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

👉 Accéder à la Formation 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