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);

Masquer une colonne en fonction des attributs de l’utilisateur qui effectue la requête

info

Bêta

Les attributs d'identité dans les politiques ABAC sont en bêta. Pour les utiliser, un administrateur de compte doit activer l'aperçu Identity Attributes in ABAC Policies depuis la page Aperçus de la console de compte. Consultez Gérer les aperçus au niveau du compte.

Une politique de masquage de colonne peut utiliser les attributs d’identité de l’utilisateur effectuant la requête pour masquer les données sensibles sans nécessiter de groupes dédiés. Par exemple, il peut conserver les données non masquées pour les utilisateurs avec department = HR et les masquer pour tous les autres.

Ces modèles nécessitent des attributs d'identité provisionnés pour vos utilisateurs à partir de votre fournisseur d'identité, et les fonctions se comportent différemment des conditions basées uniquement sur des tags, ce qui affecte la manière dont vous rédigez la politique. Avant de les utiliser, passez en revue les fonctions d'attribut d'identité et les attributs d'identité.

important

Les fonctions se résolvent en false lorsque l’utilisateur n’a aucune valeur pour l’attribut ou lorsque la clé d’attribut n’existe pas. Rédigez la condition de sorte que ce résultat false restreigne l’accès plutôt que de l’accorder. Niez la correspondance avec NOT afin que le masque s’applique sauf si l’attribut correspond. Par exemple, WHEN NOT has_identity_attribute_value('department', 'HR') masque la colonne pour tout le monde sauf pour les utilisateurs dont le département est HR, et comme une valeur manquante est également false, les utilisateurs sans attribut de département sont également masqués. Évitez l’inverse : une condition qui masque uniquement lorsque l’attribut correspond laisse les utilisateurs qui n’ont aucune valeur pour cet attribut non masqués.

Pour le comportement d'évaluation, consultez Conditions des attributs d'identité. Pour les limitations, consultez Attributs d'identité dans les conditions de politique.

Faire correspondre une valeur fixe

Masquer ssn pour toute personne dont le département n'est pas HR:

SQL
CREATE FUNCTION hr_catalog.people.mask_ssn(s STRING) RETURNS STRING RETURN '***-**-****';

CREATE OR REPLACE POLICY mask_ssn_non_hr
ON SCHEMA hr_catalog.people
COLUMN MASK hr_catalog.people.mask_ssn
TO `account users`
FOR TABLES
WHEN NOT has_identity_attribute_value('department', 'HR')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;

Dans cet exemple, un utilisateur dont le département est HR voit des valeurs réelles. Un utilisateur dans tout autre département, ainsi qu'un utilisateur sans attribut de département, voient tous deux le masque.

Faire correspondre à un tag gouverné

L'exemple précédent nomme une valeur d'attribut spécifique (HR) dans la politique ; couvrir plusieurs départements signifierait donc rédiger une politique distincte pour chacun d'eux. Pour couvrir tous les départements avec une seule politique, étiquetez chaque table avec le département qui la possède, puis comparez l'attribut department de l'utilisateur effectuant la requête avec cette étiquette. La colonne n'est révélée que lorsque le département de l'utilisateur correspond à la valeur dept_tag de la table :

SQL
CREATE FUNCTION prod.sales.mask_ssn(s STRING) RETURNS STRING RETURN '***-**-****';

CREATE OR REPLACE POLICY mask_unless_dept_matches
ON SCHEMA prod.sales
COLUMN MASK prod.sales.mask_ssn
TO `account users`
FOR TABLES
WHEN NOT has_identity_attribute_tag_match('department', 'dept_tag')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;

Les clés et les valeurs d'attribut sont toutes deux sensibles à la casse, et les valeurs sont comparées exactement : Finance et finance ne correspondent pas.

Restreindre l’accès pour les agents externes agissant pour le compte d’un utilisateur

info

Bêta

Les attributs de contexte dans les politiques ABAC sont en version bêta. Pour les utiliser, un administrateur de compte doit activer l’aperçu UC ABAC Context Attributes depuis la page Previews de la console de compte. Consultez Gérer les aperçus au niveau du compte.

Les attributs de contexte peuvent être utilisés pour restreindre l’accès aux données pour les requêtes effectuées au nom d’un utilisateur via une application OAuth. Si les agents sont connectés via OAuth, cette configuration peut être utilisée pour les empêcher d’accéder aux données lorsqu’ils agissent au nom d’un utilisateur, même si l’utilisateur peut toujours lire les données lorsqu’il les interroge directement dans le Workspace.

Tout accès authentifié par OAuth via la CLI Databricks, les SDK ou l’API SQL Statement Execution définit request.is_on_behalf_of sur 'true', même lorsqu’un utilisateur effectue une requête manuellement. L’accès authentifié avec un jeton d’accès personnel (PAT) ne le fait pas. L’accès à Genie ne peut pas être capturé via ce mécanisme car il ne définit pas request.is_on_behalf_of sur 'true'.

Ces modèles utilisent les fonctions d’attribut de contexte. Pour les attributs et comportements disponibles, consultez Fonctions d’attribut de contexte (bêta).

Configurer un agent pour envoyer des attributs de contexte

Pour utiliser les attributs de contexte, connectez l’agent à Databricks à l’aide d’une application OAuth personnalisée :

  1. Un administrateur de compte active l’aperçu UC ABAC Context Attributes depuis la console du compte. Consultez Gérer les aperçus Databricks.
  2. Un administrateur de compte enregistre une application OAuth personnalisée dans la console du compte et note son ID client. Voir Activer ou désactiver les applications OAuth des partenaires.
  3. Connectez l’agent au MCP géré par Databricks via cette application OAuth. Consultez Connecter des clients à l’aide de l’authentification OAuth.

Un agent qui utilise le client databricks-cli intégré s’authentifie toujours via OAuth, donc request.is_on_behalf_of lit 'true'. Cependant, vous ne pouvez pas distinguer ses requêtes d’une utilisation manuelle de la CLI, car les deux partagent l’ID client databricks-cli. Pour gouverner une application spécifique, enregistrez une application OAuth personnalisée et connectez l’agent via celle-ci.

Pour les concepts OAuth, consultez Autoriser l’accès utilisateur à Databricks avec OAuth.

attention

Assurez-vous qu’un agent ne peut pas accéder aux données via un chemin non couvert par votre politique :

  • Si vous restreignez l’accès en fonction de request.is_on_behalf_of, assurez-vous que l’agent ne peut pas s’authentifier avec un PAT. Un PAT ne définit pas request.is_on_behalf_of sur 'true', donc une condition sur cet attribut ne le restreint pas.
  • Si vous restreignez l’accès en fonction de request.client_id, assurez-vous que l’agent ne peut pas se connecter via un client que votre condition ne couvre pas, tel que le client générique databricks-cli.

Masquer une colonne pour les requêtes effectuées pour le compte d’un utilisateur

Masquez ssn pour les requêtes exécutées au nom d’un utilisateur, tel qu’un agent agissant via une application OAuth enregistrée, tout en le laissant non masqué pour les requêtes directes :

SQL
CREATE FUNCTION hr_catalog.people.mask_ssn(s STRING) RETURNS STRING RETURN '***-**-****';

CREATE OR REPLACE POLICY mask_ssn_for_agents
ON SCHEMA hr_catalog.people
COLUMN MASK hr_catalog.people.mask_ssn
TO `account users`
FOR TABLES
WHEN has_context_attribute_value('request.is_on_behalf_of', 'true')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;

Dans cet exemple, une query directe renvoie des valeurs réelles, et une requête « on-behalf-of » voit les valeurs masquées. En utilisant la CLI et l’API SQL Statement Execution, request.is_on_behalf_of lit également 'true', cette politique masque donc la colonne pour ces requêtes également. Pour cibler une application spécifique à la place, faites correspondre request.client_id à l’ID client de cette application.

Restreindre une colonne à une application approuvée

Masquer ssn pour chaque requête externe, à l’exception de celles provenant de votre application approuvée, identifiée par son identifiant client OAuth :

SQL
CREATE OR REPLACE POLICY mask_ssn_unapproved_apps
ON SCHEMA hr_catalog.people
COLUMN MASK hr_catalog.people.mask_ssn
TO `account users`
FOR TABLES
WHEN NOT has_context_attribute_value('request.client_id', '<your-app-client-id>')
MATCH COLUMNS has_tag_value('pii', 'ssn') AS ssn_col
ON COLUMN ssn_col;

Pour voir quelle application a effectué une requête, inspectez le champ identity_metadata.acting_resource dans les audit Logs.

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);