From 45df4d0d9b577fecee798d672695fe24ff57fb1b Mon Sep 17 00:00:00 2001 From: mo khan Date: Tue, 15 Jul 2025 16:37:08 -0600 Subject: feat: migrate from Cedar to SpiceDB authorization system This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema. --- src/authorization/cedar_authorizer.rs | 183 ---------------------------------- 1 file changed, 183 deletions(-) delete mode 100644 src/authorization/cedar_authorizer.rs (limited to 'src/authorization/cedar_authorizer.rs') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs deleted file mode 100644 index 0d30ee77..00000000 --- a/src/authorization/cedar_authorizer.rs +++ /dev/null @@ -1,183 +0,0 @@ -use super::authorizer::Authorizer; -use std::fs; -use std::str::FromStr; - -#[derive(Debug)] -pub struct CedarAuthorizer { - authorizer: cedar_policy::Authorizer, - entities: cedar_policy::Entities, - policies: cedar_policy::PolicySet, -} - -impl CedarAuthorizer { - pub fn new( - policies: cedar_policy::PolicySet, - entities: cedar_policy::Entities, - ) -> CedarAuthorizer { - CedarAuthorizer { - policies, - entities, - authorizer: cedar_policy::Authorizer::new(), - } - } - - pub fn new_from(path: &std::path::Path, entities: cedar_policy::Entities) -> CedarAuthorizer { - Self::new( - Self::load_from(path).unwrap_or_else(|e| { - tracing::error!( - path = ?path, - error = %e, - "Failed to load Cedar policies, using empty policy set" - ); - cedar_policy::PolicySet::default() - }), - entities, - ) - } - - fn load_from( - path: &std::path::Path, - ) -> Result> { - if !path.exists() { - return Ok(cedar_policy::PolicySet::default()); - } - - if path.is_file() && path.extension().is_some_and(|ext| ext == "cedar") { - let content = fs::read_to_string(path)?; - return Ok(cedar_policy::PolicySet::from_str(&content)?); - } - - if !path.is_dir() { - return Ok(cedar_policy::PolicySet::default()); - } - - let mut policies = cedar_policy::PolicySet::new(); - for entry in fs::read_dir(path)? { - policies.merge(&Self::load_from(&entry?.path())?, true)?; - } - Ok(policies) - } - - fn map_from( - &self, - http_request: envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest, - ) -> Result> { - let principal = self.principal_from(&http_request)?; - let permission = self.permission_from(&http_request)?; - let resource = self.resource_from(&http_request)?; - let context = self.context_from(http_request)?; - - Ok(cedar_policy::Request::new( - principal, permission, resource, context, None, - )?) - } - - fn principal_from( - &self, - http_request: &envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest, - ) -> Result> { - let subject = http_request - .headers - .get("x-jwt-claim-sub") - .map_or("", |v| v); - - Ok(cedar_policy::EntityUid::from_type_name_and_id( - cedar_policy::EntityTypeName::from_str("User")?, - cedar_policy::EntityId::from_str(subject)?, - )) - } - - fn permission_from( - &self, - http_request: &envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest, - ) -> Result> { - Ok(cedar_policy::EntityUid::from_type_name_and_id( - cedar_policy::EntityTypeName::from_str("Action")?, - cedar_policy::EntityId::from_str(&http_request.method)?, - )) - } - - fn resource_from( - &self, - http_request: &envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest, - ) -> Result> { - Ok(cedar_policy::EntityUid::from_type_name_and_id( - cedar_policy::EntityTypeName::from_str("Resource")?, - cedar_policy::EntityId::from_str(&http_request.path)?, - )) - } - - fn context_from( - &self, - http_request: envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest, - ) -> Result> { - let mut items = std::collections::HashMap::new(); - - items.insert("host".to_string(), self.safe_string(&http_request.host)); - items.insert("method".to_string(), self.safe_string(&http_request.method)); - items.insert("path".to_string(), self.safe_string(&http_request.path)); - - Ok(cedar_policy::Context::from_pairs( - items.into_iter().collect::>(), - )?) - } - - fn safe_string(&self, item: &str) -> cedar_policy::RestrictedExpression { - cedar_policy::RestrictedExpression::new_string(item.to_string()) - } -} - -impl Default for CedarAuthorizer { - fn default() -> Self { - Self::new_from( - std::path::Path::new("./etc/authzd"), - cedar_policy::Entities::empty(), - ) - } -} - -impl Authorizer for CedarAuthorizer { - fn authorize(&self, request: envoy_types::ext_authz::v3::pb::CheckRequest) -> bool { - let http_request = match request - .attributes - .as_ref() - .and_then(|attr| attr.request.as_ref()) - .and_then(|req| req.http.as_ref()) - { - Some(http) => http, - None => return false, - }; - - match self.map_from(http_request.clone()) { - Ok(cedar_request) => { - let response = - self.authorizer - .is_authorized(&cedar_request, &self.policies, &self.entities); - - let decision = response.decision(); - - tracing::info!( - decision = ?decision, - diagnostics = ?response.diagnostics(), - principal = %cedar_request.principal().unwrap(), - action = %cedar_request.action().unwrap(), - resource = %cedar_request.resource().unwrap(), - host = %http_request.host, - method = %http_request.method, - path = %http_request.path, - "http" - ); - - matches!(decision, cedar_policy::Decision::Allow) - } - Err(e) => { - tracing::error!( - error = %e, - path = %http_request.path, - "Failed to create Cedar request" - ); - false - } - } - } -} -- cgit v1.2.3