Usar tabelas de mapeamento para controle de acesso dinâmico

Este tutorial mostra como usar uma tabela de mapeamento para controlar o acesso em nível de linha e de coluna sem gerenciar um grande número de grupos. Uma única tabela de consulta conduz a filtragem de linhas e a aplicação de máscaras de coluna. As alterações de acesso exigem apenas uma atualização de linha. Você não precisa criar novos grupos ou reescrever políticas.

Este tutorial também demonstra o mascaramento condicional: as colunas PII são mascaradas de forma diferente, dependendo do valor de outra coluna na mesma linha. As ordens marcadas confidential têm sua PII totalmente ocultada, independentemente do nível de liberação do usuário.

Para obter orientações gerais sobre o design da tabela de mapeamento, consulte Usar tabelas de mapeamento para criar uma lista de controle de acesso.

Pré-requisitos

  • Databricks Runtime 16.4 ou superior ou computação sem servidor.
  • Permissões de administrador de conta ou de administrador de espaço de trabalho (para criar tags reguladas).
  • MANAGE permissão no catálogo ou esquema de destino.
  • EXECUTE nas UDFs.
  • Um notebook sql ou editor de consultas.

Scenario

Sua organização tem funcionários em quatro regiões (Leste dos EUA, Oeste dos EUA, UE, APAC) e quatro departamentos. Cada usuário deve ver apenas as linhas que correspondem à sua região e ao seu departamento, e as colunas de Informação de Identificação Pessoal (PII) devem ser mascaradas com base em dois fatores: o nível de autorização do usuário (full, masked ou none) armazenado em uma tabela de mapeamento e a ordem de order_priority.

Com uma abordagem por grupos, você precisa de um grupo para cada combinação de região e departamento. Por exemplo, você precisa de 16 grupos para quatro regiões e quatro departamentos. Adicionar camadas de liberação de PII triplica essa contagem. Cada nova região ou departamento requer novos grupos e atualizações de política.

A abordagem da tabela de mapeamento substitui isso por uma única tabela de pesquisa: uma linha por usuário, uma coluna por dimensão de acesso. Para alterar o acesso de um usuário, atualize uma linha.

Etapa 1: Criar tags controladas

Antes de executar qualquer SQL, crie as seguintes etiquetas governadas na interface do usuário do Explorador de Catálogo>Governar>Etiquetas Governadas>Criar etiqueta governada:

Chave de etiqueta Valores permitidos
region (etiqueta somente chave)
department (tag somente chave)
pii name, email
priority (etiqueta somente chave)

As region tags e department tags indicam à política de filtragem de linhas quais colunas devem ser passadas para o filtro UDF. A pii marca informa às políticas de máscara de coluna quais colunas mascarar e qual tipo de PII elas contêm. A priority tag permite que as políticas de máscara de coluna passem um valor order_priority para a UDF de mascaramento para mascaramento condicional.

Warning

Os dados de tag são armazenados como texto simples e podem ser replicados globalmente. Não use nomes de marca, valores ou descritores que possam comprometer a segurança de seus recursos. Por exemplo, não use nomes de marca, valores ou descritores que contenham informações pessoais ou confidenciais.

Etapa 2: Compilar dados de exemplo

Crie um catálogo, um esquema e uma tabela de pedidos. A order_priority coluna conduz o mascaramento condicional: as ordens marcadas confidential têm suas Informações de Identificação Pessoal (PII) totalmente redigidas, mesmo para usuários com alto nível de acesso.

CREATE CATALOG IF NOT EXISTS abac_tutorial;
USE CATALOG abac_tutorial;

CREATE SCHEMA IF NOT EXISTS mapping_demo;
USE SCHEMA mapping_demo;
CREATE OR REPLACE TABLE orders (
  order_id INT,
  customer_name STRING,
  customer_email STRING,
  sales_region STRING,
  dept STRING,
  amount DOUBLE,
  order_date DATE,
  order_priority STRING
);

INSERT INTO orders VALUES
  (1,  'Acme Corp',     'orders@acme.com',    'us_east', 'engineering', 50000,  '2025-01-15', 'standard'),
  (2,  'Beta Inc',      'sales@beta.com',     'us_east', 'sales',       75000,  '2025-02-01', 'confidential'),
  (3,  'Gamma LLC',     'info@gamma.com',     'us_west', 'engineering', 30000,  '2025-01-20', 'standard'),
  (4,  'Delta Co',      'deals@delta.com',    'us_west', 'sales',       95000,  '2025-03-01', 'confidential'),
  (5,  'Epsilon GmbH',  'kontakt@epsilon.de', 'eu',      'engineering', 45000,  '2025-02-15', 'standard'),
  (6,  'Zeta SA',       'contact@zeta.fr',    'eu',      'sales',       62000,  '2025-01-30', 'standard'),
  (7,  'Eta Ltd',       'hello@eta.sg',       'apac',    'marketing',   28000,  '2025-03-10', 'confidential'),
  (8,  'Theta Corp',    'biz@theta.com',      'us_east', 'marketing',   55000,  '2025-02-20', 'standard'),
  (9,  'Iota KK',       'info@iota.jp',       'apac',    'engineering', 41000,  '2025-01-25', 'standard'),
  (10, 'Kappa Inc',     'sales@kappa.com',    'us_west', 'marketing',   33000,  '2025-03-05', 'standard');

Etapa 3: Aplicar tags controladas

Marque as colunas para que as políticas do ABAC possam descobri-las automaticamente. A order_priority coluna é marcada com a marca apenas de chave priority para que as políticas de mascaramento de coluna possam encontrá-la usando MATCH COLUMNS e passar seu valor para a UDF de máscara.

ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN sales_region SET TAGS ('region' = '');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN dept SET TAGS ('department' = '');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN customer_name SET TAGS ('pii' = 'name');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN customer_email SET TAGS ('pii' = 'email');
ALTER TABLE abac_tutorial.mapping_demo.orders
  ALTER COLUMN order_priority SET TAGS ('priority' = '');

Etapa 4: Criar a tabela de mapeamento

Em vez de criar grupos para cada região, departamento e combinação de liberação, você mantém uma tabela com uma linha por usuário. A pii_access coluna controla como as colunas PII aparecem:

  • full — consulte o valor real (para pedidos de prioridade padrão)
  • masked — consulte um valor parcial, como A*** ou o***@acme.com
  • none — veja ***REDACTED***

A expires_on coluna define uma data de validade para cada entrada de acesso. Após essa data, a função UDF do filtro de linha para de corresponder à entrada e o usuário perde acesso silenciosamente sem necessidade de revogação manual. Isso é útil para contratantes, contratos temporários de compartilhamento de dados ou projetos com tempo limitado.

Se um usuário precisar de acesso a várias combinações de região e departamento, adicione linhas adicionais.

Observação

Mantenha tabelas de mapeamento pequenas e simples. Cada consulta em uma tabela protegida executa o filtro de linha e as UDFs de máscara de coluna, que por sua vez consultam a tabela de mapeamento. Tabelas de mapeamento grandes e lógica de UDF complexa podem afetar o desempenho da consulta. Use esquemas estreitos e mantenha a lógica UDF em uma única consulta sempre que possível.

CREATE OR REPLACE TABLE abac_tutorial.mapping_demo.user_access (
  user_email STRING,
  region STRING,
  department STRING,
  pii_access STRING,
  expires_on DATE
);

INSERT INTO abac_tutorial.mapping_demo.user_access VALUES
  (current_user(),      'us_east', 'engineering', 'masked', '2099-12-31'),
  ('bob@example.com',   'us_west', 'sales',       'full',   '2099-12-31'),
  ('carol@example.com', 'eu',      'engineering', 'none',   '2099-12-31'),
  ('david@example.com', 'apac',    'marketing',   'masked', '2099-12-31');

Etapa 5: Criar o filtro de linha UDF

Essa UDF recebe os valores de sales_region e dept de uma linha (passados pela política por meio do emparelhamento de tags), busca o usuário atual na tabela de mapeamento e retorna TRUE apenas se uma entrada correspondente existir e não tiver expirado. Usuários que não estão na tabela de mapeamento ou cujo acesso expirou não vêem nenhuma linha (design fail-closed).

CREATE OR REPLACE FUNCTION abac_tutorial.mapping_demo.access_filter(
  region_val STRING,
  dept_val STRING
)
RETURNS BOOLEAN
RETURN EXISTS (
  SELECT 1 FROM abac_tutorial.mapping_demo.user_access
  WHERE user_email = current_user()
    AND region = region_val
    AND department = dept_val
    AND expires_on >= current_date()
);

Etapa 6: Criar a UDF da máscara de coluna

Essa UDF controla como as colunas PII são exibidas. São necessários três argumentos: o valor da coluna, o tipo PII ('name' ou 'email'), e a linha.order_priority A lógica de mascaramento tem duas camadas:

  • Camada 1 (mascaramento condicional): Se order_priority for confidential, as Informações Pessoais Identificáveis (PII) sempre serão totalmente ocultadas independentemente do nível de autorização do usuário.
  • Camada 2 (liberação do usuário): Para linhas padrão, a UDF verifica a tabela de mapeamento para o nível do pii_access usuário e aplica a máscara correspondente. Se um usuário tiver várias entradas de tabela de mapeamento (acesso de várias regiões), a maior autorização será aplicada a todas as linhas.
CREATE OR REPLACE FUNCTION abac_tutorial.mapping_demo.pii_mask(
  val STRING,
  pii_type STRING,
  order_pri STRING
)
RETURNS STRING
RETURN CASE
  WHEN order_pri = 'confidential' THEN '***REDACTED***'
  WHEN EXISTS (
    SELECT 1 FROM abac_tutorial.mapping_demo.user_access
    WHERE user_email = current_user() AND pii_access = 'full'
  ) THEN val
  WHEN EXISTS (
    SELECT 1 FROM abac_tutorial.mapping_demo.user_access
    WHERE user_email = current_user() AND pii_access = 'masked'
  ) THEN
    CASE pii_type
      WHEN 'email' THEN CONCAT(LEFT(val, 1), '***@', SUBSTRING_INDEX(val, '@', -1))
      WHEN 'name'  THEN CONCAT(LEFT(val, 1), '***')
      ELSE CONCAT(LEFT(val, 1), '***')
    END
  ELSE '***REDACTED***'
END;

Etapa 7: Criar as políticas

Crie três políticas, todas controladas pela mesma tabela de mapeamento. Ambas as políticas de máscara de coluna usam a mesma função pii_mask. O pii_type argumento informa à função qual estilo de máscara aplicar, portanto, você não precisa de um UDF separado por tipo de coluna.

A priority etiqueta governada é usada em MATCH COLUMNS para corresponder à coluna order_priority e passar seu valor para a UDF de mascaramento como order_pri. É assim que o mascaramento condicional é implementado: a política passa o valor de prioridade da linha para a UDF no momento da consulta.

CREATE POLICY user_access_filter
ON SCHEMA abac_tutorial.mapping_demo
ROW FILTER abac_tutorial.mapping_demo.access_filter
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag('region') AS r, has_tag('department') AS d
USING COLUMNS (r, d);
CREATE POLICY pii_mask_name
ON SCHEMA abac_tutorial.mapping_demo
COLUMN MASK abac_tutorial.mapping_demo.pii_mask
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag_value('pii', 'name') AS m,
  has_tag('priority') AS pri
ON COLUMN m
USING COLUMNS ('name', pri);

CREATE POLICY pii_mask_email
ON SCHEMA abac_tutorial.mapping_demo
COLUMN MASK abac_tutorial.mapping_demo.pii_mask
TO `account users`
FOR TABLES
MATCH COLUMNS has_tag_value('pii', 'email') AS m,
  has_tag('priority') AS pri
ON COLUMN m
USING COLUMNS ('email', pri);

Etapa 8: Verificar os resultados

Sua entrada na tabela de mapeamento fornece acesso a us_east / engineering com masked autorização. Execute a consulta a seguir para verificar se você vê apenas a ordem nº 1, com a PII parcialmente mascarada.

SELECT * FROM abac_tutorial.mapping_demo.orders;

A ordem nº 1 tem order_priority = 'standard', portanto, sua masked autorização se aplica.

Resultado esperado para o usuário:

order_id nome_do_cliente customer_email região_de_vendas Departamento valor order_date prioridade_do_pedido
1 A*** o***@acme.com us_east Engenharia 50000 2025-01-15 padrão

O que outros usuários veem:

User Pedidos visíveis prioridade_do_pedido Comportamento de PII
bob@example.com (full liberação) Nº 4 (us_west, vendas) confidencial ***REDACTED*** — liberação de substituições full confidenciais
carol@example.com (none liberação) #5 (eu, engenharia) padrão ***REDACTED***none liberação significa redação completa
david@example.com (masked liberação) Nº 7 (APAC, Marketing) confidencial ***REDACTED*** — confidencial prevalece sobre masked autorização
(proprietário do catálogo) Todos os 10 Todos sem máscara (o proprietário está isento das políticas)
(usuário não listado) None O filtro de linha não retorna linhas

Observe que bob tem full autorização, mas ainda vê ***REDACTED*** porque a ordem nº 4 é confidential. Isso é mascaramento condicional: o valor de prioridade da linha substitui o nível de permissão do usuário.

Etapa 9: Atualizar o acesso dinamicamente

O principal benefício da abordagem da tabela de mapeamento é que você pode alterar o acesso atualizando linhas na tabela. Você não precisa atualizar políticas, funções definidas pelo usuário (UDFs), ou associações de grupo.

Reatribuir para um departamento diferente

Altere seu departamento de engineering para sales. O pedido nº 2 (Beta Inc) é um confidential pedido de vendas, portanto, sua PII é totalmente ocultada mesmo com masked autorização.

UPDATE abac_tutorial.mapping_demo.user_access
SET department = 'sales'
WHERE user_email = current_user();

Execute a consulta a seguir para verificar. Você deverá ver a ordem nº 2 com ***REDACTED*** PII.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Reverta a alteração:

UPDATE abac_tutorial.mapping_demo.user_access
SET department = 'engineering'
WHERE user_email = current_user();

Atualizar a liberação de Informações Pessoais Identificáveis (PII)

Altere sua liberação de masked para full. Para linhas de prioridade padrão, agora você verá os valores de PII reais.

UPDATE abac_tutorial.mapping_demo.user_access
SET pii_access = 'full'
WHERE user_email = current_user();

Execute a consulta a seguir para verificar. A ordem nº 1 é standard prioridade, logo, com a liberação full, você deve ver Acme Corp e orders@acme.com.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Reverter a alteração:

UPDATE abac_tutorial.mapping_demo.user_access
SET pii_access = 'masked'
WHERE user_email = current_user();

Conceder acesso a uma região adicional

Insira uma segunda linha para conceder acesso à engenharia da UE. Não são necessários novos grupos ou políticas.

INSERT INTO abac_tutorial.mapping_demo.user_access
VALUES (current_user(), 'eu', 'engineering', 'masked', '2099-12-31');

Execute a consulta a seguir para verificar. Agora você deve ver o pedido #1 (us_east, engenharia) e o pedido #5 (eu, engenharia), com PII parcialmente anonimizada.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Remova o acesso adicional:

DELETE FROM abac_tutorial.mapping_demo.user_access
WHERE user_email = current_user() AND region = 'eu';

Expirar o acesso

Defina sua entrada de acesso como uma data anterior. As UDFs do filtro de linha verificam expires_on >= current_date(), de modo que as entradas expiradas são ignoradas silenciosamente e o acesso é automaticamente revogado. Isso é útil para empreiteiros, contratos de compartilhamento de dados com uma duração fixa ou projetos com tempo limitado.

UPDATE abac_tutorial.mapping_demo.user_access
SET expires_on = current_date() - INTERVAL 1 DAY
WHERE user_email = current_user();

Execute a consulta a seguir para verificar se você não vê linhas.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Restaurar o acesso com uma data de validade futura:

UPDATE abac_tutorial.mapping_demo.user_access
SET expires_on = '2099-12-31'
WHERE user_email = current_user();

Execute a consulta a seguir para verificar se o acesso foi restaurado.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Resumo

Este tutorial demonstrou três padrões:

  • Padrão de tabela de mapeamento: uma única tabela de pesquisa controla a filtragem de linhas e o mascaramento de coluna. As alterações de acesso são feitas atualizando linhas, sem nenhuma política ou alterações de grupo necessárias.
  • Mascaramento condicional: a máscara UDF verifica a order_priority coluna em cada linha para decidir como mascarar a PII. As linhas confidenciais são sempre totalmente ocultadas independentemente do nível de acesso do usuário, implementado marcando order_priority e passando para a UDF por meio de MATCH COLUMNS.
  • Expiração de acesso: a tabela de mapeamento inclui uma expires_on data. A UDF do filtro de linha verifica essa data em relação a current_date(), portanto, as entradas expiradas são silenciosamente ignoradas e o acesso é revogado automaticamente sem intervenção manual.

Limpeza

Para remover todos os objetos criados neste tutorial, execute o seguinte.

DROP POLICY user_access_filter ON SCHEMA abac_tutorial.mapping_demo;
DROP POLICY pii_mask_name ON SCHEMA abac_tutorial.mapping_demo;
DROP POLICY pii_mask_email ON SCHEMA abac_tutorial.mapping_demo;
DROP FUNCTION IF EXISTS abac_tutorial.mapping_demo.access_filter;
DROP FUNCTION IF EXISTS abac_tutorial.mapping_demo.pii_mask;
DROP TABLE IF EXISTS abac_tutorial.mapping_demo.orders;
DROP TABLE IF EXISTS abac_tutorial.mapping_demo.user_access;
DROP SCHEMA IF EXISTS abac_tutorial.mapping_demo CASCADE;

Para remover as marcas governadas region, department, pii, e priority, use a interface do usuário do Catalog Explorer.