Aller au contenu principal

Modèles courants pour le filtrage de lignes et le masquage de colonnes

Cette page décrit les modèles courants pour la mise en œuvre des politiques de filtrage de lignes et de masquage de colonnes ABAC.

Fonctions de masquage compatibles avec Cast

Databricks convertit automatiquement la sortie de la fonction de masquage pour qu'elle corresponde au type de données de la colonne cible. Voir Conversion de type automatique pour les masques de colonne.

Les modèles suivants vous aident à concevoir des fonctions de masquage compatibles avec la conversion de type.

Retourner un type convertible

Lorsque vous masquez une colonne, retournez le même type de données ou un type qui peut y être converti. Vérifiez les types de données des colonnes ciblées par votre politique et vérifiez que chaque Branch de la fonction retourne une valeur compatible.

SQL
-- Succeeds: Masks a DOUBLE column, returns DOUBLE in every branch
CREATE FUNCTION mask_salary(salary DOUBLE, user_role STRING)
RETURNS DOUBLE
RETURN CASE
WHEN user_role IN ('admin', 'hr') THEN salary
WHEN user_role = 'manager' THEN ROUND(salary / 1000) * 1000
ELSE 0.0
END;

-- Fails: 'CONFIDENTIAL' cannot be cast to a DOUBLE column type
CREATE FUNCTION mask_salary_as_text(salary DOUBLE, user_role STRING)
RETURNS STRING
RETURN CASE
WHEN user_role IN ('admin', 'hr') THEN CAST(salary AS STRING)
ELSE 'CONFIDENTIAL'
END;

Éviter le débordement numérique

Lorsqu'une fonction de masque accepte et renvoie un type numérique plus large que la colonne cible, le résultat est automatiquement recodé au type de la colonne. Si la valeur renvoyée dépasse la plage du type plus étroit, le transtypage déborde et la query échoue à l'exécution.

SQL
-- The target column is TINYINT (max 127). The input is upcast to BIGINT
-- for the function. Adding 1000 produces a BIGINT result that overflows
-- when cast back to TINYINT.
CREATE FUNCTION mask_score(score BIGINT)
RETURNS BIGINT
RETURN score + 1000;

Utiliser VARIANT pour plusieurs types de colonnes

Consultez les fonctions de masquage basées sur VARIANT pour plusieurs types de colonnes.

Tester la compatibilité de conversion de type

Testez les fonctions de masquage avec différents modèles de données.

SQL
SELECT CAST(mask_salary(salary, 'admin') AS DOUBLE) FROM employees;
SELECT CAST(mask_salary(salary, 'manager') AS DOUBLE) FROM employees;
SELECT CAST(mask_salary(salary, 'viewer') AS DOUBLE) FROM employees;

Fonctions de masquage basées sur VARIANT pour plusieurs types de colonnes

Lorsque vous avez besoin de masquer des colonnes de différents types de données (par exemple, INT, DOUBLE, DECIMAL(10,2), DECIMAL(15,5), et ainsi de suite), vous pouvez écrire une seule UDF de masquage qui accepte et renvoie un type VARIANT. Databricks convertit automatiquement la sortie de la fonction de masque de colonne pour qu'elle corresponde au type de données de la colonne cible, conformément aux normes ANSI SQL.

Cette approche réduit le nombre d'UDF et de politiques nécessaires. Au lieu d'écrire des fonctions de masquage séparées pour chaque type de colonne, une seule fonction gère tous les types.

Masquer plusieurs types numériques à l'aide d'une seule fonction

Plutôt que de créer une fonction de masque distincte pour chaque précision numérique, vous pouvez utiliser VARIANT pour toutes les gérer avec une seule fonction :

SQL
CREATE FUNCTION mask_numeric(val VARIANT)
RETURNS VARIANT
DETERMINISTIC
RETURN 0::VARIANT;

Cette fonction renvoie 0 en tant que VARIANT, que Databricks convertit automatiquement au type de la colonne cible. Une seule politique ABAC utilisant cette fonction peut masquer les colonnes INT, DOUBLE et DECIMAL sans nécessiter de fonctions distinctes pour chaque précision.

Si vous préférez préserver explicitement le type au sein de la fonction, vous pouvez effectuer un Branch sur le type et renvoyer une valeur masquée appropriée pour chacun à l’aide de schema_of_variant():

SQL
-- Use VARIANT to accommodate different data types
CREATE FUNCTION flexible_mask(data VARIANT)
RETURNS VARIANT
RETURN CASE
WHEN schema_of_variant(data) = 'INT' THEN 0::VARIANT
WHEN schema_of_variant(data) = 'DATE' THEN DATE'1970-01-01'::VARIANT
WHEN schema_of_variant(data) = 'DOUBLE' THEN 0.00::VARIANT
ELSE NULL::VARIANT
END;

Masquer les colonnes de structure avec VARIANT

Pour Databricks Runtime 18.1 ou une version ultérieure, vous pouvez également masquer les colonnes de struct en les convertissant en VARIANT dans une politique ABAC. Branch sur la forme de la structure pour expurger sélectivement les champs :

remarque

La conversion de structs en VARIANT pour le masquage n'est prise en charge que dans les politiques de masquage de colonne ABAC.

L'exemple suivant utilise schema_of_variant() pour identifier deux formes de structure différentes et masquer les champs sensibles dans chacune :

SQL
CREATE FUNCTION flexible_mask(data VARIANT)
RETURNS VARIANT
RETURN CASE
WHEN schema_of_variant(data) = 'OBJECT<age: BIGINT, email: STRING>' THEN
to_variant_object(named_struct('age', data:age, 'email', 'redacted'))
WHEN schema_of_variant(data) = 'OBJECT<id: BIGINT, ssn: STRING>' THEN
to_variant_object(named_struct('id', data:id, 'ssn', 'xxx-xx-xxxx'))
ELSE NULL::VARIANT
END;

Empêcher l'accès tant que les colonnes sensibles ne sont pas taguées.

Un modèle de gouvernance courant consiste à contrôler l’accès en fonction de la classification des données. Vous pouvez implémenter ceci avec un tag restrictif par default et des politiques qui appliquent différents niveaux de protection selon le statut de classification.

  1. Appliquez une étiquette comme classification : unverified à tous les nouveaux objets par default, par automatisation ou par héritage d'étiquettes en appliquant l'étiquette au niveau du catalogue ou du schéma, afin que toutes les nouvelles tables ajoutées au catalogue ou au schéma héritent automatiquement de l'étiquette.
  2. Créez une politique de filtre de lignes qui bloque l'accès aux tables étiquetées classification : unverified.
  3. Créez une politique de masquage de colonnes qui masque les colonnes sensibles sur les tables où l'étiquette classification : unverified n'est plus présente.
  4. Lorsqu'un data steward termine la classification, il met à jour le tag. La politique de blocage ne correspond plus, et la politique de masquage prend effet.
SQL
-- Block access to unverified tables for all non-admin users
CREATE FUNCTION catalog.schema.block_all() RETURNS BOOLEAN
RETURN FALSE;

CREATE POLICY block_unverified
ON CATALOG my_catalog
ROW FILTER catalog.schema.block_all
TO `account users` EXCEPT `data_admins`
FOR TABLES
WHEN has_tag_value('classification', 'unverified');

Pour protéger les données sensibles après leur classification, définissez une politique de masque de colonne qui prend effet lorsque le tag classification : unverified n'est plus présent :

SQL
CREATE FUNCTION catalog.schema.mask_pii(val STRING)
RETURNS STRING
RETURN '***';

CREATE POLICY mask_reviewed_pii
ON CATALOG my_catalog
COLUMN MASK catalog.schema.mask_pii
TO `account users`
EXCEPT `data_admins`
FOR TABLES
WHEN NOT has_tag_value('classification', 'unverified')
MATCH COLUMNS (has_tag_value('pii', 'name') OR has_tag_value('pii', 'address')) AS m
ON COLUMN m;

Divulgation partielle sans regex

Révéler une partie d'une valeur sensible à l'aide d'opérations sur les chaînes de caractères au lieu d'une expression régulière. Le masquage basé sur des expressions régulières analyse la valeur entière de chaque ligne, ce qui est coûteux pour les grands champs de texte (voir Évitez le masquage par regex sur les grands champs de texte).

SQL
CREATE FUNCTION mask_ssn(ssn STRING, show_last INT) RETURNS STRING
DETERMINISTIC
RETURN CONCAT('***-**-', RIGHT(ssn, show_last));

Hachage cohérent (pseudonymisation déterministe)

Le hachage cohérent (également appelé pseudonymisation déterministe) remplace les données sensibles par une valeur hachée identique sur plusieurs tables. Marquer une fonction comme DETERMINISTIC indique au moteur que la fonction renvoie toujours le même résultat pour la même entrée, ce qui l'aide à optimiser la query. Consultez Utiliser des expressions déterministes et sûres.

La fonction suivante hache systématiquement une valeur de chaîne et utilise un paramètre version pour prendre en charge la rotation des clés. Incrémentez le nombre version via la clause USING COLUMNS de la politique pour générer de nouveaux hachages sans casser les données historiques qui utilisaient la version précédente. La fonction concatène la valeur d'origine avec le numéro de version avant le hachage, de sorte que la même entrée avec la même version produit toujours le même hachage.

SQL
CREATE FUNCTION pseudonymize(val STRING, version INT) RETURNS STRING
DETERMINISTIC
RETURN SHA2(CONCAT(val, CAST(version AS STRING)), 256);

Filtrage de ligne avec des prédicats de colonne uniquement

Filtrer les lignes à l'aide d'une logique booléenne simple qui référence uniquement les colonnes de table. Les prédicats de colonne uniquement activent la poussée des prédicats, ce qui permet au moteur d'ignorer les données non pertinentes pendant les analyses (consultez Comprendre la poussée des prédicats sur les tables protégées).

SQL
CREATE FUNCTION filter_by_region(region STRING, allowed STRING)
RETURNS BOOLEAN
DETERMINISTIC
RETURN array_contains(split(allowed, ','), lower(region));

Utilisez avec une politique qui transmet les régions autorisées comme constante :

SQL
CREATE POLICY regional_access
ON CATALOG analytics
ROW FILTER filter_by_region
TO 'emea_team'
FOR TABLES
MATCH COLUMNS has_tag('region') AS rgn
USING COLUMNS (rgn, 'emea,apac');

Filtrage des lignes sur plusieurs colonnes liées

Lorsqu'une table comporte plusieurs colonnes représentant des attributs connexes (par exemple, ship_to_country et bill_to_country), vous pouvez les faire correspondre avec des conditions de balise distinctes et les transmettre toutes deux à une seule UDF. Ceci évite de créer des politiques distinctes pour chaque colonne. Une politique peut inclure jusqu’à trois expressions de colonne dans la clause MATCH COLUMNS (voir Quotas de politique).

SQL
CREATE FUNCTION filter_by_countries(ship_country STRING, bill_country STRING, allowed STRING)
RETURNS BOOLEAN
DETERMINISTIC
RETURN array_contains(split(allowed, ','), lower(ship_country))
OR array_contains(split(allowed, ','), lower(bill_country));

CREATE POLICY regional_orders
ON SCHEMA prod.orders
ROW FILTER filter_by_countries
TO analysts
FOR TABLES
WHEN has_tag_value('sensitivity', 'high')
MATCH COLUMNS
has_tag('ship_country') AS ship,
has_tag('bill_country') AS bill
USING COLUMNS (ship, bill, 'us,ca,mx');

Un analyste ne voit que les commandes dont le pays d'expédition ou de facturation figure dans sa liste autorisée.

Tables de recherche dans les UDF de politique ABAC

Lorsque les règles d’accès varient par utilisateur et ne peuvent pas être exprimées uniquement par les clauses TO/EXCEPT de la politique, vous pouvez vérifier les droits d’accès à l’aide d’une petite table de recherche. Utilisez TO/EXCEPT lorsque cela est possible, car c'est l'approche préférée pour cibler les principaux (voir Approche pour cibler les principaux). Maintenez la table de recherche petite afin que l’optimiseur convertisse la sous-requête en une jointure de hachage de diffusion (consultez Maintenez les tables de recherche petites).

SQL
CREATE TABLE access_rules (
principal VARCHAR(255),
priority VARCHAR(64)
);

INSERT INTO access_rules VALUES
('alice@company.com', '1-URGENT'),
('alice@company.com', '2-HIGH'),
('bob@company.com', '1-URGENT');

CREATE FUNCTION priority_allowed(o_priority STRING) RETURNS BOOLEAN
RETURN EXISTS (
SELECT 1 FROM access_rules
WHERE principal = session_user() AND priority = o_priority
);

CREATE POLICY priority_filter
ON CATALOG operations
ROW FILTER priority_allowed
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag('priority') AS pri
USING COLUMNS (pri);