Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette page décrit les modèles courants d’implémentation des stratégies de filtre de lignes et de masque de colonne ABAC.
- Pour connaître les concepts globaux, consultez Les concepts de base pour le contrôle d’accès basé sur les attributs (ABAC).
- Pour connaître la syntaxe de stratégie, consultez Créer et gérer des stratégies de filtre de lignes et de masque de colonne.
- Pour les politiques GRANT (bêta), voir les politiques ABAC GRANT (bêta).
- Si votre environnement utilise RBAC, consultez Utiliser RBAC avec ABAC pour savoir comment les fonctions d’identité se comportent lorsque les utilisateurs assument un rôle et des modèles qui combinent RBAC avec ABAC.
Fonctions de masquage compatibles Cast
Azure Databricks caste automatiquement la sortie de la fonction de masquage pour qu'elle corresponde au type de données de la colonne cible. Consultez Conversion automatique des types pour les masques de colonne.
Les modèles suivants vous aident à concevoir des fonctions de masquage compatibles avec cast.
Retourner un type castable
Lors du masquage d’une colonne, retournez le même type de données ou un type qui est convertible. Vérifiez les types de données des colonnes que votre stratégie cible et vérifiez que chaque branche de la fonction retourne une valeur compatible.
-- 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épassement de capacité numérique
Lorsqu’une fonction de masque accepte et retourne un type numérique plus large que la colonne cible, le résultat est automatiquement converti en type de colonne. Si la valeur retournée dépasse la plage du type plus étroit, le cast provoque un débordement et la requête échoue pendant l'exécution.
-- 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.
Compatibilité des casts de test
Testez les fonctions de masquage avec différents modèles de données.
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 devez masquer les colonnes de différents types de données (par exemple, INT, , DOUBLEDECIMAL(10,2), DECIMAL(15,5)et ainsi de suite), vous pouvez écrire une seule fonction UDF masquage qui accepte et retourne un VARIANT type. Azure Databricks caste automatiquement la sortie de la fonction 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 de fonctions utilisateur et les stratégies requises. Au lieu d’écrire des fonctions de masquage distinctes pour chaque type de colonne, une fonction gère tous les types.
Masquer plusieurs types numériques avec une fonction unique
Au lieu de créer une fonction de masque distincte pour chaque précision numérique, vous pouvez les utiliser VARIANT pour les gérer toutes avec une seule fonction :
CREATE FUNCTION mask_numeric(val VARIANT)
RETURNS VARIANT
DETERMINISTIC
RETURN 0::VARIANT;
Cette fonction retourne 0 en tant que VARIANT, où Azure Databricks l'adapte automatiquement au type de la colonne cible. Une stratégie ABAC unique utilisant cette fonction peut masquer INT, DOUBLEet DECIMAL les colonnes sans nécessiter de fonctions distinctes pour chaque précision.
Si vous préférez conserver le type explicitement dans la fonction, vous pouvez faire une branche sur le type et retourner une valeur masquée appropriée pour chaque utilisation schema_of_variant():
-- 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 struct avec VARIANT
Pour Databricks Runtime 18.1 et versions ultérieures, vous pouvez également masquer les colonnes de struct en les convertissant en VARIANT dans une politique ABAC. Utiliser la structure du struct pour masquer sélectivement les champs.
Note
La conversion des structs en VARIANT pour le masquage est prise en charge uniquement dans le cadre des politiques de masquage de colonne ABAC.
L’exemple suivant utilise schema_of_variant() pour identifier deux formes de struct différentes et redacter des champs sensibles dans chacun d’eux :
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 jusqu’à ce que les colonnes sensibles soient marquées
Un modèle de gouvernance courant consiste à contrôler l’accès en fonction de la classification des données. Vous pouvez l’implémenter avec une balise et des stratégies restrictives par défaut qui appliquent différents niveaux de protection en fonction de l’état de classification.
- Appliquez une balise comme
classification : unverifiedà tous les nouveaux objets par défaut, par le biais de l’automatisation ou de l’héritage des étiquettes en appliquant la balise 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 la balise. - Créez une stratégie de filtre de lignes qui bloque l’accès aux tables marquées
classification : unverified. - Créez une stratégie de masque de colonne qui masque les colonnes sensibles sur les tables où la
classification : unverifiedbalise n’est plus présente. - Lorsqu’un gestionnaire de données termine la classification, il met à jour la balise. La stratégie de blocage ne correspond plus et la stratégie de masquage prend effet.
-- 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 une fois qu’elles ont été classifiées, définissez une stratégie de masque de colonne qui prend effet lorsque la classification : unverified balise n’est plus présente :
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;
Révélation partielle sans regex
Révéler une partie d’une valeur sensible à l’aide d’opérations de chaîne au lieu d’une expression régulière. Le masquage basé sur les expressions régulières examine la valeur complète de chaque ligne, ce qui est coûteux sur les champs de texte volumineux (voir Éviter le masquage par expressions régulières sur les champs de texte volumineux).
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é pseudonyme déterministe) remplace les données sensibles par une valeur hachée identique sur plusieurs tables. Le marquage d’une fonction indique DETERMINISTIC au moteur que la fonction retourne toujours le même résultat pour la même entrée, ce qui lui permet d’optimiser la requête. Consultez Utiliser des expressions déterministes et sans risque d’erreur.
La fonction suivante hache de manière cohérente une valeur de chaîne et utilise un paramètre version pour permettre la rotation des clés. Incrémentez le versionnombre à travers la clause de stratégie USING COLUMNS pour générer de nouveaux hachages sans affecter 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. Par conséquent, la même entrée avec la même version produit toujours le même hachage.
CREATE FUNCTION pseudonymize(val STRING, version INT) RETURNS STRING
DETERMINISTIC
RETURN SHA2(CONCAT(val, CAST(version AS STRING)), 256);
Masquez une colonne en fonction des attributs de l’utilisateur interrogateur
Important
Les attributs d’identité des politiques ABAC sont en bêta. Pour les utiliser, un administrateur de compte doit activer les attributs d’identité dans l’aperçu des politiques ABAC depuis la page Aperçu de la console de compte. Consultez Gérer les versions préliminaires du compte.
Une politique de masque en colonne peut utiliser les attributs d’identité de l’utilisateur interrogé pour masquer des données sensibles sans nécessiter de groupes dédiés. Par exemple, il peut garder les données non masquées pour les utilisateurs department = HR et les masquer pour tous les autres.
Ces schémas nécessitent des attributs d’identité fournis à vos utilisateurs par votre fournisseur d’identité, et les fonctions se comportent différemment des conditions uniquement par tag, ce qui affecte la manière dont vous rédigez la politique. Avant de les utiliser, examinez les fonctions d’attributs d’identité et les attributs d’identité.
Important
Les fonctions renvoient false lorsque l’utilisateur n’a aucune valeur pour l’attribut ou que la clé d’attribut n’existe pas. Écrivez la condition de façon à ce que ce false résultat limite l’accès plutôt que de l’accorder. Inversez 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 les utilisateurs dont le département est HR, et parce qu’une valeur manquante est aussi false, les utilisateurs sans attribut département sont aussi masqués. Évitez l’inverse : une condition qui ne masque que lorsque l’attribut correspond laisse non masqués les utilisateurs pour lesquels l’attribut n’a aucune valeur.
Pour le comportement d’évaluation, voir Conditions d’attribut d’identité. Pour connaître les limitations, voir Attributs d’identité dans les conditions de stratégie.
Correspond à une valeur fixe
Masquer ssn pour tous ceux dont le département n’est pas HR :
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 appartient HR voit de vraies valeurs. Un utilisateur dans un autre département, et un utilisateur sans attribut département, voient tous deux le masque.
Comparer à une étiquette régie
L’exemple précédent nomme une valeur d’attribut spécifique (HR) dans la politique, donc couvrir plusieurs départements signifierait rédiger une politique distincte pour chacun. Pour couvrir tous les départements ayant une seule politique, identifiez chaque table avec le département qui en est propriétaire, puis comparez l’attribut de department l’utilisateur interrogateur avec ce tag. La colonne n’est révélée que lorsque le département de l’utilisateur correspond à la valeur du dept_tag tableau :
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 valeurs d’attribut sont toutes deux sensibles à la majuscule, et les valeurs sont comparées exactement : Finance et finance ne correspondent pas.
Restreignez l’accès aux agents externes agissant au nom d’un utilisateur
Important
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 des attributs contextuels UC ABAC depuis la page Aperçu de la console de compte. Consultez Gérer les versions préliminaires du compte.
Les attributs de contexte peuvent être utilisés pour restreindre l’accès aux données lors de 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 l’espace de travail.
Tout accès authentifié par OAuth via la CLI d’Azure Databricks, les SDKs ou l’API d’exécution de données SQL se définit request.is_on_behalf_of à 'true', même lorsqu’un utilisateur interroge 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 pris en compte par ce mécanisme, car il ne définit pas request.is_on_behalf_of sur 'true'.
Ces motifs utilisent les fonctions d’attribut contextuel. Pour les attributs et comportements disponibles, voir Fonctions d’attributs contextuelles (Bêta).
Configurez un agent pour envoyer des attributs contextuels
Pour utiliser les attributs contextuels, connectez l’agent à Azure Databricks en utilisant une application OAuth personnalisée :
- Un administrateur de compte active l’aperçu des attributs contextuels UC ABAC depuis la console de compte. Consultez Gérer les préversions d’Azure Databricks.
- Un administrateur de compte enregistre une application OAuth personnalisée dans la console de compte et note son identifiant client. Consultez Activer ou désactiver des applications OAuth de partenaires.
- Connectez l’agent au MCP géré par Azure Databricks via cette application OAuth. Consultez Connecter des clients à l’aide de l’authentification OAuth.
Un agent qui utilise le client intégré databricks-cli authentifie toujours via OAuth, donc request.is_on_behalf_of lit 'true'. Cependant, vous ne pouvez pas distinguer ses requêtes de l’utilisation manuelle de la ligne de commande, car les deux partagent l’identifiant databricks-cli client. Pour gouverner une application spécifique, enregistrez une application OAuth personnalisée et connectez l’agent via celle-ci.
Pour les concepts OAuth, voir Autoriser l’accès utilisateur à Azure Databricks avec OAuth.
Warning
Assurez-vous qu’un agent ne puisse pas accéder aux données par un chemin que votre police ne couvre pas :
- 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 pasrequest.is_on_behalf_ofsur'true', donc une condition sur cet attribut ne le limite 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, comme le client génériquedatabricks-cli.
Masquez une colonne pour les requêtes effectuées pour le compte de quelqu’un
Masque ssn pour les requêtes qui s’exécutent au nom d’un utilisateur, comme un agent agissant via une application OAuth enregistrée, tout en la laissant non masquée pour les requêtes directes :
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 requête directe retourne des valeurs réelles, et une requête au nom de l’utilisateur retourne les valeurs masquées. Avec la CLI et l’API d’exécution des instructions SQL, request.is_on_behalf_of lit également 'true', donc cette politique masque aussi la colonne pour ces requêtes. Pour cibler une application spécifique, comparez request.client_id avec l’identifiant client de cette application.
Restreindre une colonne à une demande approuvée
Masque ssn pour toutes les requêtes externes sauf celles de votre application approuvée, identifiées par son identifiant client OAuth :
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 fait une demande, inspectez le identity_metadata.acting_resource champ dans les journaux d’audit.
Filtrage de lignes avec prédicats en colonnes uniquement
Filtrez des lignes à l’aide d’une logique booléenne simple qui référence uniquement des colonnes de table. Les prédicats de colonne uniquement activent l'optimisation des prédicats, ce qui permet au moteur d'ignorer les données non pertinentes pendant les scans (voir Comprendre l'optimisation des prédicats sur les tables protégées).
CREATE FUNCTION filter_by_region(region STRING, allowed STRING)
RETURNS BOOLEAN
DETERMINISTIC
RETURN array_contains(split(allowed, ','), lower(region));
Utilisez une stratégie qui transmet les régions autorisées en tant que constante :
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 de lignes à travers plusieurs colonnes associées
Lorsqu’une table comporte plusieurs colonnes représentant des attributs associés (par exemple, ship_to_country et bill_to_country), vous pouvez les mettre en correspondance avec des conditions d’étiquette distinctes et passer les deux à une seule fonction UDF. Cela évite de créer des stratégies distinctes pour chaque colonne. Une stratégie peut inclure jusqu’à trois expressions de colonne dans la MATCH COLUMNS clause (voir quotas de stratégie).
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 voit uniquement les commandes où le pays d’expédition ou de facturation se trouve dans leur liste autorisée.
Tables de recherche dans les UDF de stratégie ABAC
Lorsque les règles d’accès varient par utilisateur et ne peuvent pas être exprimées uniquement par les clauses de la stratégie TO/EXCEPT, vous pouvez vérifier les droits d’accès sur une petite table de recherche. Utilisez TO/EXCEPT le cas échéant, car il s’agit de l’approche recommandée pour le ciblage des principaux (voir Approche pour le ciblage des principaux). Conserver la table de recherche de petite taille afin que l'optimiseur convertisse la sous-requête en jointure de hachage par diffusion (voir Conserver les tables de recherche de petite taille).
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);