Aller au contenu principal

Appliquer manuellement des filtres de lignes et des masques de colonnes

Cette page fournit des conseils et des exemples pour l'utilisation des filtres de lignes, des masques de colonnes et des tables de correspondance afin de filtrer les données sensibles dans vos tables. Ces fonctionnalités nécessitent Unity Catalog.

Si vous recherchez une approche centralisée, basée sur des tags, pour le filtrage et le masquage, consultez le contrôle d'accès basé sur les attributs dans Unity Catalog. ABAC vous permet de gérer les politiques à l'aide de tags gouvernés et de les appliquer de manière cohérente sur de nombreuses tables.

Avant de commencer

Pour ajouter des filtres de ligne et des masques de colonne aux tables, vous devez disposer de :

  • Un Workspace qui est activé pour Unity Catalog.
  • Une UDF SQL qui est enregistrée dans Unity Catalog. Pour utiliser la logique Python ou Scala, créez d'abord une UDF Python ou Scala, puis créez une UDF SQL qui l'appelle. Le SQL UDF est ce que vous appliquez comme filtre de ligne ou masque de colonne. Pour un exemple, consultez Masque de colonne avec UDF Python. Pour les meilleures pratiques et les limitations des UDF, voir Filtres de lignes et masques de colonne.

Vous devez également respecter les exigences suivantes :

  • Pour attribuer une fonction qui ajoute des filtres de ligne ou des masques de colonne à une table, vous devez disposer du privilège EXECUTE sur la fonction, de USE SCHEMA sur le schéma et de USE CATALOG sur le catalogue parent.
  • Si vous ajoutez des filtres ou des masques lorsque vous créez une nouvelle table, vous devez disposer du privilège CREATE TABLE sur le schéma.
  • Si vous ajoutez ou supprimez des filtres ou des masques sur une table existante , vous devez être le propriétaire de la table ou disposer des privilèges MANAGE et SELECT sur la table.
  • Si la même instruction modifie également le schéma de table (par exemple, l'ajout d'une nouvelle colonne avec un masque), vous avez également besoin du privilège MODIFY sur la table.

Pour accéder à une table qui contient des filtres de ligne ou des masques de colonne, votre ressource de compute doit répondre à l'une de ces exigences :

  • Un SQL Warehouse.
  • Mode d'accès standard (anciennement mode d'accès partagé) sur Databricks Runtime 12.2 LTS ou version ultérieure.
  • Mode d'accès dédié (anciennement mode d'accès utilisateur unique) sur Databricks Runtime 15.4 LTS ou version ultérieure.

Vous ne pouvez pas lire les filtres de ligne ou les masques de colonne à l’aide de compute dédié sur Databricks Runtime 15,3 ou version antérieure.

Pour tirer parti du filtrage des données fourni dans Databricks Runtime 15.4 LTS et versions ultérieures, vous devez également vérifier que votre Workspace est activé pour le compute serverless, car la fonctionnalité de filtrage des données qui prend en charge les filtres de ligne et les masques de colonne s'exécute sur le compute serverless. Des frais peuvent vous être facturés pour les Ressources de compute serverless lorsque vous utilisez un compute configuré en mode d'accès dédié pour lire des tables qui utilisent des filtres de ligne ou des masques de colonne. Les Opérations d'écriture sur ces tables ne sont prises en charge qu'avec Databricks Runtime 16.3 et versions ultérieures, et doivent utiliser des modèles pris en charge tels que MERGE INTO. Consultez le contrôle d'accès granulaire sur un compute dédié.

remarque

Les filtres de lignes et les masques de colonnes sont conservés lors du remplacement d'une table.

Si vous exécutez REPLACE TABLE, tout filtre de ligne existant est conservé, quels que soient les changements de schéma. Les masques de colonne sont également conservés si la nouvelle table inclut des colonnes portant les mêmes noms que celles qui avaient des masques dans la table d'origine. Dans les deux cas, les politiques sont préservées même si elles ne sont pas explicitement redéfinies. Cela permet d'éviter la perte accidentelle des politiques d'accès aux données.

Toutefois, si une stratégie conservée référence une colonne qui a été supprimée ou modifiée, les requêtes suivantes risquent d'échouer. Pour résoudre ce problème, mettez à jour ou supprimez la politique à l'aide de ALTER TABLE.

Appliquer un filtre de ligne

Pour créer un filtre de ligne, vous écrivez une fonction (UDF) pour définir la politique de filtre, puis l'appliquez à une table. Chaque table peut avoir un seul filtre de ligne. Un filtre de ligne accepte zéro ou plusieurs paramètres d'entrée, chaque paramètre d'entrée se liant à une colonne de la table correspondante.

important

Les types de paramètres UDF doivent correspondre aux types de données des colonnes de la table qui leur sont transmises. Si le type d’une colonne diffère de celui du type de parameter d’une UDF, comme une colonne STRING passée à un parameter INT, la valeur de la colonne est implicitement convertie. Lorsque le mode ANSI est désactivé, les valeurs qui ne peuvent pas être castées sont silencieusement converties en NULL, ce qui peut entraîner la production de résultats incorrects par le filtre sans générer d’erreur. Pour en savoir plus, consultez le comportement en cas de non-concordance des types de données.

Vous pouvez appliquer un filtre de ligne à l'aide de l'Explorateur de catalogues ou de commandes SQL. Les instructions de l'Explorateur de catalogues supposent que vous avez déjà créé une fonction et l'avez enregistrée dans Unity Catalog. Les instructions SQL comprennent des exemples de création d’une fonction de filtre de ligne et de son application à une table.

remarque

Si vous utilisez les Lakeflow pipelines, vous pouvez utiliser l'API Python des Lakeflow pipelines pour créer des tables de streaming ou des vues matérialisées qui utilisent des filtres de lignes et des masques de colonnes. Consultez Publier des tables avec des filtres de ligne et des masques de colonne.

  1. Dans votre workspace Databricks, cliquez sur Icône de données. Catalogue .
  2. Parcourez ou recherchez la table que vous souhaitez filtrer.
  3. Sous l'onglet Vue d'ensemble , sous Filtre de ligne , cliquez sur Ajouter un filtre .
  4. Dans la boîte de dialogue Ajouter un filtre de ligne , sélectionnez le catalogue et le schéma qui contiennent la fonction de filtre, puis sélectionnez la fonction.
  5. Dans la boîte de dialogue développée, consultez la définition de la fonction et sélectionnez les colonnes de la table qui correspondent aux colonnes incluses dans l'instruction de fonction.
  6. Cliquez sur **Ajouter**.

Pour supprimer le filtre de la table, cliquez sur fx Filtre de lignes , puis sur Supprimer .

Exemples de filtre de ligne

Cet exemple crée une fonction définie par l’utilisateur SQL qui s’applique aux membres du groupe admin dans la région US.

Lorsque cette fonction d'échantillonnage est appliquée à la table sales, les membres du groupe admin peuvent accéder à tous les enregistrements de la table. Si la fonction est appelée par un non-administrateur, la condition RETURN_IF échoue et l'expression region='US' est évaluée, filtrant la table pour n'afficher que les enregistrements de la région US.

SQL
CREATE FUNCTION us_filter(region STRING)
RETURN IF(IS_ACCOUNT_GROUP_MEMBER('admin'), true, region='US');

Appliquez la fonction à une table comme filtre de ligne. Les queries suivantes de la table sales renvoient ensuite un sous-ensemble de lignes.

SQL
CREATE TABLE sales (region STRING, id INT);
ALTER TABLE sales SET ROW FILTER us_filter ON (region);

Désactiver le filtre de ligne. Les futures queries des utilisateurs à partir de la table sales renvoient alors toutes les lignes de la table.

SQL
ALTER TABLE sales DROP ROW FILTER;

Créez une table avec la fonction appliquée comme filtre de lignes dans le cadre de l'instruction CREATE TABLE. Les futures queries de la table sales renvoient ensuite un sous-ensemble de lignes.

SQL
CREATE TABLE sales (region STRING, id INT)
WITH ROW FILTER us_filter ON (region);

Appliquer un masque de colonne

Pour appliquer un masque de colonne, créez une fonction (UDF) et appliquez-la à une colonne de table.

important

Les types de paramètres d'UDF doivent correspondre aux types de données des colonnes qui leur sont transmises. Si un type de colonne diffère du type de paramètre d'UDF, la valeur de la colonne est implicitement castée. Lorsque le mode ANSI est désactivé, les valeurs qui ne peuvent pas être converties sont silencieusement converties en NULL, ce qui peut entraîner des résultats incorrects du masque sans lever d’erreur. Pour en savoir plus, consultez Comportement en cas d’incompatibilité de type de données.

Vous pouvez appliquer un masque de colonne à l’aide de l’Explorateur de catalogues ou de commandes SQL. Les instructions de l'Explorateur de catalogues supposent que vous avez déjà créé une fonction et l'avez enregistrée dans Unity Catalog. Les instructions SQL incluent des exemples de création d'une fonction de masquage de colonne et de son application à une colonne de table.

remarque

Si vous utilisez les Lakeflow pipelines, vous pouvez utiliser l'API Python des Lakeflow pipelines pour créer des tables de streaming ou des vues matérialisées qui utilisent des filtres de lignes et des masques de colonnes. Consultez Publier des tables avec des filtres de ligne et des masques de colonne.

  1. Dans votre workspace Databricks, cliquez sur Icône de données. Catalogue .
  2. Parcourez ou recherchez la table.
  3. Sous l'onglet **Vue d'ensemble**, recherchez la ligne à laquelle vous souhaitez appliquer le masque de colonne et cliquez sur l'icône de modification Icône de modification **Masque**.
  4. Dans la boîte de dialogue Ajouter un masque de colonne , sélectionnez le catalogue et le schéma qui contiennent la fonction de filtre, puis sélectionnez la fonction.
  5. Dans la boîte de dialogue développée, visualisez la définition de fonction. Si la fonction inclut des paramètres en plus de la colonne masquée, sélectionnez les colonnes de la table dans lesquelles vous souhaitez caster ces paramètres de fonction supplémentaires.
  6. Cliquez sur **Ajouter**.

Pour supprimer le masque de colonne de la table, cliquez sur fx Column mask dans la ligne du tableau, puis sur Supprimer .

Exemples de masque de colonne

Dans cet exemple, vous créez une fonction définie par l'utilisateur qui masque la colonne ssn afin que seuls les utilisateurs membres du groupe HumanResourceDept puissent afficher les valeurs de cette colonne.

SQL
CREATE FUNCTION ssn_mask(ssn STRING)
RETURN CASE WHEN is_account_group_member('HumanResourceDept') THEN ssn ELSE '***-**-****' END;

Appliquez la nouvelle fonction à une table en tant que masque de colonne. Vous pouvez ajouter le masque de colonne lors de la création de la table ou ultérieurement.

SQL
--Create the `users` table and apply the column mask in a single step:

CREATE TABLE users (
name STRING,
ssn STRING MASK ssn_mask);
SQL
--Create the `users` table and apply the column mask after:

CREATE TABLE users
(name STRING, ssn STRING);

ALTER TABLE users ALTER COLUMN ssn SET MASK ssn_mask;

Les requêtes sur cette table renvoient désormais les valeurs de colonne ssn masquées lorsque l'utilisateur qui effectue la requête n'est pas membre du groupe HumanResourceDept :

SQL
SELECT * FROM users;
James ***-**-****

Pour désactiver le masque de colonne afin que les requêtes renvoient les valeurs d'origine dans la colonne ssn :

SQL
ALTER TABLE users ALTER COLUMN ssn DROP MASK;

Masque de colonne avec UDF Python

Pour utiliser la logique Python ou Scala dans un masque de colonne, vous devez créer une UDF Python ou Scala, puis l'encapsuler dans une UDF SQL. La fonction wrapper SQL est ce que vous appliquez comme masque de colonne.

Cet exemple crée une UDF Python pour masquer les adresses e-mail, puis l'encapsule dans une UDF SQL :

SQL
-- Step 1: Create the Python UDF with masking logic
CREATE OR REPLACE FUNCTION email_mask_python(email STRING)
RETURNS STRING
LANGUAGE PYTHON
AS $$
import re
return re.sub(r'^[^@]+', lambda m: '*' * len(m.group()), email)
$$;

-- Step 2: Create a SQL wrapper function that calls the Python UDF
CREATE OR REPLACE FUNCTION email_mask_sql(email STRING)
RETURN email_mask_python(email);

Ensuite, appliquez l'encapsuleur SQL en tant que masque de colonne à votre table :

SQL
-- Create the `contacts` table and apply the SQL wrapper as the column mask
CREATE TABLE contacts (
name STRING,
email STRING MASK email_mask_sql);
important

Vous devez appliquer la fonction d'encapsulage SQL (email_mask_sql) comme masque de colonne, et non l'UDF Python directement. Si vous tentez d'utiliser l'UDF Python (email_mask_python) directement comme masque de colonne, vous recevrez une erreur [ROUTINE_NOT_FOUND].

Masque de colonne avec colonnes supplémentaires (USING COLUMNS)

Utilisez la clause USING COLUMNS lorsqu'une fonction de masquage doit faire référence à des parameters statiques ou à d'autres colonnes de la table. USING COLUMNS permet le masquage conditionnel basé sur des valeurs au-delà de la colonne masquée.

La clause USING COLUMNS fournit des arguments supplémentaires à la fonction de masquage :

  • Le 1er parameter de la fonction de masquage correspond toujours à la colonne masquée elle-même.
  • Fournissez des parameters supplémentaires en utilisant USING COLUMNS avec des valeurs statiques ou des noms de colonne de la même table.

L'exemple suivant crée un masque de colonne qui censure les adresses différemment en fonction de la valeur d'une autre colonne (country). La fonction prend un paramètre supplémentaire qui spécifie le groupe. Seuls les membres de la paire pays-groupe résultante peuvent consulter les adresses de ce pays.

SQL
-- Create a masking function that accepts two parameters:
-- 1. address (the masked column)
-- 2. country (an additional column used for conditional logic)
-- 3. group_suffix (group the user belongs to)
CREATE FUNCTION mask_address_by_country(address STRING, country STRING, group_suffix STRING DEFAULT '_address_viewers')
RETURN IF(
is_account_group_member(country || group_suffix),
address,
'REDACTED'
);

-- Create a table and apply the mask using USING COLUMNS to pass the country column
CREATE TABLE customers (
name STRING,
address STRING MASK mask_address_by_country USING COLUMNS (country, '_address_viewers'),
country STRING
);

-- Insert sample data
INSERT INTO customers VALUES
('Alice', '123 Main St, New York', 'US'),
('Bob', '456 High St, London', 'UK'),
('Charlie', '789 Rue de Rivoli, Paris', 'FR');

Les résultats de la query dépendent de l'appartenance au groupe. Si l'utilisateur est membre de US_address_viewers, il peut voir les adresses américaines, mais pas les autres :

SQL
-- As a member of 'US_address_viewers' group
SELECT * FROM customers;
Alice | 123 Main St, New York | US
Bob | REDACTED | UK
Charlie | REDACTED | FR

Vous pouvez également appliquer le masque à une table existante :

SQL
-- Apply mask to existing column
ALTER TABLE customers
ALTER COLUMN address
SET MASK mask_address_by_country USING COLUMNS (country, '_address_viewers');

Masque de colonne pour les champs imbriqués STRUCT

Vous pouvez appliquer des masques de colonnes aux colonnes STRUCT imbriquées pour masquer sélectivement des champs spécifiques au sein de la structure tout en préservant d'autres champs. Ceci est utile lorsqu'un STRUCT contient des données publiques et sensibles, et que vous souhaitez appliquer différents contrôles d'accès à des champs individuels basés sur les attributs de l'utilisateur.

Pour masquer les champs imbriqués, créez une fonction de masquage qui reconstruit la STRUCT à l’aide de named_struct(), en remplaçant les valeurs de champs sensibles de manière conditionnelle tout en gardant les autres champs intacts.

Cet exemple crée une fonction de masquage pour une colonne STRUCT qui contient à la fois un champ value public et un champ secret sensible. La fonction de masquage utilise is_account_group_member() pour déterminer s'il faut afficher toutes les données ou masquer le champ sensible.

SQL
-- Create a masking function for nested STRUCT fields
CREATE FUNCTION mask_nested_field(data STRUCT<value: STRING, secret: STRING>)
RETURN IF(
is_account_group_member('privileged_users'),
data,
named_struct('value', data.value, 'secret', 'REDACTED')
);

Appliquez la fonction de masquage lors de la création d'une table avec une colonne STRUCT :

SQL
-- Create a table with a masked STRUCT column
CREATE TABLE sensitive_data (
id INT,
nested_column STRUCT<value: STRING, secret: STRING>
MASK mask_nested_field
);

-- Insert sample data
INSERT INTO sensitive_data VALUES
(1, named_struct('value', 'public_info', 'secret', 'private_info')),
(2, named_struct('value', 'general_data', 'secret', 'confidential_data'));

Query la table pour tester le masquage. Les résultats varient en fonction de l'appartenance au groupe. Si l'utilisateur n'est pas membre de privileged_users, le secret est censuré :

SQL
-- As a non-member of 'privileged_users'
SELECT * FROM sensitive_data;
1 {"value":"public_info","secret":"REDACTED"}
2 {"value":"general_data","secret":"REDACTED"}

Vous pouvez également appliquer le masque à une table existante :

SQL
-- Apply mask to existing STRUCT column
ALTER TABLE sensitive_data
ALTER COLUMN nested_column
SET MASK mask_nested_field;
important

La fonction de masquage doit retourner une valeur avec le même type STRUCT que la colonne masquée. Cela permet d'éviter les incoérences de schémas déroutantes qui peuvent survenir pendant les opérations INSERT, MERGE et UPDATE. Dans cet exemple, la fonction retourne STRUCT<value: STRING, secret: STRING> pour correspondre au type de colonne.

Utilisez des tables de mappage pour créer une liste de contrôle d'accès

Pour obtenir une sécurité au niveau des lignes, envisagez de définir une table de mappage (ou une liste de contrôle d'accès). Une table de mappage complète code quelles lignes de données dans la table d'origine sont accessibles à certains utilisateurs ou groupes. Les tables de mappage sont utiles car elles offrent une intégration simple avec vos tables de faits via des jointures directes.

Cette méthodologie répond à de nombreux cas d'utilisation qui incluent des exigences personnalisées. Exemples :

  • Imposer des restrictions en fonction de l'utilisateur connecté tout en tenant compte de règles différentes pour des groupes d'utilisateurs spécifiques.
  • Création de hiérarchies complexes, telles que des structures organisationnelles, qui nécessitent des ensembles de règles variés.
  • Réplication de modèles de sécurité complexes à partir de systèmes source externes.

En adoptant des tables de mappage, vous pouvez réaliser ces scénarios complexes et assurer des implémentations robustes de sécurité au niveau des lignes et des colonnes.

Exemples de table de mappage

Utilisez une table de mappage pour vérifier si l'utilisateur actuel est dans une liste :

SQL
USE CATALOG main;

Créer une nouvelle table de mappage :

SQL
DROP TABLE IF EXISTS valid_users;

CREATE TABLE valid_users(username string);
INSERT INTO valid_users
VALUES
('fred@databricks.com'),
('barney@databricks.com');

Créez un nouveau filtre :

remarque

Tous les filtres s’exécutent avec les droits du définisseur, à l’exception des fonctions qui vérifient le contexte utilisateur (par exemple, les fonctions SESSION_USER et IS_ACCOUNT_GROUP_MEMBER), qui s’exécutent en tant qu’invocateur.

Dans cet exemple, la fonction vérifie si l’utilisateur actuel se trouve dans la table valid_users. Si l'utilisateur est trouvé, la fonction renvoie true.

SQL
DROP FUNCTION IF EXISTS row_filter;

CREATE FUNCTION row_filter()
RETURN EXISTS(
SELECT 1 FROM valid_users v
WHERE v.username = SESSION_USER()
);

L'exemple ci-dessous applique le filtre de lignes lors de la création de la table. Vous pouvez également ajouter le filtre plus tard à l'aide d'une instruction ALTER TABLE. Lorsque vous appliquez le filtre à des colonnes non spécifiées, utilisez la syntaxe ON (). Pour une colonne spécifique, utilisez ON (column);. Pour plus de détails, consultez Paramètres.

SQL
DROP TABLE IF EXISTS data_table;

CREATE TABLE data_table
(x INT, y INT, z INT)
WITH ROW FILTER row_filter ON ();

INSERT INTO data_table VALUES
(1, 2, 3),
(4, 5, 6),
(7, 8, 9);

Sélectionnez les données du tableau. Cela ne devrait renvoyer des données que si l'utilisateur se trouve dans le tableau valid_users.

SQL
SELECT * FROM data_table;

Créez une table de mappage comprenant les comptes qui devraient toujours avoir accès pour afficher toutes les lignes de la table, quelles que soient les valeurs de colonne :

SQL
CREATE TABLE valid_accounts(account string);
INSERT INTO valid_accounts
VALUES
('admin'),
('cstaff');

Maintenant, créez une UDF SQL qui renvoie true si les valeurs de toutes les colonnes de la ligne sont inférieures à cinq ou si l'utilisateur appelant est membre de la table de mappage ci-dessus.

SQL
CREATE FUNCTION row_filter_small_values (x INT, y INT, z INT)
RETURN (x < 5 AND y < 5 AND z < 5)
OR EXISTS(
SELECT 1 FROM valid_accounts v
WHERE IS_ACCOUNT_GROUP_MEMBER(v.account));

Enfin, appliquez l'UDF SQL à la table comme filtre de ligne :

SQL
ALTER TABLE data_table SET ROW FILTER row_filter_small_values ON (x, y, z);