MÓDULO 11 · CONCEITO 06 DE 12

RBAC, ABAC e ReBAC — modelos de controle de acesso

Papéis, atributos e relacionamentos como base de autorização — RBAC com hierarquia, ABAC com políticas OPA, Google Zanzibar e SpiceDB para sistemas de relacionamento em escala

Tempo de leitura ~24 min Pré-requisito 05 · JWT em Profundidade Próximo 07 · Criptografia Aplicada

Autorização — a decisão de o que uma identidade autenticada pode fazer — é um problema que os sistemas resolvem mal com surpreendente frequência. Não porque a lógica de negócio seja complexa, mas porque o modelo de dados escolhido para representar políticas de acesso cresce de formas que o design original não antecipou. Sistemas começam com "admin pode tudo, user pode ler" — uma distinção que cabe em um if — e evoluem para "usuário pode editar este documento se for o autor, ou se tiver permissão explícita de edição, ou se for membro de um grupo que tem acesso ao projeto ao qual o documento pertence, ou se for admin mas não estiver fora do horário de expediente". Nesse ponto, o if está muito além do ponto de retorno.

RBAC (Role-Based Access Control), ABAC (Attribute-Based Access Control) e ReBAC (Relationship-Based Access Control) são modelos formais para representar políticas de autorização. Cada um resolve um problema diferente com trade-offs diferentes. A escolha incorreta — RBAC para um problema de relacionamento, ABAC para um problema de hierarquia simples — produz sistemas difíceis de manter e impossíveis de auditar. Este conceito cobre os três modelos em profundidade, com as implementações concretas mais usadas em produção e os critérios de escolha.

RBAC — Role-Based Access Control

RBAC foi formalizado por Ferraiolo e Kuhn em 1992 e pelo NIST em 2000 (NIST Special Publication 800-192). O modelo central é simples: usuários são atribuídos a papéis, e papéis têm permissões. A query de autorização é: "o usuário U tem o papel R? O papel R tem a permissão P? Então conceder."

-- Schema RBAC básico em SQL
CREATE TABLE roles (id SERIAL PRIMARY KEY, name TEXT UNIQUE NOT NULL);
CREATE TABLE permissions (id SERIAL PRIMARY KEY, action TEXT, resource TEXT,
  UNIQUE(action, resource));
CREATE TABLE role_permissions (role_id INT REFERENCES roles, permission_id INT REFERENCES permissions,
  PRIMARY KEY(role_id, permission_id));
CREATE TABLE user_roles (user_id INT, role_id INT REFERENCES roles,
  PRIMARY KEY(user_id, role_id));

-- Verificação de permissão
SELECT EXISTS (
  SELECT 1 FROM user_roles ur
  JOIN role_permissions rp ON ur.role_id = rp.role_id
  JOIN permissions p ON rp.permission_id = p.id
  WHERE ur.user_id = $1
    AND p.action = $2    -- ex: 'delete'
    AND p.resource = $3  -- ex: 'documents'
);

O modelo básico é escalável para sistemas com dezenas de papéis e centenas de permissões. O problema surge quando as permissões se tornam muito granulares ou quando os papéis proliferam — o que Ferraiolo e Kuhn chamaram de "role explosion". Times que criam um papel por combinação de permissões únicas chegam a centenas de papéis distintos, tornando a gestão impraticável.

RBAC hierárquico (RBAC-H) resolve parte do problema: papéis herdam permissões de papéis pai. super_admin herda de admin, que herda de editor, que herda de viewer. Permissões do papel pai são transitivas para os filhos. Isso reduz duplicação mas não resolve o problema fundamental de regras de acesso dependentes de contexto.

heurística do sênior

RBAC é correto quando a resposta para "o que determina o acesso?" é o papel do usuário na organização. Se a resposta envolver "depende de qual recurso específico", "depende do horário", "depende de quem criou o recurso" — RBAC básico não é o modelo certo, embora RBAC com verificações adicionais (chamado às vezes RBAC+) possa cobrir os 80% mais simples.

Implementação em código: a abordagem mais direta para APIs é decorator/middleware que verifica papéis antes de executar o handler. A complexidade de autorização fica nos decorators, não espalhada pelo código de negócio.

C# — Policy-based authorization com ASP.NET Core
// Program.cs — configuração de políticas
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("CanEditDocuments", policy =>
        policy.RequireRole("admin", "editor"));

    options.AddPolicy("CanDeleteDocuments", policy =>
        policy.RequireRole("admin"));

    options.AddPolicy("CanPublish", policy =>
        policy.RequireClaim("feature_flags", "publishing_enabled")
              .RequireRole("editor", "admin"));
});

// Controller — aplicação da política
[HttpDelete("/documents/{id}")]
[Authorize(Policy = "CanDeleteDocuments")]
public async Task<IActionResult> Delete(int id)
{
    // Política verificada antes de entrar no handler
    var doc = await _docs.GetAsync(id);
    // Ainda precisa verificar ownership — RBAC não resolve isso
    if (doc.UserId != User.GetUserId() && !User.IsInRole("admin"))
        return Forbid();
    await _docs.DeleteAsync(id);
    return NoContent();
}

ASP.NET Core separa autenticação de autorização cleanly. Policy-based auth é mais flexível que [Authorize(Roles = "admin")] e permite composição de regras sem modificar o handler.

Python — decorator de autorização com FastAPI
from functools import wraps
from fastapi import HTTPException, Depends

def require_role(*roles: str):
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, current_user: User = Depends(get_current_user), **kwargs):
            if not any(role in current_user.roles for role in roles):
                raise HTTPException(status_code=403, detail="Insufficient permissions")
            return await func(*args, current_user=current_user, **kwargs)
        return wrapper
    return decorator

@router.delete("/documents/{doc_id}")
@require_role("admin", "editor")
async def delete_document(
    doc_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    doc = await db.get(Document, doc_id)
    if not doc:
        raise HTTPException(404)
    # RBAC verifica papel — mas ownership precisa de verificação adicional
    if doc.user_id != current_user.id and "admin" not in current_user.roles:
        raise HTTPException(403, "Cannot delete document owned by another user")
    await db.delete(doc)
    await db.commit()

O decorator require_role lida com RBAC; a verificação de ownership dentro do handler é a camada de autorização baseada em relacionamento que RBAC não cobre.

Go — middleware de autorização com chi
func RequireRole(roles ...string) func(http.Handler) http.Handler {
    roleSet := make(map[string]bool)
    for _, r := range roles { roleSet[r] = true }

    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            user := UserFromContext(r.Context())
            for _, role := range user.Roles {
                if roleSet[role] {
                    next.ServeHTTP(w, r)
                    return
                }
            }
            http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden)
        })
    }
}

// Rotas com middleware de papel
r.With(RequireRole("admin", "editor")).Delete("/documents/{id}", deleteDocument)
r.With(RequireRole("admin")).Post("/documents/{id}/publish", publishDocument)

chi permite composição de middlewares por rota sem repetição. O RequireRole é reutilizável por qualquer handler que precise de verificação de papel.

ABAC — Attribute-Based Access Control

ABAC, descrito pelo NIST no SP 800-162 (2014), generaliza RBAC: em vez de verificar apenas o papel do usuário, verifica atributos arbitrários do sujeito (usuário), do objeto (recurso), da ação, e do contexto. Uma política ABAC pode expressar: "usuários com atributo department=finance podem ler documentos com atributo classification=financial durante horário de trabalho (time BETWEEN 08:00 AND 18:00) de IPs na subnet corporativa".

A engine mais usada para ABAC em sistemas modernos é Open Policy Agent (OPA, CNCF), que usa a linguagem Rego para expressar políticas. OPA roda como sidecar ou como serviço externo e recebe um input JSON com o contexto da requisição; a política Rego retorna um resultado booleano (allow/deny) ou um objeto com detalhes.

# OPA — Política Rego para controle de documentos
package documents.authz

import future.keywords.if

# Por padrão, negar tudo
default allow := false

# Admin pode tudo
allow if {
    input.user.roles[_] == "admin"
}

# Autor pode editar seus próprios documentos em rascunho
allow if {
    input.action == "edit"
    input.document.user_id == input.user.id
    input.document.status == "draft"
}

# Editor pode publicar se document.status == "approved"
allow if {
    input.action == "publish"
    input.user.roles[_] == "editor"
    input.document.status == "approved"
    # Apenas durante horário de trabalho UTC-3
    time.clock(time.now_ns())[0] >= 8
    time.clock(time.now_ns())[0] < 18
}
# Input JSON para a query OPA — enviado pelo resource server
{
  "user": {
    "id": "user_123",
    "roles": ["editor"],
    "department": "content"
  },
  "action": "edit",
  "document": {
    "id": "doc_456",
    "user_id": "user_123",
    "status": "draft",
    "classification": "internal"
  },
  "context": {
    "ip": "10.0.5.42",
    "timestamp": "2026-05-12T14:30:00Z"
  }
}

A vantagem do ABAC com OPA é a separação entre política e código: as regras de negócio de autorização ficam em arquivos Rego versionados, testáveis, e atualizáveis sem redeploy do serviço. Times de segurança podem revisar e atualizar políticas sem acesso ao código da aplicação. O custo é a curva de aprendizado do Rego e a latência adicional da consulta ao OPA por requisição (mitigável com cache e modo em-processo).

armadilha de adoção

ABAC com políticas ricas é difícil de auditar. "Quais recursos o usuário X pode acessar?" é uma query trivial em RBAC (listar permissões do papel). Em ABAC, a resposta depende de todos os atributos do contexto — um auditoria completa requer simular cada combinação de atributos possível. Para sistemas com requisito regulatório de auditoria de acesso, ABAC puro pode ser problemático. RBAC com ABAC como camada adicional (para os casos que RBAC não cobre) é frequentemente mais auditável.

ReBAC — Relationship-Based Access Control

Google Zanzibar, descrito no paper "Zanzibar: Google's Consistent, Global Authorization System" (USENIX ATC 2019), é o sistema de autorização que controla o acesso a Google Drive, Gmail, YouTube, e dezenas de outros produtos Google. O problema que Zanzibar resolve é fundamentalmente diferente do que RBAC e ABAC resolvem: autorização baseada em relacionamentos entre objetos.

Em um sistema de documentos colaborativo, a pergunta de autorização é: "o usuário U pode ler o documento D?" A resposta depende de uma cadeia de relacionamentos: U tem papel de viewer em D diretamente? U é membro de um grupo G que tem acesso a D? U tem acesso à pasta F que contém D? U tem acesso ao workspace W que contém F? Em RBAC, modelar essa hierarquia de containment requer queries SQL complexas com múltiplos joins recursivos. Em Zanzibar, a query é expressa como tuplas de relacionamento.

# Tuplas de relacionamento Zanzibar — armazenadas como (objeto, relação, usuário/grupo)
document:123#owner@user:alice         # alice é owner do documento 123
document:123#editor@group:beta-team   # o grupo beta-team é editor do doc 123
group:beta-team#member@user:bob       # bob é membro do grupo beta-team
folder:projects#document@document:123  # documento 123 está na pasta projects
folder:projects#viewer@user:charlie   # charlie tem viewer na pasta projects

# Query: "pode user:bob editar document:123?"
# Check: document:123#editor@user:bob
# → Expand: user:bob pode ser em group:beta-team#member
# → Expand: group:beta-team é document:123#editor
# → Sim, bob pode editar via grupo

# Query: "pode user:charlie ler document:123?"
# Check: document:123#viewer@user:charlie
# → Charlie não tem acesso direto
# → document:123 está em folder:projects
# → folder:projects#viewer@user:charlie → Sim

SpiceDB (Authzed) é a implementação open source mais madura de Zanzibar. Usa uma linguagem de schema chamada Authzed Schema Language (ASL) para definir os tipos de objeto e as relações possíveis, e expõe uma API gRPC para check de permissão, expand de permissão (quem tem acesso?), e list de recursos (quais recursos o usuário tem acesso?).

# SpiceDB schema — sistema de documentos
definition user {}

definition group {
  relation member: user
}

definition folder {
  relation parent: folder
  relation viewer: user | group#member
  relation editor: user | group#member

  permission view = viewer + editor + parent->view
  permission edit = editor + parent->edit
}

definition document {
  relation parent_folder: folder
  relation owner: user
  relation editor: user | group#member
  relation viewer: user | group#member

  permission view = viewer + editor + owner + parent_folder->view
  permission edit = editor + owner + parent_folder->edit
  permission delete = owner
}

O schema define que a permissão view de um documento é a union de viewers diretos, editors, o owner, e quem tem view na pasta pai — transitivamente. Isso é o que torna ReBAC poderoso para sistemas onde a hierarquia de containment define acesso. Google Drive, GitHub (repositórios em organizations), Notion (páginas em workspaces) e Dropbox são exemplos canônicos.

Qual modelo para qual problema

A decisão entre RBAC, ABAC e ReBAC não é de modismo técnico — é de adequação ao problema. Os critérios de escolha:

Na prática, sistemas maduros combinam modelos: RBAC para os casos simples (papéis organizacionais), ABAC para regras de contexto (horário, localização, classificação), e ReBAC para hierarquia de recursos. A tentação de escolher apenas um modelo e forçar todos os casos nele resulta em explosão de papéis (RBAC forçado), políticas incompreensíveis (ABAC forçado), ou schema de relacionamento monstruoso (ReBAC forçado).

princípio orientador

A pergunta de design correta não é "qual modelo de autorização vamos usar?" mas "para cada tipo de decisão de acesso no nosso sistema, qual modelo captura a regra de forma mais direta?". Misturar modelos é sinal de maturidade, não de inconsistência — desde que cada uso seja intencional e a fronteira entre eles seja clara.

Policy Decision Point e Policy Enforcement Point

Uma arquitetura de autorização bem separada distingue dois papéis: o Policy Decision Point (PDP) — onde a decisão de autorização é computada — e o Policy Enforcement Point (PEP) — onde a decisão é aplicada. Em sistemas simples, ambos estão no mesmo código; em sistemas maiores, o PDP é externalizado (OPA, SpiceDB) e o PEP é o middleware do resource server que chama o PDP e aplica o resultado.

A separação tem um custo — latência de rede por requisição de autorização — e um benefício — a lógica de autorização vive em um lugar só, versionável, testável, e atualizável sem redeploy. Para sistemas com múltiplos resource servers e políticas complexas, o benefício supera o custo. Para um monolito com regras simples, externalizar o PDP é over-engineering.

Decisões de engenharia

RBAC vs ABAC vs ReBAC — critério de escolha

RBAC: acesso determinado pelo papel organizacional. "Admin pode tudo, editor pode publicar." Regras não dependem de atributos do recurso nem de hierarquia. Simples de auditar — basta listar permissões do papel.

ABAC: acesso depende de atributos dinâmicos: horário, localização, classificação do dado, atributos do tenant. Regras que RBAC não captura sem role explosion.

ReBAC: acesso segue hierarquia de containment entre objetos. "Quem tem acesso à pasta X tem acesso a todos os documentos dentro." Sistemas colaborativos, multi-tenant com delegação, hierarquias de org.

PDP inline vs PDP externo

PDP inline (lógica no próprio serviço): adequado para RBAC simples em monolito ou em um serviço com poucas regras. Zero latência adicional, sem dependência de serviço externo.

PDP externo (OPA/SpiceDB como serviço): quando múltiplos serviços compartilham as mesmas políticas, quando times de segurança precisam atualizar regras sem redeploy, ou quando políticas são suficientemente complexas para requerer testes isolados. Custo: latência de rede por request — mitigável com sidecar (OPA em processo) ou cache de decisão.

SpiceDB vs OpenFGA vs OPA

SpiceDB (Authzed): melhor implementação de Zanzibar, API gRPC madura, playground rico. Escolha quando o caso de uso é claramente ReBAC com hierarquias complexas.

OpenFGA (CNCF/Okta): API compatível, melhor integração com ecossistema Auth0/Okta. Escolha quando já usa Auth0 ou quando prefere o modelo de dados ligeiramente mais simples.

OPA (CNCF): poliglota — implementa RBAC, ABAC, ou ReBAC simples em Rego. Escolha quando as políticas são principalmente ABAC ou quando já há OPA na infra (Kubernetes admission control). Não é otimizado para grafos de relacionamento profundos como Zanzibar.

Role explosion — mitigação

Sintoma: o número de papéis cresce com cada novo caso de uso; papéis se tornam combinações de permissões únicas em vez de abstrações organizacionais.

Mitigação com RBAC-H: consolidar papéis em hierarquia — papéis filho herdam do pai. Reduz duplicação de permissões sem eliminar o modelo RBAC.

Migrar para ABAC: quando papéis diferenciam por atributo do recurso (ex: editor_projeto_alpha, editor_projeto_beta), substituir por política ABAC que verifica o atributo do projeto no input. Elimina a classe de papel inteira.

Migrar para ReBAC: quando papéis diferenciam por hierarquia de objeto, substituir por relacionamentos diretos usuário→recurso via SpiceDB. Uma tupla substitui mil papéis.

Como praticar

  1. Implementar RBAC com hierarquia no banco de dados. Crie o schema SQL de RBAC com herança de papéis: tabelas de papéis com relação pai-filho (parent_role_id), permissões, e uma query recursiva (CTE WITH RECURSIVE) que resolve as permissões transitivas de um usuário. Implemente a verificação em uma API simples e teste os casos de borda: papel sem permissão própria mas com permissão herdada, usuário com múltiplos papéis onde apenas um tem a permissão necessária.
    Critério: a query recursiva retorna permissões transitivas corretamente em 3+ níveis de hierarquia; testes automatizados cobrem allow por herança e deny quando nenhum papel do usuário tem a permissão — sem false positives.
  2. Escrever políticas OPA com testes unitários para um sistema existente. Instale OPA localmente e escreva políticas Rego para um conjunto de regras de autorização reais — mínimo 3 regras distintas (pelo menos uma com condição de atributo de contexto como horário ou departamento). Escreva testes OPA (opa test) cobrindo allow e deny para cada regra, incluindo os edge cases.
    Critério: opa test passa com cobertura ≥ 80% das regras; pelo menos 5 casos de teste com expect deny que realmente retornam deny — garantia de que o default-deny está funcionando.
  3. Modelar um sistema colaborativo no playground do Authzed (SpiceDB). Acesse play.authzed.com e modele: documentos em pastas, pastas em projetos, usuários com papéis diferentes por recurso, e grupos com membros. Escreva 10+ tuplas de relacionamento e valide 5 queries de check — algumas allow via herança transitiva, outras deny por ausência de relacionamento. Observe como a hierarquia é resolvida sem SQL.
    Critério: pelo menos 2 queries allow que funcionam exclusivamente via herança transitiva (sem tupla direta usuário→documento); pelo menos 2 queries deny esperadas; o schema exportado tem pelo menos 3 tipos de objeto com permissões compostas por union/intersection.
  4. Identificar e resolver role explosion em um sistema existente. Em um sistema RBAC real ou simulado com 10+ papéis, mapeie quais papéis se diferenciam apenas por um atributo do recurso (ex: tenant, projeto, departamento). Para cada classe de role explosion identificada, proponha a substituição: ABAC via OPA (se é atributo do contexto) ou ReBAC via tuplas (se é hierarquia de objeto). Implemente a substituição para pelo menos uma classe.
    Critério: a substituição elimina pelo menos 3 papéis redundantes; os testes de autorização existentes passam contra o novo modelo; documento explica a decisão de qual modelo foi escolhido e por quê.
  5. Integrar SpiceDB ou OpenFGA em uma API existente via gRPC. Adicione SpiceDB (via Docker) ou OpenFGA a um projeto com API HTTP. Substitua uma verificação de autorização existente (mesmo que simples) pela chamada ao serviço de autorização: escreva o schema, popule as tuplas no setup do usuário, e substitua o check inline pela chamada gRPC CheckPermission. Meça a latência adicionada pelo sidecar vs chamada de rede.
    Critério: a API existente passa os testes de integração com SpiceDB/OpenFGA como PDP; a latência adicionada pela chamada gRPC é medida e documentada (p50 e p99); o schema SpiceDB está versionado no repositório junto com seeds de tuplas para testes.

Perguntas de entrevista

Quando RBAC falha e você precisa de ABAC ou ReBAC? Dê um exemplo concreto de cada transição.

RBAC → ABAC: RBAC falha quando o acesso depende de atributos que não são o papel do usuário. Exemplo: uma plataforma multi-tenant onde analistas podem ver apenas dados do seu próprio tenant. Com RBAC puro, você precisaria criar um papel por tenant (analyst_acme, analyst_contoso) — role explosion clássico. Com ABAC, a política verifica input.user.tenant_id == input.resource.tenant_id — um único papel analyst com uma condição de atributo.

RBAC → ReBAC: RBAC falha quando o acesso segue hierarquia de containment entre objetos. Exemplo: Google Drive — "o usuário tem acesso à pasta raiz do projeto, portanto tem acesso a todas as subpastas e documentos dentro". Com RBAC, modelar essa hierarquia recursiva requer JOINs ou código procedural complexo. Com ReBAC, uma tupla folder:root#viewer@user:alice e permissões transitivas no schema resolvem automaticamente o acesso a todos os descendentes.

Como funciona o Google Zanzibar e o que o diferencia fundamentalmente de RBAC?

Zanzibar armazena relacionamentos como tuplas (objeto, relação, sujeito) em um banco distribuído globalmente. Uma query de autorização — "pode user:alice editar document:123?" — é resolvida expandindo recursivamente o grafo de relacionamentos: document:123#editor pode incluir group:g#member, que inclui user:alice indiretamente. O sistema garante causalidade (usando "zookies" — tokens de consistência) para evitar que uma remoção de permissão não seja visível imediatamente após ser aplicada.

A diferença fundamental de RBAC é que Zanzibar não pressupõe um conjunto fixo de papéis organizacionais — as relações são arbitrárias entre qualquer tipo de objeto. Em RBAC, a unidade de autorização é o papel do usuário; em Zanzibar, é o relacionamento entre quaisquer dois objetos do sistema. Isso permite hierarquias arbitrárias de containment e delegação direta (Alice delega acesso a Bob em um documento específico) sem precisar de papéis intermediários. O custo é a necessidade de um sistema de armazenamento e processamento de grafos especializado — não é uma query SQL simples.

O que é role explosion no RBAC, como detectar que está ocorrendo, e quais estratégias de mitigação existem?

Role explosion ocorre quando o número de papéis cresce não como abstração organizacional, mas como combinação de permissões únicas por instância de recurso. Sintomas: papéis com nomes como editor_projeto_alpha, admin_tenant_xyz, ou viewer_branch_123; número de papéis crescendo proporcionalmente ao número de recursos; gestão manual de atribuição de papéis com erros frequentes.

Mitigações: (1) RBAC-H (hierárquico) — consolidar papéis que diferem apenas por um nível de permissão em hierarquia pai-filho. Reduz duplicação, não elimina o problema de recursos. (2) ABAC para atributos de contexto — quando papéis diferenciam por atributo do recurso (tenant, projeto, classificação), migrar para política ABAC que verifica o atributo no input. Um único papel + condição substitui N papéis. (3) ReBAC para hierarquias — quando papéis diferenciam por hierarquia de containment, migrar para tuplas de relacionamento. Cada atribuição vira uma tupla direta usuário→recurso, eliminando a classe de papéis intermediários.

Qual a diferença entre PDP e PEP em autorização? Quando externalizar o PDP é justificável vs over-engineering?

Policy Decision Point (PDP) é onde a decisão "pode ou não pode" é computada. Policy Enforcement Point (PEP) é onde essa decisão é aplicada — o middleware que bloqueia ou permite a requisição. Em sistemas simples, ambos estão no mesmo processo: o middleware lê o papel do JWT e decide inline. Em sistemas maiores, o PDP é externalizado (OPA, SpiceDB) e o PEP chama o PDP via gRPC/HTTP e aplica o resultado.

Externalizar é justificável quando: múltiplos serviços compartilham as mesmas políticas de autorização (evita duplicação e inconsistência); times de segurança precisam atualizar políticas sem redeploy do serviço de negócio; políticas são suficientemente complexas para requerer testes isolados com cobertura; compliance exige auditabilidade centralizada das decisões de autorização.

É over-engineering quando: há um único serviço com regras de autorização simples; a latência adicional (mesmo sidecar) é inaceitável para o SLA; o time não tem capacidade para operar mais um componente em produção. Um monolito com RBAC inline e testes de autorização adequados é preferível a um PDP externo mal operado.

Como auditar "quem tem acesso ao recurso X" em RBAC vs ReBAC? Por que isso importa para compliance?

Em RBAC: a query de auditoria é relativamente simples — "quais papéis têm a permissão P no recurso R? Quais usuários têm esses papéis?" São dois JOINs em SQL. A resposta é determinística e independente do contexto. Auditorias de compliance (SOC 2, ISO 27001) podem ser geradas com queries diretas ao banco de dados de autorização.

Em ReBAC: a query equivalente — "quem tem acesso a document:123?" — requer expandir o grafo de relacionamentos inteiro: viewers diretos, membros de grupos com acesso, usuários com acesso transitivo via pasta pai, usuários com acesso via workspace. SpiceDB tem uma operação Expand para isso, mas é computacionalmente cara em hierarquias profundas. A auditoria em tempo real pode ser lenta.

Para compliance, isso importa porque regulamentações como GDPR, SOC 2, e LGPD podem exigir prova de que o acesso a dados pessoais é restrito corretamente. Em RBAC, a prova é uma query SQL. Em ReBAC, a prova requer uma operação de expansão do grafo — mais complexa de automatizar e potencialmente mais lenta. Sistemas com requisito forte de auditoria frequentemente combinam ReBAC para autorização operacional com uma projeção RBAC-like mantida sincronizada para auditoria.

Referências para aprofundar

  1. paper Zanzibar: Google's Consistent, Global Authorization System — Warfield et al. (USENIX ATC 2019). O paper que descreve o sistema Zanzibar em produção no Google — arquitetura, modelo de dados de tuplas, e as garantias de consistência. Gratuito em usenix.org. Leitura fundamental para entender ReBAC em escala.
  2. docs SpiceDB Documentation — Authzed. authzed.com/docs. A documentação da implementação open source de Zanzibar mais madura. Inclui tutoriais de schema, exemplos de sistemas reais (Google Drive, GitHub), e guias de integração com Go, Python, e Node.js.
  3. docs Open Policy Agent (OPA) — Documentação Oficial. openpolicyagent.org/docs. Documentação completa do OPA e Rego — tutoriais, referência da linguagem, e guias de integração. O playground online (play.openpolicyagent.org) permite testar políticas sem instalação.
  4. paper Role-Based Access Control (RBAC) — NIST SP 800-192 — Ferraiolo, Kuhn e Chandramouli. A especificação formal do RBAC pelo NIST. Define RBAC0 (básico), RBAC1 (hierárquico), RBAC2 (com restrições), e RBAC3 (combinado). Disponível em nvlpubs.nist.gov. Útil como referência normativa.
  5. article ABAC and NIST SP 800-162 — NIST (2014). A guia do NIST para ABAC — define os componentes, o modelo de política, e os casos de uso. nvlpubs.nist.gov/nistpubs/specialpublications/NIST.SP.800-162.pdf. Referência normativa para compliance.
  6. article Implementing Fine-Grained Authorization — Auth0 Blog. Comparação prática entre RBAC, ABAC e ReBAC com exemplos de código e critérios de decisão. Inclui exemplos de quando cada modelo falha e o que usar como alternativa. auth0.com/blog/fine-grained-authorization.
  7. docs OpenFGA — Open Fine Grained Authorization — CNCF. openfga.dev. Implementação open source de Zanzibar pela Okta, adotada pela CNCF. API compatível com SpiceDB mas com foco em integração com identity providers existentes. Alternativa a SpiceDB com mais integração com ecossistema Okta/Auth0.
  8. article OPA Integration Patterns — Styra Blog. blog.styra.com. Styra criou o OPA e publica artigos sobre padrões de integração — sidecar vs serviço centralizado, cache de decisões, bundle de políticas. Prático para decisões de arquitetura de autorização.
  9. vídeo Fine-Grained Authorization at Scale — Zanzibar and Beyond — Kunal Taneja (KubeCon 2023). Palestra sobre implementação de Zanzibar-compatible systems em Kubernetes com SpiceDB — arquitetura, performance, e lições aprendidas em produção. Disponível no YouTube canal CNCF.
  10. book Solving the Bottom Turtle — A SPIFFE Way to Establish Trust in Your Infrastructure — SPIFFE Project. Gratuito em spiffe.io/book. Cobre identidade e autorização de workload em sistemas distribuídos — complementa RBAC/ABAC/ReBAC no contexto de autorização serviço-a-serviço (não apenas usuário-para-recurso).
  11. article The Two Pillars of Authorization — Justin Richer (jricher.org). Análise da distinção entre authorization (o que você pode fazer) e authentication (quem você é) com implicações práticas para design de sistemas. Complementa a separação conceitual do conceito anterior.
  12. book API Security in Action — Neil Madden (Manning, 2020). Capítulos 8-9 cobrem RBAC e ABAC para APIs REST com exemplos práticos em Java. Discute as limitações de cada modelo e quando combinar abordagens. Os exemplos são adaptáveis a qualquer linguagem.