Pular para o conteúdo principal

Padrões comuns para filtragem de linhas e mascaramento de colunas

Esta página descreve padrões comuns para implementar políticas de filtro de linha e máscara de coluna ABAC. Para conceitos gerais, consulte Conceitos básicos para controle de acesso baseado em atributos (ABAC). Para obter informações sobre a sintaxe da política, consulte Criar e gerenciar políticas ABAC.

Funções de mascaramento compatíveis com Cast

O Databricks converte automaticamente a saída da função de mascaramento para corresponder ao tipo de dados da coluna de destino. Consulte Conversão automática de tipos para máscaras de coluna.

Os seguintes padrões ajudam você a projetar funções de mascaramento compatíveis com a conversão de tipo.

Retorna um tipo que pode ser convertido para outro tipo.

Ao mascarar uma coluna, retorne o mesmo tipo de dados ou um tipo que possa ser convertido para ele. Verifique os tipos de dados das colunas que sua política visa e certifique-se de que cada ramo da função retorne um valor compatível.

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;

Evite estouro numérico

Quando uma função de máscara aceita e retorna um tipo numérico mais amplo do que a coluna de destino, o resultado é automaticamente convertido de volta para o tipo da coluna. Se o valor retornado exceder o intervalo do tipo mais restrito, ocorrerá um estouro de conversão e a consulta falhará em tempo de execução.

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;

Use VARIANT para vários tipos de coluna.

Consulte Funções de mascaramento baseadas em VARIANT para vários tipos de coluna.

Compatibilidade de elenco de teste

Teste funções de mascaramento com diferentes padrões de dados.

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;

Funções de mascaramento baseadas em VARIANTES para vários tipos de coluna

Quando você precisa mascarar colunas de diferentes tipos de dados (por exemplo, INT, DOUBLE, DECIMAL(10,2), DECIMAL(15,5) e assim por diante), você pode escrever uma única UDF de mascaramento que aceita e retorna um tipo VARIANT . O Databricks converte automaticamente a saída da função de máscara de coluna para corresponder ao tipo de dados da coluna de destino, seguindo os padrões ANSI SQL.

Essa abordagem reduz o número de UDFs e políticas necessárias. Em vez de escrever funções de mascaramento separadas para cada tipo de coluna, uma única função lida com todos os tipos.

Mascarar vários tipos numéricos com uma única função

Em vez de criar uma função de máscara separada para cada precisão numérica, você pode usar VARIANT para lidar com todas elas com uma única função:

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

Esta função retorna 0 como um VARIANT, que o Databricks converte automaticamente para o tipo da coluna de destino. Uma única política ABAC usando esta função pode mascarar colunas INT, DOUBLE e DECIMAL sem exigir funções separadas para cada precisão.

Se preferir preservar o tipo explicitamente dentro da função, você pode criar uma ramificação com base no tipo e retornar um valor mascarado apropriado para cada um usando 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;

Colunas de estrutura de máscara com VARIANT

Para Databricks Runtime 18.1 e versões superiores, você também pode mascarar colunas struct convertendo-as para VARIANT dentro de uma política ABAC. Crie ramificações com base no formato da estrutura para ocultar campos seletivamente:

nota

A conversão de structs para VARIANT para mascaramento é suportada apenas em políticas de máscara de coluna ABAC.

O exemplo a seguir usa schema_of_variant() para identificar duas formas de estrutura diferentes e ocultar campos sensíveis em cada uma delas:

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;

Impeça o acesso até que as colunas sensíveis sejam marcadas.

Um padrão comum de governança é controlar o acesso com base na classificação dos dados. Você pode implementar isso com uma tag restritiva default e políticas que aplicam diferentes níveis de proteção dependendo do status de classificação.

  1. Aplique uma tag como classification : unverified a todos os novos objetos por default, por meio de automação ou por meio de herança tag , aplicando a tag no nível do catálogo ou esquema, para que quaisquer novas tabelas adicionadas ao catálogo ou esquema herdem automaticamente a tag.
  2. Crie uma política de filtro de linha que bloqueie o acesso às tags de tabela classification : unverified.
  3. Crie uma política de máscara de coluna que oculte colunas sensíveis em tabelas onde a tag classification : unverified não está mais presente.
  4. Quando uma gestão de dados conclui a classificação, ela atualiza a tag. A política de bloqueio deixa de ser válida e a política de mascaramento entra em vigor.
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');

Para proteger dados sensíveis após sua classificação, defina uma política de máscara de coluna que entre em vigor quando a tag classification : unverified não estiver mais presente:

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;

Revelação parcial sem expressão regular

Revele parte de um valor sensível usando operações com strings em vez de expressões regulares. A máscara baseada em expressões regulares examina o valor inteiro de cada linha, o que é dispendioso em campos de texto grandes (consulte Evitar a máscara de expressões regulares em campos de texto grandes).

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

Hashing consistente (pseudonimização determinística)

A criptografia consistente (também chamada de pseudonimização determinística) substitui dados sensíveis por um valor criptografado que é o mesmo em várias tabelas. Marcar uma função como DETERMINISTIC informa ao mecanismo que a função sempre retorna o mesmo resultado para a mesma entrada, o que ajuda a otimizar a consulta. Consulte Usar expressões determinísticas e à prova de erros.

A função a seguir realiza um hash consistente do valor de uma string e usa um parâmetro version para suportar a rotação key . Incremente o número version através da cláusula USING COLUMNS da política para gerar novos hashes sem quebrar os dados históricos que usaram a versão anterior. A função concatena o valor original com o número da versão antes de gerar o hash, portanto, a mesma entrada com a mesma versão sempre produz o mesmo hash.

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

Filtragem de linhas com predicados somente de coluna

Filtrar linhas usando lógica booleana simples que referencia apenas colunas da tabela. Os predicados somente de coluna permitem o pushdown de predicados, o que permite que o mecanismo ignore dados irrelevantes durante as varreduras (consulte Entender o pushdown de predicados em tabelas protegidas).

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

Utilize com uma política que passe as regiões permitidas como uma 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');

Filtragem de linhas em várias colunas relacionadas

Quando uma tabela possui várias colunas representando atributos relacionados (por exemplo, ship_to_country e bill_to_country), você pode combiná-las com condições de tag separadas e passar ambas para uma única UDF. Isso evita a criação de políticas separadas para cada coluna. Uma política pode incluir até três expressões de coluna na cláusula MATCH COLUMNS (consulte Cotas de política).

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

Um analista visualiza apenas os pedidos em que o país de envio ou o país de faturamento esteja na lista de países permitidos.

Tabelas de pesquisa em UDFs de política ABAC

Quando as regras de acesso variam por usuário e não podem ser expressas apenas pelas cláusulas TO/EXCEPT da política, você pode verificar os direitos de acesso em uma pequena tabela de pesquisa. Use TO/EXCEPT sempre que possível, pois é a abordagem preferida para segmentar principais (consulte Abordagem para segmentar principais). Mantenha a tabela de pesquisa pequena para que o otimizador converta a subconsulta em uma join hash de broadcast (consulte Manter tabelas de pesquisa pequenas).

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