pub struct AuthzEngine { /* private fields */ }Expand description
The Cedar-based authorization engine.
Thread-safe — can be shared across threads via Arc<AuthzEngine>.
§Policy Versioning & Rollback
The engine maintains an in-memory ring buffer of the last
MAX_POLICY_VERSIONS policy snapshots. Every mutating operation
(load_policies, add_policy, remove_policy) bumps the version
counter and pushes the previous state into the history before
swapping in the new set. Rollback to any retained version is
available via revert_to_version().
A dry-run mode (dryrun_load_policies())
parses and validates a policy string without modifying the active set.
§Cross-Tenant Isolation
There is no implicit “deny cross-tenant access” policy built into the engine. Tenant isolation is enforced at two layers:
- Namespace scoping — every request carries a namespace context
(see
ChronixNamespace). The storage and query layers filter by namespace before authorization is even checked. - Explicit Cedar policies — operators must deploy
forbidpolicies that deny access whenresource.namespace != principal.namespace. Seedocs/security.mdfor a reference policy template.
This explicit-policy approach avoids magic built-in rules that are invisible to policy auditors.
Implementations§
Source§impl AuthzEngine
impl AuthzEngine
Sourcepub const CROSS_TENANT_ISOLATION_POLICY: &'static str = r#"
forbid(
principal,
action,
resource
)
when {
resource has namespace &&
principal has namespace &&
resource.namespace != principal.namespace
}
unless {
principal in Chronix::Role::"admin"
};
"#
pub const CROSS_TENANT_ISOLATION_POLICY: &'static str = r#" forbid( principal, action, resource ) when { resource has namespace && principal has namespace && resource.namespace != principal.namespace } unless { principal in Chronix::Role::"admin" }; "#
Built-in Cedar policy that denies cross-tenant resource access.
Uses Cedar’s forbid with unless to deny any request where
the resource’s namespace does not match the principal’s namespace,
unless the principal has the admin role.
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new authorizer with the built-in cross-tenant isolation policy auto-loaded (default-deny + namespace isolation).
Schema validation is automatically enabled when a schema
is loaded via with_schema() or load_schema(). Without a
schema, policies are accepted without type-level validation.
Call .with_require_schema(true) to force a schema requirement.
Sourcepub fn with_policies(policies: PolicySet) -> Self
pub fn with_policies(policies: PolicySet) -> Self
Create an authorizer with the given policy set.
Sourcepub fn with_schema(self, schema: Schema) -> Self
pub fn with_schema(self, schema: Schema) -> Self
Set the Cedar schema for policy validation.
When a schema is set, load_policies() and add_policy() will
validate policies against it and reject those that reference
unknown entity types, actions, or attributes.
Setting a schema automatically enables require_schema,
which means all policies MUST validate against the schema.
Sourcepub fn load_schema(&mut self, schema_src: &str) -> Result<()>
pub fn load_schema(&mut self, schema_src: &str) -> Result<()>
Load a Cedar schema from its string representation.
Loading a schema automatically enables require_schema.
Sourcepub fn with_require_schema(self, require: bool) -> Self
pub fn with_require_schema(self, require: bool) -> Self
Require a Cedar schema for all policy operations.
When enabled, load_policies() and add_policy() will fail
if no schema has been loaded.
Sourcepub fn load_policies(&self, policy_src: &str) -> Result<usize>
pub fn load_policies(&self, policy_src: &str) -> Result<usize>
Load policies from a Cedar policy string.
Replaces all existing policies. If a schema is set, policies are validated against it before being accepted.
The previous policy set is pushed into the version history ring buffer before being replaced.
Sourcepub fn dryrun_load_policies(&self, policy_src: &str) -> Result<usize>
pub fn dryrun_load_policies(&self, policy_src: &str) -> Result<usize>
Dry-run policy loading: parse and validate without modifying the active policy set.
Returns the number of policies that would be loaded, or an error if parsing or schema validation fails. The active policy set is not modified.
Sourcepub fn add_policy(&self, id: &str, policy_src: &str) -> Result<()>
pub fn add_policy(&self, id: &str, policy_src: &str) -> Result<()>
Add a single policy from source.
Uses a clone-and-swap strategy: clones the current policy set under a brief read lock, builds and validates the candidate set without holding any lock, and only acquires a write lock for the final atomic swap. If parsing or validation fails, the current set is left untouched (automatic rollback).
Sourcepub fn remove_policy(&self, id: &str) -> bool
pub fn remove_policy(&self, id: &str) -> bool
Remove a policy by ID.
Returns true if the policy was found and removed.
Sourcepub fn current_version(&self) -> u64
pub fn current_version(&self) -> u64
Return the current policy version number.
Sourcepub fn policy_versions(&self) -> Vec<PolicyVersion>
pub fn policy_versions(&self) -> Vec<PolicyVersion>
List all retained policy versions (oldest first).
Sourcepub fn revert_to_version(&self, version: u64) -> Result<()>
pub fn revert_to_version(&self, version: u64) -> Result<()>
Revert the active policy set to a previously retained version .
The version must exist in the history ring buffer. On success the reverted-to snapshot becomes the active set and the pre-revert state is pushed into history (so it can itself be rolled back).
Sourcepub fn load_policies_from_dir(&self, dir: &Path) -> Result<usize>
pub fn load_policies_from_dir(&self, dir: &Path) -> Result<usize>
Load policies from all .cedar files in a directory.
Evaluate an authorization request.
Returns Decision::Allow if any policy explicitly permits the request,
or Decision::Deny with reasons otherwise (default-deny).
Evaluate a granular admin action, falling back to the Admin
super-action if the specific action is denied.
Policies that grant Action::"Admin" automatically cover
all granular admin actions (ManageNodes, ManageKeys, etc.).
This avoids breaking existing policies while enabling least-privilege
grants for new deployments.
Evaluate an authorization request against a namespace resource.
This is used for namespace-level policies, e.g.:
permit(
principal in Chronix::Role::"ns_admin",
action,
resource == Chronix::Namespace::"production"
);Sourcepub fn policy_count(&self) -> usize
pub fn policy_count(&self) -> usize
Returns the number of active policies.
Sourcepub fn policy_ids(&self) -> Vec<String>
pub fn policy_ids(&self) -> Vec<String>
List all policy IDs.
Sourcepub fn load_cross_tenant_isolation_policy(&self) -> Result<()>
pub fn load_cross_tenant_isolation_policy(&self) -> Result<()>
**** Load the default cross-tenant isolation policy.
This policy forbids any principal from accessing resources in a
namespace that differs from the principal’s own namespace attribute.
Without this, data is visible across tenants unless explicit Cedar
forbid policies are deployed.
The policy is idempotent — calling this multiple times is safe (the existing built-in policy is removed before re-adding).
Sourcepub fn warn_if_no_namespace_policies(&self)
pub fn warn_if_no_namespace_policies(&self)
**** Check if any namespace-scoped policies are loaded.
Logs a warning if no policies reference Chronix::Namespace,
which likely means cross-tenant isolation is not enforced.
Trait Implementations§
Source§impl Debug for AuthzEngine
impl Debug for AuthzEngine
Auto Trait Implementations§
impl !Freeze for AuthzEngine
impl !RefUnwindSafe for AuthzEngine
impl !UnwindSafe for AuthzEngine
impl Send for AuthzEngine
impl Sync for AuthzEngine
impl Unpin for AuthzEngine
impl UnsafeUnpin for AuthzEngine
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more