Use tabelas de mapeamento para controlo dinâmico de acesso

Este tutorial mostra como usar uma tabela de mapeamento para controlar o acesso ao nível das linhas e das colunas sem gerir um grande número de grupos. Uma única tabela de consulta gere tanto o filtro de linhas como o mascaramento de colunas. As alterações de acesso requerem apenas uma atualização numa linha. Não precisas de criar novos grupos ou reescrever políticas.

Este tutorial também demonstra mascaramento condicional: as colunas de PII são mascaradas de forma diferente dependendo do valor de outra coluna na mesma linha. As encomendas assinaladas confidential têm as suas PII totalmente censuradas, independentemente do nível de autorização do utilizador.

Para orientações gerais sobre o design de tabelas de mapeamento, veja Usar tabelas de mapeamento para criar uma lista de controlo de acesso.

Pré-requisitos

  • Databricks Runtime 16.4 ou superior, ou computação sem servidor.
  • Permissões de administrador de conta ou de espaço de trabalho (para criar etiquetas governadas).
  • MANAGE Permissão sobre o catálogo ou esquema de destino.
  • EXECUTE sobre as UDFs.
  • Um caderno SQL ou editor de consultas.

Scenario

A sua organização tem colaboradores em quatro regiões (EUA Este, EUA Oeste, UE, APAC) e quatro departamentos. Cada utilizador deve ver apenas as linhas que correspondem à sua região e departamento, e as colunas de PII devem ser mascaradas com base em dois fatores: o nível de autorização de acesso do utilizador (full, masked ou none) armazenado numa tabela de mapeamento, e a ordem do order_priority.

Com uma abordagem baseada em grupo, é necessário um grupo para cada combinação região-departamento. Por exemplo, precisas de 16 grupos para quatro regiões e quatro departamentos. Adicionar níveis de autorização de PII triplica essa importância. Cada nova região ou departamento exige novos grupos e atualizações de políticas.

A abordagem de tabela de mapeamento substitui isto por uma única tabela de consulta: uma linha por utilizador, uma coluna por dimensão de acesso. Para alterar o acesso de um utilizador, atualiza-se uma linha.

Passo 1: Criar etiquetas governadas

Antes de executar qualquer SQL, crie as seguintes etiquetas governadas na interface do Catalog Explorer (Catalog>Govern>Etiquetas Governadas>Criar etiqueta governada):

Chave da etiqueta Valores permitidos
region (etiqueta só com chave)
department (etiqueta só com chave)
pii name, email
priority (etiqueta só com chave)

As etiquetas region e department informam a política de filtro de linha sobre quais colunas passar para o filtro UDF. A pii etiqueta indica às políticas de máscara da coluna quais colunas devem mascarar e que tipo de PII contêm. A priority tag permite que as políticas de máscara de coluna passem o valor order_priority para a máscara UDF para mascaramento condicional.

Advertência

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

Passo 2: Construir dados de exemplo

Crie um catálogo, esquema e tabela de encomendas. A order_priority coluna controla o mascaramento condicional: as ordens marcadas confidential têm as suas informações pessoalmente identificáveis (PII) totalmente censuradas, mesmo para utilizadores com elevado nível de autorização.

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

Passo 3: Aplicar etiquetas governadas

Marque as colunas para que as políticas ABAC as possam descobrir automaticamente. A coluna order_priority está marcada com a etiqueta priority apenas de chave para que as políticas de máscara da coluna possam associá-la MATCH COLUMNS e passar o 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' = '');

Passo 4: Criar a tabela de mapeamento

Em vez de criar grupos para cada região, departamento e combinação de autorizações, mantém uma tabela com uma linha por utilizador. A pii_access coluna controla como as colunas de PII aparecem:

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

A expires_on coluna define uma data de validade para cada entrada de acesso. Após esta data, o filtro de linha UDF deixa de coincidir com a entrada e o utilizador perde o acesso silenciosamente, sem necessidade de revogação manual. Isto é útil para empreiteiros, acordos temporários de partilha de dados ou projetos com tempo limitado.

Se um utilizador precisar de acesso a múltiplas combinações de regiões e departamentos, adicione linhas adicionais.

Note

Mantém as tabelas de mapeamento pequenas e simples. Cada consulta contra uma tabela protegida executa os UDFs do filtro de linhas e da máscara de coluna, que por sua vez consultam a tabela de mapeamento. Grandes tabelas de mapeamento e lógica UDF complexa podem afetar o desempenho das consultas. Use esquemas restritos e mantenha a lógica UDF numa única pesquisa 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');

Passo 5: Criar o filtro de linhas UDF

Este UDF recebe os valores sales_region e dept de uma linha (passados pela política através da correspondência de tags), procura o utilizador atual na tabela de correspondência e retorna apenas TRUE se existir uma entrada correspondente que esteja existente e não expirada. Os utilizadores que não estão na tabela de mapeamento, ou cujo acesso expirou, não conseguem ver nenhuma linha (design de falha-fechada).

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

Passo 6: Criar a máscara de coluna UDF

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

  • Camada 1 (mascaramento condicional): Se order_priority for confidential, as PII são sempre totalmente censuradas, independentemente do nível de autorização do utilizador.
  • Camada 2 (autorização do utilizador): Para linhas padrão, o UDF verifica a tabela de mapeamento para o nível do pii_access utilizador e aplica a máscara correspondente. Se um utilizador tiver múltiplas entradas na tabela de mapeamento (acesso multi-região), aplica-se a maior autorização em 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;

Passo 7: Criar as políticas

Crie três políticas, todas orientadas pela mesma tabela de mapeamento. Ambas as políticas de máscara de coluna usam a mesma pii_mask função. O pii_type argumento indica à função que estilo de mascaramento aplicar, por isso não precisas de um UDF separado por tipo de coluna.

A priority etiqueta governada é usada em MATCH COLUMNS para corresponder à order_priority coluna e passar o seu valor para a máscara UDF como order_pri. É assim que o mascaramento condicional é implementado: a política passa o valor de prioridade da linha para a UDF (Função Definida pelo Usuário) no momento da execução 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);

Passo 8: Verificar os resultados

A entrada da sua tabela de mapeamento dá-lhe acesso us_east / engineering com masked autorização. Execute a seguinte consulta para verificar se vê apenas a ordem #1, com as PII parcialmente mascaradas.

SELECT * FROM abac_tutorial.mapping_demo.orders;

O Pedido #1 tem order_priority = 'standard', portanto, a sua autorização masked aplica-se.

Resultado esperado para o seu utilizador:

identificador_de_encomenda nome_cliente customer_email região de vendas departamento Montante data de encomenda prioridade_de_pedido
1 A*** o***@acme.com us_east Engenharia 50000 2025-01-15 norma

O que outros utilizadores veem:

User Ordens visíveis prioridade_de_ordem Comportamento das PII
bob@example.com (full autorização) #4 (us_west, vendas) confidencial ***REDACTED*** — autorização de sobreposição full confidencial
carol@example.com (none autorização) #5 (EU, engenharia) norma ***REDACTED***none a permissão significa supressão total
david@example.com (masked autorização) #7 (APAC, Marketing) confidencial ***REDACTED*** — autorização de sobreposição masked confidencial
(dono do catálogo) Todos os 10 Todos sem máscara (o proprietário está isento das apólices)
(utilizador não listado) Nenhum O filtro de linhas não retorna nenhuma linha

Repara que o Bob tem full autorização mas continua a ver ***REDACTED*** porque a ordem #4 é confidential. Isto é mascaramento condicional: o valor de prioridade da linha sobrepõe-se à autorização do utilizador.

Passo 9: Atualizar o acesso dinamicamente

O principal benefício da abordagem de tabela de mapeamento é que pode alterar o acesso atualizando linhas na tabela. Não precisa de atualizar políticas, UDFs ou associações a grupos.

Reatribuição para outro departamento

Muda o teu departamento de engineering para sales. A Encomenda #2 (Beta Inc) é uma confidential encomenda de venda, por isso as suas PII estão totalmente censuradas mesmo com masked autorização.

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

Execute a seguinte consulta para verificar. Deverás ver a ordem #2 com ***REDACTED*** PII.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Reverter a alteração:

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

Atualização da autorização de PII

Altere a sua autorização de masked para full. Para linhas de prioridade padrão, agora pode ver os valores reais das informações pessoalmente identificáveis (PII).

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

Execute a seguinte consulta para verificar. A Ordem #1 é standard prioritária, portanto, com full autorização, deverá 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

Inserir uma segunda fila 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 seguinte consulta para verificar. Agora deverá ver tanto a ordem #1 (us_east, engenharia) como a ordem #5 (eu, engenharia), com as PII parcialmente mascaradas.

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 acesso

Defina a sua entrada de acesso para uma data passada. O filtro de linhas UDF verifica expires_on >= current_date(), pelo que as entradas expiradas são silenciosamente ignoradas e o acesso é automaticamente revogado. Isto é útil para empreiteiros, acordos de partilha de dados com 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 seguinte consulta para verificar se não vê linhas.

SELECT * FROM abac_tutorial.mapping_demo.orders;

Restaurar o acesso com data de expiração futura:

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

Execute a seguinte consulta 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 consulta controla tanto o filtro de linhas como o mascaramento de colunas. As alterações de acesso são feitas atualizando linhas, sem necessidade de alterações de políticas ou grupos.
  • Mascaramento condicional: o UDF da máscara verifica a order_priority coluna em cada linha para decidir como mascarar os PII. As linhas confidenciais são sempre completamente ocultadas, independentemente do nível de autorização do utilizador, implementadas através da marcação order_priority e passada para a UDF através de MATCH COLUMNS.
  • Expiração do acesso: a tabela de mapeamento inclui uma expires_on data. O filtro de registo UDF verifica esta data contra current_date(), pelo que 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 etiquetas region, department, pii e priority controladas, use a interface do utilizador do Explorador de Catálogos.