Patrones comunes para el filtrado de filas y el enmascaramiento de columnas

En esta página se describen patrones comunes para implementar directivas de filtro de fila y máscara de columna de ABAC. Para conocer los conceptos generales, consulte Conceptos básicos para el control de acceso basado en atributos (ABAC). Para ver la sintaxis de directiva, consulte Creación y administración de directivas de ABAC.

Funciones de enmascaramiento compatibles con conversión

Azure Databricks convierte automáticamente la salida de la función de enmascaramiento para que coincida con el tipo de datos de la columna de destino. Consulte Conversión automática de tipos para máscaras de columna.

Los patrones siguientes ayudan a diseñar funciones de enmascaramiento compatibles con el casting.

Devolver un tipo que admite conversión explícita

Al enmascarar una columna, asegúrese de utilizar el mismo tipo de datos o un tipo que se pueda convertir a él. Compruebe los tipos de datos de las columnas que tiene como destino la directiva y compruebe que cada rama de la función devuelve un valor 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;

Evitar desbordamiento numérico

Cuando una función mask acepta y devuelve un tipo numérico más amplio que la columna de destino, el resultado se devuelve automáticamente al tipo de columna. Si el valor devuelto supera el rango del tipo más estrecho, se produce un desbordamiento en la conversión, lo que hace que la consulta falle en tiempo de ejecución.

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

Uso de VARIANT para varios tipos de columna

Consulte Funciones de enmascaramiento basadas en VARIANTEs para varios tipos de columna.

Compatibilidad de la ejecución de pruebas

Pruebe las funciones de enmascaramiento con diferentes patrones de datos.

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;

Funciones de enmascaramiento basadas en VARIANT para varios tipos de columnas

Cuando necesite enmascarar columnas de distintos tipos de datos (por ejemplo, INT, DOUBLEDECIMAL(10,2), DECIMAL(15,5), , etc.), puede escribir una UDF de enmascaramiento única que acepte y devuelva un VARIANT tipo. Azure Databricks convierte automáticamente el resultado de la función de máscara de columna para que coincida con el tipo de datos de la columna de destino siguiendo los estándares de ANSI SQL.

Este enfoque reduce el número de UDFs y directivas necesarias. En lugar de escribir funciones de enmascaramiento independientes para cada tipo de columna, una función controla todos los tipos.

Enmascarar varios tipos numéricos con una sola función

En lugar de crear una función de máscara independiente para cada precisión numérica, puede usar VARIANT para gestionarlas todas con una sola función.

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

Esta función devuelve 0 como VARIANT, y Azure Databricks lo convierte automáticamente al tipo de la columna de destino. Una sola política de ABAC que use esta función puede enmascarar las columnas INT, DOUBLE y DECIMAL sin la necesidad de funciones separadas para cada exactitud.

Si prefiere conservar el tipo explícitamente dentro de la función, puede realizar una bifurcación basada en el tipo y devolver un valor enmascarado adecuado para cada tipo mediante 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;

Enmascarar columnas de estructuras con VARIANT

Para Databricks Runtime 18.1 y versiones posteriores, también puede enmascarar las columnas de estructura convirtiéndolas a VARIANT dentro de una directiva de ABAC. Bifurcación en la forma de la estructura para censurar los campos de forma selectiva:

Note

La conversión de estructuras a VARIANT para enmascaramiento solo se admite en las directivas de máscara de columna de ABAC.

En el ejemplo siguiente se usa schema_of_variant() para identificar dos formas struct diferentes y redactar campos confidenciales en cada uno de ellos:

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;

Impedir el acceso hasta que se etiquetan las columnas confidenciales

Un patrón de gobernanza común es controlar el acceso en función de si los datos se han clasificado. Puede implementarlo con una etiqueta y directivas restrictivas predeterminadas que apliquen distintos niveles de protección en función del estado de clasificación.

  1. Aplique una etiqueta como classification : unverified a todos los objetos nuevos de forma predeterminada, mediante la automatización o la herencia de etiquetas aplicando la etiqueta en el nivel de catálogo o esquema, de modo que las nuevas tablas agregadas al catálogo o esquema hereden automáticamente la etiqueta.
  2. Cree una directiva de filtro de fila que bloquee el acceso a las tablas etiquetadas classification : unverified.
  3. Cree una directiva de máscara de columna que enmascara columnas confidenciales en tablas donde la classification : unverified etiqueta ya no esté presente.
  4. Cuando un administrador de datos completa la clasificación, actualiza la etiqueta. La directiva de bloqueo ya no coincide y la directiva de enmascaramiento surte efecto.
-- 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');

Para proteger los datos confidenciales después de clasificarlos, defina una directiva de máscara de columna que surte efecto cuando la classification : unverified etiqueta ya no esté presente:

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;

Revelado parcial sin regex

Mostrar parte de un valor confidencial mediante operaciones de cadena en lugar de regex. El enmascaramiento basado en expresiones regulares examina todo el valor de cada fila, lo cual es costoso en campos de texto grandes (consulte Evitar enmascaramiento de expresiones regulares en campos de texto grandes).

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

Hash coherente (pseudonimización determinista)

El hash coherente (también denominado seudonimización determinista) reemplaza los datos confidenciales por un valor hash que es el mismo en varias tablas. Al marcar una función como DETERMINISTIC se indica al motor que la función siempre devuelve el mismo resultado para la misma entrada, lo que ayuda a optimizar la consulta. Consulte Uso de expresiones deterministas y seguras para errores.

La siguiente función aplica un hash coherente a un valor de cadena y usa un version parámetro para admitir la rotación de claves. Incremente el version número mediante la cláusula de la directiva USING COLUMNS para generar nuevos hashes sin interrumpir los datos históricos que usaron la versión anterior. La función concatena el valor original con el número de versión antes de aplicar hash, por lo que la misma entrada con la misma versión siempre genera el mismo hash.

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

Filtrado de filas con predicados que utilizan exclusivamente columnas

Filtre las filas mediante una lógica booleana simple que haga referencia solo a columnas de tabla. Los predicados de solo columna habilitan la inserción de predicados, lo que permite al motor omitir los datos irrelevantes durante los escaneos (consulte Descripción de la inserción de predicados en tablas protegidas).

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

Use con una directiva que pase las regiones permitidas como una 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');

Filtrado de filas entre varias columnas relacionadas

Cuando una tabla tiene varias columnas que representan atributos relacionados (por ejemplo, ship_to_country y bill_to_country), puede coincidir con condiciones de etiqueta independientes y pasar ambas a una sola UDF. Esto evita la creación de directivas independientes para cada columna. Una directiva puede incluir hasta tres expresiones de columna en la MATCH COLUMNS cláusula (consulte Cuotas de directiva).

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 analista solo ve pedidos en los que el país de envío o de facturación está en su lista permitida.

Tablas de búsqueda en las UDFs de políticas ABAC

Cuando las reglas de acceso varían por usuario y no se pueden expresar solo a través de las cláusulas de TO/EXCEPT la directiva, puede comprobar los derechos de acceso en una tabla de búsqueda pequeña. Utilice TO/EXCEPT siempre que sea posible, ya que es el enfoque preferido para los principales (consulte Enfoque para los principales). Mantenga la tabla de búsqueda pequeña para que el optimizador convierta la subconsulta en una combinación hash de difusión (consulte Mantener pequeñas tablas de búsqueda).

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