# ADR-010: Cedar Policy Engine para Authorization **Status**: Accepted | Implemented **Date**: 2024-11-01 **Deciders**: Security Architecture Team **Technical Story**: Implementing declarative RBAC with audit-friendly policies --- ## Decision Usar **Cedar policy engine** para autorización declarativa (no custom RBAC, no Casbin). --- ## Rationale 1. **Declarative Policies**: Separar políticas de autorización de lógica de código 2. **Auditable**: Políticas versionables en Git, fácil de revisar 3. **AWS Proven**: Usado internamente en AWS, production-proven 4. **Type Safe**: Schemas para resources y principals 5. **No Vendor Lock-in**: Open source, portable --- ## Alternatives Considered ### ❌ Custom RBAC Implementation - **Pros**: Full control - **Cons**: Mantenimiento pesada, fácil de introducir vulnerabilidades ### ❌ Casbin (Policy Engine) - **Pros**: Flexible - **Cons**: Menos maduro en Rust ecosystem que Cedar ### ✅ Cedar (CHOSEN) - Declarative, auditable, production-proven, AWS-backed --- ## Trade-offs **Pros**: - ✅ Declarative policies separate from code - ✅ Easy to audit and version control - ✅ Type-safe schema validation - ✅ AWS production-proven - ✅ Support for complex hierarchies (teams, orgs) **Cons**: - ⚠️ Learning curve (new policy language) - ⚠️ Policies must be pre-compiled for performance - ⚠️ Smaller community than Casbin --- ## Implementation **Policy Definition**: ```cedar // policies/authorization.cedar // Allow owners full access to projects permit( principal, action, resource ) when { principal.role == "owner" }; // Allow members to create tasks permit( principal in [User], action == Action::"create_task", resource in [Project] ) when { principal.team_id == resource.team_id && principal.role in ["owner", "member"] }; // Deny editing completed tasks forbid( principal, action == Action::"update_task", resource in [Task] ) when { resource.status == "done" }; // Allow viewing with viewer role permit( principal, action == Action::"read", resource ) when { principal.role == "viewer" }; ``` **Authorization Check in Backend**: ```rust // crates/vapora-backend/src/api/projects.rs use cedar_policy::{Authorizer, Request, Entity, Entities}; async fn get_project( State(app_state): State, Path(project_id): Path, ) -> Result, ApiError> { let user = get_current_user()?; // Create authorization request let request = Request::new( user.into_entity(), action("read"), resource("project", &project_id), None, )?; // Load policies and entities let policies = app_state.cedar_policies(); let entities = app_state.cedar_entities(); // Authorize let authorizer = Authorizer::new(); let response = authorizer.is_authorized(&request, &policies, &entities)?; match response.decision { Decision::Allow => { let project = app_state .project_service .get_project(&user.tenant_id, &project_id) .await?; Ok(Json(project)) } Decision::Deny => Err(ApiError::Forbidden), } } ``` **Entity Schema**: ```rust // crates/vapora-backend/src/auth/entities.rs pub struct User { pub id: String, pub role: UserRole, pub tenant_id: String, } pub struct Project { pub id: String, pub tenant_id: String, pub status: ProjectStatus, } // Convert to Cedar entities impl From for cedar_policy::Entity { fn from(user: User) -> Self { // Serialized to Cedar format } } ``` **Key Files**: - `/crates/vapora-backend/src/auth/` (Cedar integration) - `/crates/vapora-backend/src/api/` (authorization checks) - `/policies/authorization.cedar` (policy definitions) --- ## Verification ```bash # Validate policy syntax cedar validate --schema schemas/schema.json --policies policies/authorization.cedar # Test authorization decision cedar evaluate \ --schema schemas/schema.json \ --policies policies/authorization.cedar \ --entities entities.json \ --request '{"principal": "User:alice", "action": "Action::read", "resource": "Project:123"}' # Run authorization tests cargo test -p vapora-backend test_cedar_authorization # Test edge cases cargo test -p vapora-backend test_forbidden_access cargo test -p vapora-backend test_hierarchical_permissions ``` **Expected Output**: - Policies validate without syntax errors - Owners have full access - Members can create tasks in their team - Viewers can only read - Completed tasks cannot be edited - All tests pass --- ## Consequences ### Authorization Model - Three roles: Owner, Member, Viewer - Hierarchical teams (can nest permissions) - Resource-scoped access (per project, per task) - Audit trail of policy decisions ### Policy Management - Policies versioned in Git - Policy changes require code review - Centralized policy repository - No runtime policy compilation (pre-compiled) ### Performance - Policy evaluation cached (policies don't change often) - Entity resolution cached per request - Negligible latency overhead (<1ms) ### Scaling - Policies apply across all services - Cedar policies portable to other services - Centralized policy management --- ## References - [Cedar Policy Language Documentation](https://docs.cedarpolicy.com/) - [Cedar GitHub Repository](https://github.com/aws/cedar) - `/policies/authorization.cedar` (policy definitions) - `/crates/vapora-backend/src/auth/` (integration code) --- **Related ADRs**: ADR-009 (Istio), ADR-025 (Multi-Tenancy)