Como projetar sistemas de autorização baseados em atributos com ABAC

1. Fundamentos do ABAC e diferenciação de outros modelos

O ABAC (Attribute-Based Access Control) é um modelo de controle de acesso que avalia permissões com base em atributos associados a quatro entidades fundamentais: sujeito (quem solicita), recurso (o que está sendo acessado), ação (o que está sendo feito) e ambiente (o contexto da solicitação). Diferentemente do RBAC (Role-Based Access Control), que atribui permissões fixas a papéis predefinidos, ou das ACLs (Access Control Lists), que listam permissões específicas por usuário/recurso, o ABAC oferece granularidade dinâmica e flexibilidade para expressar regras complexas.

Enquanto o RBAC exige a criação de dezenas de papéis para cobrir variações de permissão, o ABAC permite definir uma única política que combina múltiplos atributos. Por exemplo, em vez de criar papéis "Gerente_Financeiro_Diurno" e "Gerente_Financeiro_Noturno", uma política ABAC pode avaliar: "Permitir acesso se cargo = gerente E departamento = finanças E horário entre 9h e 18h". Isso reduz a proliferação de papéis e simplifica a manutenção.

Casos de uso ideais para ABAC incluem sistemas multi-tenant (onde inquilinos diferentes têm atributos distintos), ambientes regulados como LGPD e HIPAA (que exigem controle fino baseado em contexto) e aplicações com regras dinâmicas que mudam com frequência.

2. Estrutura de atributos: sujeito, recurso, ação e ambiente

Os atributos do sujeito capturam características do usuário ou entidade solicitante. Exemplos incluem:

sujeito.cargo = "analista_financeiro"
sujeito.departamento = "financas"
sujeito.localizacao = "brasil"
sujeito.nivel_confianca = 3
sujeito.autenticacao_multifator = true

Atributos do recurso descrevem o objeto sendo acessado:

recurso.tipo = "registro_financeiro"
recurso.classificacao = "confidencial"
recurso.proprietario = "joao.silva"
recurso.data_criacao = "2024-01-15"

Atributos de ação e ambiente contextualizam a operação:

acao.tipo = "leitura"
ambiente.horario = "14:30"
ambiente.ip = "192.168.1.100"
ambiente.dispositivo = "corporativo"
ambiente.pais = "BR"

Essa estrutura permite que políticas avaliem combinações complexas, como "negar exportação de dados se ambiente.pais != recurso.pais_origem".

3. Projeto de políticas ABAC com linguagens declarativas

Políticas ABAC são definidas usando linguagens declarativas como XACML, ALFA ou JSON Policy. Uma política típica contém três elementos: target (alvo que especifica quando a política se aplica), condition (condição que deve ser verdadeira) e effect (permitir ou negar).

Exemplo de política em JSON Policy:

{
  "policyId": "acesso_registros_financeiros",
  "target": {
    "resource": { "type": "registro_financeiro" },
    "action": { "type": "leitura" }
  },
  "rules": [
    {
      "effect": "permit",
      "condition": {
        "allOf": [
          { "attribute": "sujeito.departamento", "equals": "financas" },
          { "attribute": "ambiente.horario", "greaterThanOrEquals": "09:00" },
          { "attribute": "ambiente.horario", "lessThanOrEquals": "18:00" },
          { "attribute": "sujeito.autenticacao_multifator", "equals": true }
        ]
      }
    }
  ],
  "defaultEffect": "deny"
}

Esta política permite leitura de registros financeiros apenas se o sujeito for do departamento de finanças, entre 9h e 18h, com autenticação multifator ativada. Qualquer outra combinação resulta em negação por padrão.

4. Arquitetura do motor de decisão de autorização (PDP)

A arquitetura ABAC típica envolve quatro componentes principais:

  • PEP (Policy Enforcement Point): intercepta requisições e exige decisão do PDP
  • PDP (Policy Decision Point): avalia políticas e retorna permitir/negar
  • PIP (Policy Information Point): fornece atributos de fontes externas
  • PAP (Policy Administration Point): gerencia e versiona políticas

Fluxo de decisão:

1. Usuário envia requisição HTTP GET /api/financeiros/123
2. PEP intercepta e extrai atributos do token JWT e contexto
3. PEP envia requisição XACML ao PDP com atributos
4. PDP consulta PIP para atributos adicionais (ex: classificação do recurso)
5. PDP avalia políticas e retorna "Permit" ou "Deny"
6. PEP aplica decisão (200 OK ou 403 Forbidden)

Para reduzir latência, implemente cache de decisões com TTL configurável. Decisões para combinações frequentes de atributos podem ser cacheadas por 5 a 60 segundos, dependendo da volatilidade dos atributos.

5. Integração de fontes de atributos (PIP) em tempo real

O PIP conecta-se a fontes de dados para obter atributos dinâmicos. Exemplos de integração:

# Atributos de sujeito via LDAP
PIP.ldap.query("uid=joao.silva", ["department", "clearanceLevel"])

# Atributos de recurso via banco relacional
PIP.sql.query("SELECT classification, owner FROM documents WHERE id = 123")

# Atributos de ambiente via API externa
PIP.http.get("https://geolocation-api.com/192.168.1.100")

Para atributos ausentes, defina valores padrão seguros:

atributo.sujeito.nivel_confianca = atributo.sujeito.nivel_confianca ?? 0
recurso.classificacao = recurso.classificacao ?? "publico"

Sempre implemente negação por omissão (default deny) quando atributos não puderem ser resolvidos.

6. Implementação de ABAC em APIs REST e microsserviços

Em APIs REST, atributos do sujeito são transportados via JWT com claims personalizados:

{
  "sub": "joao.silva",
  "department": "financas",
  "clearance": 3,
  "mfa": true,
  "country": "BR"
}

Exemplo de middleware de autorização em gateway de API (Kong):

# Plugin de autorização personalizado
local jwt = ngx.var.jwt_payload
local path = ngx.var.uri
local method = ngx.var.request_method

local attributes = {
  sujeito = { departamento = jwt.department, nivel = jwt.clearance },
  recurso = { tipo = extrair_tipo_recurso(path) },
  acao = { tipo = method },
  ambiente = { horario = os.date("%H:%M") }
}

local decisao = pdp.avaliar(attributes)
if decisao == "deny" then
  ngx.exit(403)
end

Fluxo completo:

Requisição: GET /api/documentos/456
Headers: Authorization: Bearer <JWT>
IP: 200.201.202.203
Horário: 15:30

PEP extrai:
  sujeito.departamento = "rh" (do JWT)
  recurso.tipo = "documento_pessoal" (da URL)
  acao.tipo = "leitura"
  ambiente.horario = "15:30"

PDP avalia política: "Permitir leitura de documento_pessoal apenas se sujeito.departamento = 'rh'"
Resultado: Permit → 200 OK

7. Testes, auditoria e manutenção de políticas ABAC

Testes unitários para políticas devem simular combinações de atributos:

Teste 1: sujeito.departamento = "financas", horario = "14:00" → Permit
Teste 2: sujeito.departamento = "rh", horario = "14:00" → Deny
Teste 3: sujeito.departamento = "financas", horario = "20:00" → Deny
Teste 4: sujeito.departamento = "financas", horario = "14:00", mfa = false → Deny

Logs de auditoria devem registrar:

{
  "timestamp": "2024-03-15T14:30:00Z",
  "user": "joao.silva",
  "resource": "/api/financeiros/123",
  "action": "GET",
  "decision": "permit",
  "policy": "acesso_registros_financeiros",
  "attributes": {
    "sujeito.departamento": "financas",
    "ambiente.horario": "14:30",
    "sujeito.mfa": true
  }
}

Versionamento de políticas com Git permite rastrear mudanças e reverter alterações problemáticas. Realize revisões trimestrais para remover políticas obsoletas.

8. Desafios comuns e boas práticas na adoção de ABAC

Gerenciamento de complexidade: Use hierarquias de atributos e templates. Por exemplo, defina um atributo "nivel_acesso" que combina cargo e departamento, reduzindo o número de condições em políticas.

Performance em alta escala: Otimize consultas ao PIP com índices em atributos frequentemente avaliados (ex: departamento, classificação). Considere caching de atributos estáveis com TTL de 5 minutos.

Equilíbrio entre segurança e usabilidade: Evite políticas excessivamente restritivas. Teste com usuários reais para identificar falsos positivos. Implemente um modo de auditoria que registre decisões sem bloquear, permitindo ajustes antes da aplicação completa.

Policy sprawl: Estabeleça um ciclo de vida para políticas com data de expiração e revisão obrigatória. Agrupe políticas relacionadas em pacotes e use namespaces para organizar por domínio (ex: "financas.leitura", "rh.escrita").

Referências