Gerenciar quem pode fazer o quê em um sistema é uma das responsabilidades mais críticas e mais frequentemente negligenciadas da engenharia de software moderna. Identity and Access Management (IAM) avançado vai muito além de logins e senhas: trata-se de modelar políticas de acesso com precisão matemática, auditar cada operação privilegiada e garantir que nenhum usuário — humano ou máquina — acumule permissões além do necessário. Este artigo explora os modelos RBAC e ABAC, a disciplina de Privileged Access Management (PAM) e os fundamentos de uma governança de identidades robusta, com implementações práticas em Python.
O Problema de Autorização em Sistemas Modernos
Autenticação e autorização são frequentemente confundidas. Autenticação responde à pergunta "quem é você?" — é o processo de verificar identidade via senha, token ou certificado. Autorização responde "o que você pode fazer?" — é o processo de verificar se uma identidade verificada tem permissão para executar determinada operação sobre determinado recurso.
Em sistemas pequenos, autorização pode ser implementada com checagens simples como if user.role == "admin". À medida que o sistema cresce, essa abordagem torna-se insustentável: regras espalhadas pelo código, ausência de auditoria, impossibilidade de revisar políticas sem análise de código-fonte. É aqui que entram os modelos formais de controle de acesso.
O princípio fundamental que guia todo IAM moderno é o Princípio do Menor Privilégio (Least Privilege): cada entidade — usuário, serviço, processo — deve possuir apenas as permissões estritamente necessárias para executar suas funções, e nada mais. Violações desse princípio são a causa raiz de grande parte dos incidentes de segurança registrados atualmente.
Componentes de um Sistema IAM
| Componente | Função | Exemplo |
|---|---|---|
| Identity Provider (IdP) | Autentica usuários e emite tokens | Keycloak, Okta, Azure AD |
| Policy Engine | Avalia se uma requisição é autorizada | Open Policy Agent (OPA) |
| Directory Service | Armazena atributos de usuários e grupos | LDAP, Active Directory |
| Access Governance | Revisa e certifica permissões periodicamente | SailPoint, Saviynt |
| PAM Solution | Controla e audita acesso privilegiado | CyberArk, HashiCorp Vault |
| Audit Log | Registra toda ação para conformidade e investigação | SIEM, CloudTrail, Splunk |
RBAC: Role-Based Access Control
Role-Based Access Control (RBAC) é o modelo de controle de acesso mais amplamente adotado em sistemas corporativos. A ideia central é simples: permissões são atribuídas a papéis (roles), e usuários são atribuídos a papéis. Um usuário herda todas as permissões dos papéis que possui.
O modelo foi formalizado pelo NIST na publicação NIST RBAC Model (ANSI INCITS 359-2004) e define quatro componentes principais: usuários, papéis, permissões e sessões. Sessões representam a ativação de um subconjunto dos papéis de um usuário — um usuário pode possuir o papel de administrador mas não ativá-lo em sessões cotidianas, reduzindo o risco de uso acidental.
Hierarquia de Papéis
RBAC suporta hierarquia: um papel pode herdar permissões de papéis abaixo dele na hierarquia. Um papel ENGENHEIRO_SENIOR pode herdar tudo de ENGENHEIRO e ESTAGIARIO. Isso elimina a duplicação de definições de permissão.
┌─────────────────────────────────────────────────┐
│ Hierarquia RBAC │
│ │
│ ┌──────────────┐ │
│ │ ADMIN │ ← todas as perms │
│ └──────┬───────┘ │
│ │ herda │
│ ┌─────────┴────────┐ │
│ │ ENGENHEIRO │ │
│ │ _SENIOR │ │
│ └─────────┬────────┘ │
│ │ herda │
│ ┌─────────┴────────┐ │
│ │ ENGENHEIRO │ │
│ └─────────┬────────┘ │
│ │ herda │
│ ┌─────────┴────────┐ │
│ │ ESTAGIARIO │ ← perms mínimas │
│ └──────────────────┘ │
└─────────────────────────────────────────────────┘
Implementação de RBAC em Python
A seguir, uma implementação completa de um sistema RBAC com suporte a hierarquia de papéis, separação de funções (Separation of Duties — SoD) e auditoria de decisões:
from dataclasses import dataclass, field
from typing import Set, Dict, Optional
from datetime import datetime
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s [RBAC] %(message)s')
logger = logging.getLogger(__name__)
@dataclass
class Permission:
resource: str # ex: "relatorio_financeiro"
action: str # ex: "read", "write", "delete"
def __hash__(self):
return hash((self.resource, self.action))
def __eq__(self, other):
return self.resource == other.resource and self.action == other.action
def __repr__(self):
return f"{self.action}:{self.resource}"
@dataclass
class Role:
name: str
permissions: Set[Permission] = field(default_factory=set)
parent_roles: Set[str] = field(default_factory=set) # hierarquia
def add_permission(self, resource: str, action: str):
self.permissions.add(Permission(resource, action))
class RBACEngine:
def __init__(self):
self._roles: Dict[str, Role] = {}
self._user_roles: Dict[str, Set[str]] = {}
# Regras de Separation of Duties: papéis mutuamente exclusivos
self._sod_rules: list[tuple[str, str]] = []
# ── Gerenciamento de papéis ──────────────────
def define_role(self, role: Role):
self._roles[role.name] = role
logger.info(f"Papel definido: {role.name} | {len(role.permissions)} permissões")
def add_sod_rule(self, role_a: str, role_b: str):
"""Impede que um usuário possua os dois papéis simultaneamente."""
self._sod_rules.append((role_a, role_b))
# ── Atribuição de papéis ─────────────────────
def assign_role(self, user_id: str, role_name: str) -> bool:
if role_name not in self._roles:
logger.error(f"Papel '{role_name}' não existe.")
return False
current_roles = self._user_roles.get(user_id, set())
# Verificar SoD antes de atribuir
for role_a, role_b in self._sod_rules:
conflicting = (role_name == role_a and role_b in current_roles) or \
(role_name == role_b and role_a in current_roles)
if conflicting:
logger.warning(
f"SoD violado: '{user_id}' não pode ter '{role_a}' e '{role_b}' juntos."
)
return False
if user_id not in self._user_roles:
self._user_roles[user_id] = set()
self._user_roles[user_id].add(role_name)
logger.info(f"Papel '{role_name}' atribuído a '{user_id}'.")
return True
# ── Resolução de permissões com herança ──────
def _resolve_permissions(self, role_name: str, visited: Optional[Set[str]] = None) -> Set[Permission]:
if visited is None:
visited = set()
if role_name in visited:
return set()
visited.add(role_name)
role = self._roles.get(role_name)
if not role:
return set()
perms = set(role.permissions)
for parent_name in role.parent_roles:
perms |= self._resolve_permissions(parent_name, visited)
return perms
def get_effective_permissions(self, user_id: str) -> Set[Permission]:
roles = self._user_roles.get(user_id, set())
perms: Set[Permission] = set()
for role_name in roles:
perms |= self._resolve_permissions(role_name)
return perms
# ── Verificação de acesso ────────────────────
def is_authorized(self, user_id: str, resource: str, action: str) -> bool:
required = Permission(resource, action)
effective = self.get_effective_permissions(user_id)
result = required in effective
logger.info(
f"[{'PERMITIDO' if result else 'NEGADO'}] "
f"user={user_id} | {action}:{resource}"
)
return result
# ── Exemplo de uso ───────────────────────────────────────────────────────────
def demonstrar_rbac():
engine = RBACEngine()
# Definir papéis com hierarquia
estagiario = Role("ESTAGIARIO")
estagiario.add_permission("relatorio_basico", "read")
engenheiro = Role("ENGENHEIRO", parent_roles={"ESTAGIARIO"})
engenheiro.add_permission("codigo_fonte", "read")
engenheiro.add_permission("codigo_fonte", "write")
engenheiro.add_permission("pipeline_ci", "execute")
engenheiro_senior = Role("ENGENHEIRO_SENIOR", parent_roles={"ENGENHEIRO"})
engenheiro_senior.add_permission("infraestrutura", "read")
engenheiro_senior.add_permission("credenciais_prod", "read")
admin = Role("ADMIN", parent_roles={"ENGENHEIRO_SENIOR"})
admin.add_permission("usuarios", "write")
admin.add_permission("usuarios", "delete")
admin.add_permission("auditoria", "read")
# Papel financeiro — sujeito a SoD
financeiro = Role("FINANCEIRO")
financeiro.add_permission("folha_pagamento", "write")
financeiro.add_permission("relatorio_financeiro", "read")
aprovador = Role("APROVADOR_FINANCEIRO")
aprovador.add_permission("folha_pagamento", "approve")
for r in [estagiario, engenheiro, engenheiro_senior, admin, financeiro, aprovador]:
engine.define_role(r)
# SoD: quem lança folha não pode aprovar folha
engine.add_sod_rule("FINANCEIRO", "APROVADOR_FINANCEIRO")
# Atribuir papéis
engine.assign_role("alice", "ENGENHEIRO_SENIOR")
engine.assign_role("bob", "ESTAGIARIO")
engine.assign_role("carol", "ADMIN")
engine.assign_role("dave", "FINANCEIRO")
engine.assign_role("dave", "APROVADOR_FINANCEIRO") # SoD deve bloquear
print("\n=== Verificações de Acesso ===")
print(engine.is_authorized("alice", "codigo_fonte", "write")) # True
print(engine.is_authorized("alice", "credenciais_prod", "read")) # True
print(engine.is_authorized("alice", "usuarios", "delete")) # False
print(engine.is_authorized("bob", "relatorio_basico", "read")) # True
print(engine.is_authorized("bob", "codigo_fonte", "write")) # False
print(engine.is_authorized("carol", "usuarios", "delete")) # True
print(engine.is_authorized("dave", "folha_pagamento", "approve")) # False
demonstrar_rbac()
A saída esperada demonstra a hierarquia em funcionamento: Alice, como ENGENHEIRO_SENIOR, herda as permissões de ENGENHEIRO e ESTAGIARIO automaticamente, sem duplicação de definições. Dave tem o papel de APROVADOR_FINANCEIRO recusado pela regra de separação de funções, protegendo o processo financeiro contra fraude interna.
Limitações do RBAC
RBAC é poderoso, mas apresenta limitações conhecidas. O principal problema é a explosão de papéis (role explosion): em organizações grandes, o número de combinações contextuais cresce exponencialmente — "engenheiro do time A com acesso ao projeto X apenas em horário comercial" é difícil de expressar em um papel estático. Isso leva ao ABAC.
ABAC: Attribute-Based Access Control
Attribute-Based Access Control (ABAC) resolve a expressividade que falta ao RBAC ao permitir que políticas de acesso sejam expressas em termos de atributos — propriedades do sujeito, do recurso, da ação e do contexto ambiental. Uma política ABAC pode ser: "um médico pode ler prontuários de pacientes que são seus, durante horário de expediente, se acessar da rede hospitalar".
Os Quatro Tipos de Atributos
| Tipo | O que descreve | Exemplos |
|---|---|---|
| Sujeito | Quem está requisitando | departamento, cargo, localização, nível_clearance |
| Recurso | O que está sendo acessado | classificação, proprietário, projeto, sensibilidade |
| Ação | O que está sendo feito | read, write, delete, approve, export |
| Ambiente | Contexto da requisição | horário, IP, dispositivo, país, nível_risco |
Implementação de ABAC com Open Policy Agent (OPA)
O Open Policy Agent é o motor de políticas de fato no ecossistema cloud-native. Políticas são escritas em Rego, uma linguagem declarativa de consulta. O OPA é utilizado pelo Kubernetes, Istio, Terraform e diversas plataformas de API gateway.
A seguir, uma política ABAC em Rego que controla acesso a documentos financeiros com base em múltiplos atributos:
# policies/financeiro.rego
package financeiro.acesso
import future.keywords.if
import future.keywords.in
# Decisão padrão: negar
default allow := false
# Regra 1: Gerentes financeiros podem ler qualquer documento do próprio departamento
allow if {
input.subject.cargo == "gerente_financeiro"
input.subject.departamento == input.resource.departamento
input.action == "read"
}
# Regra 2: Analistas só podem ver documentos classificados como "interno" ou abaixo
allow if {
input.subject.cargo == "analista_financeiro"
input.resource.classificacao in ["publico", "interno"]
input.action == "read"
# Restrição de horário: apenas horário comercial (UTC-3)
time.hour(time.now_ns()) >= 8
time.hour(time.now_ns()) <= 18
}
# Regra 3: Exportação só é permitida de dispositivos gerenciados pela empresa
allow if {
input.action == "export"
input.subject.cargo in ["gerente_financeiro", "diretor"]
input.environment.dispositivo_gerenciado == true
input.environment.pais == "BR"
}
# Regra 4: Auditores externos podem apenas ler documentos em período de auditoria
allow if {
input.subject.tipo == "auditor_externo"
input.action == "read"
input.resource.classificacao in ["publico", "interno"]
input.environment.periodo_auditoria == true
}
Para integrar OPA em uma API Python com FastAPI:
import httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import time
app = FastAPI(title="API Financeira com ABAC via OPA")
OPA_URL = "http://localhost:8181/v1/data/financeiro/acesso/allow"
class OPAInput(BaseModel):
subject: dict
resource: dict
action: str
environment: dict
async def verificar_acesso(opa_input: OPAInput) -> bool:
"""Consulta o OPA para verificar se a requisição é autorizada."""
async with httpx.AsyncClient() as client:
try:
response = await client.post(
OPA_URL,
json={"input": opa_input.model_dump()},
timeout=2.0
)
response.raise_for_status()
result = response.json()
return result.get("result", False)
except httpx.TimeoutException:
# Falha segura: negar acesso se OPA não responder
return False
except Exception as e:
raise HTTPException(status_code=503, detail=f"Serviço de autorização indisponível: {e}")
@app.get("/documentos/{doc_id}")
async def obter_documento(
doc_id: str,
usuario_id: str = "usuario_demo",
cargo: str = "analista_financeiro"
):
recurso = {
"id": doc_id,
"classificacao": "interno",
"departamento": "financeiro",
"proprietario": "gerente_001"
}
opa_input = OPAInput(
subject={"id": usuario_id, "cargo": cargo, "departamento": "financeiro"},
resource=recurso,
action="read",
environment={
"ip": "10.0.1.50",
"dispositivo_gerenciado": True,
"pais": "BR",
"periodo_auditoria": False
}
)
autorizado = await verificar_acesso(opa_input)
if not autorizado:
raise HTTPException(status_code=403, detail=f"Acesso negado ao documento {doc_id}")
return {
"documento": doc_id,
"conteudo": "Dados financeiros confidenciais...",
"acessado_por": usuario_id,
"timestamp": time.time()
}
Boas Práticas OPA: O OPA deve ser executado como um sidecar junto ao serviço que o utiliza, e não como um serviço centralizado único. Isso evita que o OPA se torne ponto único de falha e reduz a latência das consultas. Em Kubernetes, isso é feito automaticamente via Admission Controller.
RBAC vs ABAC: Quando Usar Cada Um
| Critério | RBAC | ABAC |
|---|---|---|
| Complexidade de implementação | Baixa | Alta |
| Expressividade de políticas | Limitada | Muito alta |
| Performance | Excelente (lookup simples) | Variável (avaliação de política) |
| Número de papéis/políticas | Cresce com organização | Estável — política é reutilizável |
| Contexto ambiental | Não suportado | Nativo |
| Ideal para | SaaS, aplicações simples | Sistemas governamentais, bancários, saúde |
Na prática, a maioria dos sistemas modernos utiliza uma combinação: RBAC para granularidade grossa (o usuário é funcionário, gerente ou admin?) e ABAC para regras contextuais finas (em que horário, de qual dispositivo, acessando qual classificação de dado?).
PAM: Privileged Access Management
Acesso privilegiado é qualquer acesso que vai além do que um usuário comum possui — raiz de um servidor, credenciais de banco de dados de produção, chave de API de serviço crítico. Estudos da indústria apontam consistentemente que mais de 70% dos incidentes de segurança relevantes envolvem abuso de credenciais privilegiadas, seja por atores externos que as comprometem, seja por insiders maliciosos.
Privileged Access Management é a disciplina e o conjunto de controles que governam o ciclo de vida de credenciais e sessões privilegiadas.
Os Pilares do PAM
Um programa PAM maduro abrange quatro pilares interdependentes:
1. Cofre de Credenciais (Credential Vault): nenhuma credencial privilegiada deve existir em texto claro em arquivos de configuração, scripts, repositórios ou ambientes. Todas as credenciais são armazenadas em cofres criptografados com controle de acesso rigoroso.
2. Acesso Just-in-Time (JIT): em vez de conceder acesso privilegiado permanente, o acesso é provisionado apenas quando necessário e por um período limitado. Após o prazo, o acesso é revogado automaticamente e a credencial é rotacionada.
3. Gravação de Sessões: todas as sessões privilegiadas (SSH, RDP, banco de dados) são gravadas e indexadas. Em caso de incidente, é possível reproduzir exatamente o que foi feito.
4. Análise de Comportamento Privilegiado (PUBA): baselines de comportamento são estabelecidos e desvios são alertados automaticamente. Um DBA que nunca exportou dados mas começa a executar dumps noturnos é uma anomalia que deve acionar alerta.
Implementação de Cofre de Credenciais com HashiCorp Vault
HashiCorp Vault é a solução open-source de referência para gerenciamento de segredos. Ele fornece cofre dinâmico de credenciais, rotação automática, PKI dinâmico e muito mais:
# Instalar e iniciar o Vault em modo desenvolvimento (apenas para testes)
docker run -d \
--name vault \
-p 8200:8200 \
-e VAULT_DEV_ROOT_TOKEN_ID=root-token-dev \
hashicorp/vault:latest server -dev
# Configurar variáveis de ambiente
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='root-token-dev'
# Habilitar o motor de segredos KV v2
vault secrets enable -path=secretos kv-v2
# Armazenar credencial de banco de dados
vault kv put secretos/banco_producao \
host="db-prod.empresa.com" \
porta="5432" \
usuario="app_service" \
senha="S3nh@Mu1toC0mplexa!" \
banco="producao_db"
# Verificar
vault kv get secretos/banco_producao
Integração Python que consulta o Vault e jamais armazena credenciais em disco:
import hvac
import psycopg2
import os
import logging
from contextlib import contextmanager
logger = logging.getLogger(__name__)
class VaultCredentialManager:
"""Gerencia credenciais de banco de dados via HashiCorp Vault."""
def __init__(self, vault_addr: str, vault_token: str | None = None):
self.client = hvac.Client(url=vault_addr)
if vault_token:
self.client.token = vault_token
else:
# AppRole: mais seguro para serviços em produção
role_id = os.environ["VAULT_ROLE_ID"]
secret_id = os.environ["VAULT_SECRET_ID"]
response = self.client.auth.approle.login(role_id, secret_id)
self.client.token = response["auth"]["client_token"]
if not self.client.is_authenticated():
raise RuntimeError("Falha na autenticação com o Vault.")
logger.info("Autenticado no Vault com sucesso.")
def obter_credencial_bd(self, caminho: str) -> dict:
"""Obtém credenciais do banco a partir do Vault KV v2."""
try:
segredo = self.client.secrets.kv.v2.read_secret_version(
path=caminho, mount_point="secretos"
)
return segredo["data"]["data"]
except Exception as e:
logger.error(f"Falha ao obter credencial '{caminho}': {e}")
raise
@contextmanager
def conexao_banco(self, caminho_credencial: str):
"""Context manager que cria conexão com banco usando credenciais do Vault."""
creds = self.obter_credencial_bd(caminho_credencial)
conn = None
try:
conn = psycopg2.connect(
host=creds["host"],
port=int(creds["porta"]),
user=creds["usuario"],
password=creds["senha"],
dbname=creds["banco"]
)
logger.info("Conexão com banco de dados estabelecida.")
yield conn
finally:
if conn:
conn.close()
logger.info("Conexão com banco de dados encerrada.")
# ── Uso ──────────────────────────────────────────────────────────────────────
def executar_consulta_segura():
vault_mgr = VaultCredentialManager(
vault_addr=os.environ.get("VAULT_ADDR", "http://127.0.0.1:8200"),
vault_token=os.environ.get("VAULT_TOKEN")
)
with vault_mgr.conexao_banco("banco_producao") as conn:
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM usuarios WHERE ativo = TRUE;")
resultado = cursor.fetchone()
print(f"Usuários ativos: {resultado[0]}")
Credenciais Dinâmicas: o Próximo Nível
O Vault suporta credenciais dinâmicas de banco de dados: em vez de armazenar uma senha fixa, o Vault cria um usuário temporário no banco a cada requisição, com TTL configurável. Após o prazo, o usuário é automaticamente removido:
# Habilitar o motor de banco de dados
vault secrets enable database
# Configurar conexão com PostgreSQL
vault write database/config/producao \
plugin_name="postgresql-database-plugin" \
allowed_roles="app-role" \
connection_url="postgresql://{{username}}:{{password}}@db-prod:5432/producao_db" \
username="vault_admin" \
password="VaultAdminPass123!"
# Definir papel com TTL de 1 hora
vault write database/roles/app-role \
db_name="producao" \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="4h"
# Obter credencial dinâmica
vault read database/creds/app-role
# Key Value
# --- -----
# username v-token-app-role-AbCdEf123456
# password A1B2C3D4E5F6...
# lease_duration 1h
Atenção em Produção: Em produção, nunca utilize o modo
-devdo Vault. O modo dev desabilita TLS, armazena dados na memória e reinicia sem persistência. Utilize o modo servidor com backend de armazenamento (Consul, etcd ou S3) e TLS obrigatório.
Governança de Identidades
Governança de identidades é a camada de processo e controle que garante que as permissões atribuídas nos sistemas de IAM refletem, de fato, as necessidades legítimas do negócio — e que permissões acumuladas ao longo do tempo sejam regularmente revisadas e revogadas quando não mais necessárias.
O Problema do Acúmulo de Privilégios (Privilege Creep)
Privilege creep é um fenômeno universal: ao longo do tempo, funcionários mudam de área, assumem projetos temporários e acumulam permissões que nunca são removidas. Um analista que trabalhou temporariamente no time de infraestrutura pode continuar com acesso a servidores de produção por anos após retornar à função original.
O resultado é um ecossistema de permissões que diverge progressivamente do que foi planejado, criando superfície de ataque crescente. A governança endereça isso com três processos principais:
Certificação de Acesso (Access Certification): gestores revisam periodicamente (tipicamente trimestral) todas as permissões de seus subordinados e certificam que cada permissão ainda é necessária. Permissões não certificadas são revogadas automaticamente.
Provisionamento e Desprovisionamento Automatizados: quando um funcionário é admitido, transferido ou demitido, as permissões são ajustadas automaticamente com base no papel do diretório (Active Directory, LDAP). Nenhum processo manual é necessário — e nenhum esquecimento é possível.
Análise de Risco de Identidade: ferramentas de Identity Governance analisam continuamente o conjunto de permissões de cada identidade e calculam um score de risco. Identidades com combinações perigosas de permissões (lançar pagamentos e aprovar pagamentos) geram alertas para revisão imediata.
Implementação de Processo de Certificação de Acesso
from dataclasses import dataclass, field
from typing import Optional
from datetime import datetime, timedelta
from enum import Enum
import uuid
class StatusCertificacao(Enum):
PENDENTE = "pendente"
APROVADO = "aprovado"
REVOGADO = "revogado"
EXPIRADO = "expirado"
@dataclass
class ItemCertificacao:
id: str = field(default_factory=lambda: str(uuid.uuid4()))
usuario_id: str = ""
recurso: str = ""
papel: str = ""
concedido_em: datetime = field(default_factory=datetime.utcnow)
ultimo_uso: Optional[datetime] = None
gestor_responsavel: str = ""
status: StatusCertificacao = StatusCertificacao.PENDENTE
justificativa: str = ""
revisado_em: Optional[datetime] = None
revisado_por: Optional[str] = None
class CampanhaCertificacao:
"""Gerencia uma campanha de certificação de acesso."""
def __init__(self, nome: str, prazo_dias: int = 14):
self.id = str(uuid.uuid4())
self.nome = nome
self.criada_em = datetime.utcnow()
self.prazo = datetime.utcnow() + timedelta(days=prazo_dias)
self.itens: list[ItemCertificacao] = []
def adicionar_item(self, item: ItemCertificacao):
self.itens.append(item)
def certificar(self, item_id: str, gestor_id: str, aprovar: bool, justificativa: str = "") -> bool:
item = next((i for i in self.itens if i.id == item_id), None)
if not item:
return False
if item.gestor_responsavel != gestor_id:
print(f"ERRO: {gestor_id} não é responsável por este item.")
return False
if datetime.utcnow() > self.prazo:
item.status = StatusCertificacao.EXPIRADO
return False
item.status = StatusCertificacao.APROVADO if aprovar else StatusCertificacao.REVOGADO
item.revisado_em = datetime.utcnow()
item.revisado_por = gestor_id
item.justificativa = justificativa
acao = "APROVADO" if aprovar else "REVOGADO"
print(f"[{acao}] {item.usuario_id} | {item.papel} em {item.recurso} | por {gestor_id}")
return True
def encerrar_campanha(self) -> dict:
"""Encerra a campanha: itens ainda pendentes são revogados automaticamente."""
for item in self.itens:
if item.status == StatusCertificacao.PENDENTE:
item.status = StatusCertificacao.REVOGADO
item.justificativa = "Não revisado dentro do prazo — revogação automática"
print(f"[REVOGADO_AUTO] {item.usuario_id} | {item.papel} | prazo expirado")
aprovados = sum(1 for i in self.itens if i.status == StatusCertificacao.APROVADO)
revogados = sum(1 for i in self.itens if i.status == StatusCertificacao.REVOGADO)
relatorio = {
"campanha": self.nome,
"total_itens": len(self.itens),
"aprovados": aprovados,
"revogados": revogados,
"taxa_revogacao_pct": round(revogados / len(self.itens) * 100, 1) if self.itens else 0
}
print(f"\n=== Relatório Final: {self.nome} ===")
for k, v in relatorio.items():
print(f" {k}: {v}")
return relatorio
# ── Demonstração ──────────────────────────────────────────────────────────────
campanha = CampanhaCertificacao("Q1-2025 Revisão Acesso Produção", prazo_dias=14)
itens = [
ItemCertificacao(usuario_id="alice", recurso="servidores_prod", papel="SSH_ADMIN",
gestor_responsavel="carlos", ultimo_uso=datetime(2024, 11, 1)),
ItemCertificacao(usuario_id="bob", recurso="banco_producao", papel="DB_WRITE",
gestor_responsavel="carlos", ultimo_uso=datetime(2024, 6, 15)),
ItemCertificacao(usuario_id="dave", recurso="pipeline_deploy", papel="DEPLOY_PROD",
gestor_responsavel="carlos", ultimo_uso=None),
]
for item in itens:
campanha.adicionar_item(item)
campanha.certificar(itens[0].id, "carlos", aprovar=True, justificativa="Alice ainda gerencia infra produção")
campanha.certificar(itens[1].id, "carlos", aprovar=False, justificativa="Bob mudou de time em julho; acesso desnecessário")
# dave não é revisado — será revogado automaticamente
campanha.encerrar_campanha()
Métricas de Governança de Identidades
Uma governança eficaz deve produzir métricas rastreáveis ao longo do tempo, pois são elas que demonstram maturidade para auditores e para a liderança:
| Métrica | Descrição | Meta Saudável |
|---|---|---|
| Taxa de Orphan Accounts | % de contas sem usuário ativo associado | < 1% |
| Taxa de Conclusão de Certificação | % de itens revisados dentro do prazo | > 95% |
| Tempo Médio de Desprovisionamento | Tempo entre desligamento e revogação de acessos | < 4 horas |
| Permissões por Identidade (média) | Complexidade do modelo de acesso | Monitorar tendência |
| Violações SoD Detectadas | Conflitos de separação de funções ativos | 0 em produção |
| Cobertura de MFA | % de identidades com MFA habilitado | 100% para acesso privilegiado |
Zero Trust e IAM Moderno
Zero Trust não é um produto — é uma filosofia arquitetural que substitui o modelo "confiar na rede interna" por "verificar sempre, confiar nunca". No contexto de IAM, isso significa que nenhuma identidade — mesmo dentro do perímetro corporativo — recebe confiança implícita. Cada requisição é autenticada, autorizada e auditada.
Os princípios Zero Trust aplicados ao IAM são: verificar explicitamente a identidade em cada chamada (não apenas no login inicial); usar acesso de menor privilégio com escopos temporais; assumir que a violação já ocorreu e monitorar continuamente comportamentos anômalos.
Checklist IAM Zero Trust: MFA obrigatório para todos os acessos privilegiados · Credenciais rotacionadas automaticamente com TTL < 24h · Nenhuma credencial em variável de ambiente ou repositório git · Sessões privilegiadas gravadas e indexadas · Certificação de acesso trimestral com revogação automática de não revisados · Análise comportamental contínua (UEBA) · SoD validado automaticamente no provisionamento
Referências
-
NIST — Role-Based Access Control (ANSI INCITS 359-2004)
https://csrc.nist.gov/projects/role-based-access-control -
NIST SP 800-162 — Guide to Attribute Based Access Control (ABAC)
https://csrc.nist.gov/publications/detail/sp/800-162/final -
Open Policy Agent — Documentation
https://www.openpolicyagent.org/docs/latest/ -
HashiCorp Vault — Secrets Management
https://developer.hashicorp.com/vault/docs -
CyberArk — What is Privileged Access Management?
https://www.cyberark.com/what-is/privileged-access-management/ -
OWASP — Access Control Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html -
NIST SP 800-207 — Zero Trust Architecture
https://csrc.nist.gov/publications/detail/sp/800-207/final