Controle de Acesso
Controle de acesso de nível empresarial para agentes de IA usando adk-auth.
Visão Geral
adk-auth fornece controle de acesso baseado em função (RBAC) com registro de auditoria e suporte a SSO para ADK agents. Ele permite controle seguro e granular sobre quais usuários podem acessar quais tools.
Arquitetura
┌─────────────────────────────────────────────────────────────────┐
│ Agent Request │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ SSO Token Validation │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Google │ │ Azure AD │ │ OIDC Discovery │ │
│ │ Provider │ │ Provider │ │ (Okta, Auth0, etc) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ JWKS Cache │ ← Auto-refresh keys │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼ TokenClaims
┌─────────────────────────────────────────────────────────────────┐
│ Claims Mapper │
│ │
│ IdP Groups → adk-auth Roles │
│ ───────────────────────────────────────── │
│ "AdminGroup" → "admin" │
│ "DataAnalysts" → "analyst" │
│ (default) → "viewer" │
└─────────────────────────────────────────────────────────────────┘
│
▼ Roles
┌─────────────────────────────────────────────────────────────────┐
│ Access Control │
│ │
│ Role: admin │
│ ├── allow: AllTools │
│ └── allow: AllAgents │
│ │
│ Role: analyst │
│ ├── allow: Tool("search") │
│ ├── allow: Tool("summarize") │
│ └── deny: Tool("code_exec") ← Deny takes precedence │
└─────────────────────────────────────────────────────────────────┘
│
▼ Check Result
┌─────────────────────────────────────────────────────────────────┐
│ Audit Logging │
│ │
│ {"user":"alice","resource":"search","outcome":"allowed"} │
│ {"user":"bob","resource":"exec","outcome":"denied"} │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Tool Execution │
│ (only if access granted) │
└─────────────────────────────────────────────────────────────────┘
Princípios de Design
1. Precedência de Negação
Quando uma função possui regras de permissão (allow) e negação (deny), a negação sempre prevalece:
let role = Role::new("limited")
.allow(Permission::AllTools) // Allow everything...
.deny(Permission::Tool("admin")); // ...except admin
// Result: Can access any tool EXCEPT "admin"
2. União de Múltiplas Funções
Usuários com múltiplas funções obtêm a união das permissões, mas as regras de negação de qualquer função ainda se aplicam:
let ac = AccessControl::builder()
.role(reader) // allow: search
.role(writer) // allow: write
.assign("alice", "reader")
.assign("alice", "writer")
.build()?;
// Alice can access both "search" AND "write"
3. Explícito Sobre Implícito
As permissões são explícitas - nenhum acesso é concedido por padrão:
let role = Role::new("empty");
// This role grants NO permissions
ac.check("user", &Permission::Tool("anything")); // → Denied
4. Separação de Autenticação e Autorização
- Autenticação (SSO): Verifica QUEM é o usuário (via JWT)
- Autorização (RBAC): Determina O QUE eles podem acessar
// Authentication: validate JWT, extract claims
let claims = provider.validate(token).await?;
// Authorization: check specific permission
ac.check(&claims.sub, &Permission::Tool("search"))?;
// Combined: SsoAccessControl does both
sso.check_token(token, &permission).await?;
Instalação
[dependencies]
adk-auth = "0.2.0"
# For SSO/OAuth support
adk-auth = { version = "0.2.0", features = ["sso"] }
Componentes Principais
Permission
pub enum Permission {
Tool(String), // Ferramenta específica por nome
AllTools, // Coringa: todas as ferramentas
Agent(String), // Agent específico por nome
AllAgents, // Coringa: todos os agents
}
Role
let analyst = Role::new("analyst")
.allow(Permission::Tool("search".into()))
.allow(Permission::Tool("summarize".into()))
.deny(Permission::Tool("code_exec".into()));
AccessControl
let ac = AccessControl::builder()
.role(admin)
.role(analyst)
.assign("alice@company.com", "admin")
.assign("bob@company.com", "analyst")
.build()?;
// Verificar permissão
ac.check("bob@company.com", &Permission::Tool("search".into()))?;
ProtectedTool
Envolve uma ferramenta com verificação automática de permissões:
use adk_auth::ToolExt;
let protected = my_tool.with_access_control(Arc::new(ac));
// Quando executado, verifica a permissão antes de rodar
protected.execute(ctx, args).await?;
AuthMiddleware
Protege em lote múltiplas ferramentas:
let middleware = AuthMiddleware::new(ac);
let protected_tools = middleware.protect_all(tools);
Integração SSO
Provedores Suportados
| Provedor | Construtor | Emissor |
|---|---|---|
GoogleProvider::new(client_id) | accounts.google.com | |
| Azure AD | AzureADProvider::new(tenant, client) | login.microsoftonline.com |
| Okta | OktaProvider::new(domain, client) | {domain}/oauth2/default |
| Auth0 | Auth0Provider::new(domain, audience) | {domain}/ |
| Genérico | OidcProvider::from_discovery(issuer, client) | Qualquer provedor OIDC |
Declarações do Token
Declarações extraídas de JWTs validados:
pub struct TokenClaims {
pub sub: String, // Assunto (ID do usuário)
pub email: Option<String>, // E-mail
pub name: Option<String>, // Nome de exibição
pub groups: Vec<String>, // Grupos IdP
pub roles: Vec<String>, // Funções IdP
pub hd: Option<String>, // Domínio hospedado do Google
pub tid: Option<String>, // ID do inquilino do Azure
// ... mais declarações OIDC padrão
}
Mapeador de Declarações
Mapeia grupos IdP para funções adk-auth:
let mapper = ClaimsMapper::builder()
.map_group("AdminGroup", "admin")
.map_group("Users", "viewer")
.default_role("guest")
.user_id_from_email()
.build();
Controle de Acesso SSO
Combina validação SSO com RBAC em uma única chamada:
let sso = SsoAccessControl::builder()
.validator(GoogleProvider::new("client-id"))
.mapper(mapper)
.access_control(ac)
.audit_sink(audit)
.build()?;
// Valida token + verifica permissão + log de auditoria
let claims = sso.check_token(token, &Permission::Tool("search".into())).await?;
Registro de Auditoria
Coletor de Auditoria de Arquivo
let audit = FileAuditSink::new("/var/log/adk/audit.jsonl")?;
let middleware = AuthMiddleware::with_audit(ac, audit);
Formato de Saída (JSONL)
{"timestamp":"2025-01-01T10:30:00Z","user":"bob","session_id":"sess-123","event_type":"tool_access","resource":"search","outcome":"allowed"}
{"timestamp":"2025-01-01T10:30:01Z","user":"bob","session_id":"sess-123","event_type":"tool_access","resource":"code_exec","outcome":"denied"}
Coletor de Auditoria Personalizado
use adk_auth::{AuditSink, AuditEvent, AuthError};
use async_trait::async_trait;
pub struct DatabaseAuditSink { /* ... */ }
#[async_trait]
impl AuditSink for DatabaseAuditSink {
async fn log(&self, event: AuditEvent) -> Result<(), AuthError> {
// Inserir no banco de dados
sqlx::query("INSERT INTO audit_log ...")
.bind(event.user)
.bind(event.resource)
.execute(&self.pool)
.await?;
Ok(())
}
}
Exemplos
# RBAC Essencial
cargo run --example auth_basic # Controle de acesso baseado em função
cargo run --example auth_audit # Registro de auditoria
# SSO (requer --features sso)
cargo run --example auth_sso --features sso # Fluxo SSO completo
cargo run --example auth_jwt --features sso # Validação de JWT
cargo run --example auth_oidc --features sso # Descoberta OIDC
cargo run --example auth_google --features sso # Identidade Google
Melhores Práticas de Segurança
| Prática | Descrição |
|---|---|
| Negar por padrão | Conceda apenas as permissões explicitamente necessárias |
| Negações explícitas | Adicione regras de negação para operações perigosas |
| Auditar tudo | Habilite o registro para conformidade |
| Validar no lado do servidor | Sempre valide JWTs no servidor |
| Usar HTTPS | Endpoints JWKS requerem conexões seguras |
| Rotacionar chaves | O cache JWKS atualiza automaticamente a cada hora |
| Limitar tempo de vida do token | Use tokens de acesso de curta duração |
Tratamento de Erros
use adk_auth::{AccessDenied, AuthError};
use adk_auth::sso::TokenError;
// Erros de RBAC
match ac.check("user", &Permission::Tool("admin".into())) {
Ok(()) => { /* acesso concedido */ }
Err(AccessDenied { user, permission }) => {
eprintln!("Acesso negado: {} não pode acessar {}", user, permission);
}
}
// Erros de SSO
match provider.validate(token).await {
Ok(claims) => { /* token válido */ }
Err(TokenError::Expired) => { /* token expirado */ }
Err(TokenError::InvalidSignature) => { /* assinatura inválida */ }
Err(TokenError::InvalidIssuer { expected, actual }) => { /* emissor errado */ }
Err(e) => { /* outro erro */ }
}
Anterior: ← Avaliação | Próximo: Diretrizes de Desenvolvimento →