Skip to main content

chronix_security/authz/
mod.rs

1//! # Chronix Authz — Cedar-based Authorization
2//!
3//! Fine-grained authorization for the Chronix time-series database using
4//! the [Cedar](https://www.cedarpolicy.com/) policy language (formally
5//! verified, pure Rust).
6//!
7//! ## Architecture
8//!
9//! ```text
10//! Request → AuthMiddleware → AuthContext
11//!                                │
12//!                                ▼
13//!                         AuthzEngine (Cedar)
14//!                            ├── PolicySet (hot-reloadable)
15//!                            ├── Entities (principal, resource, roles)
16//!                            └── Decision: Allow | Deny { reasons }
17//! ```
18//!
19//! ## Policy Model
20//!
21//! - **Principals:** `Chronix::User`, with role membership via `Chronix::Role`
22//! - **Resources:** `Chronix::Namespace` for data, `Chronix::System` for
23//!   administration — the two things `chronixd` asks about, and nothing else
24//! - **Actions:** `Read`, `Write`, `Delete` on a namespace; the capabilities
25//!   in the `Admin` group on the system
26//!
27//! The model is compiled in as a Cedar schema ([`engine::SCHEMA_SRC`])
28//! and **every policy is validated against it**, so a rule naming something
29//! this server never asks about is refused at load rather than accepted and
30//! never consulted.
31//!
32//! ## Default-Deny
33//!
34//! If no policy explicitly permits a request, it is denied. Use `forbid`
35//! policies to create hard denials that override permissive policies.
36//!
37//! ## Example
38//!
39//! ```
40//! use chronix_security::authz::{
41//!     AuthzEngine, ChronixAction, ChronixNamespace, ChronixPrincipal,
42//! };
43//!
44//! let engine = AuthzEngine::new();
45//! engine.load_policies(r#"
46//!     permit(
47//!         principal in Chronix::Role::"operator",
48//!         action in [Chronix::Action::"Read", Chronix::Action::"Write"],
49//!         resource == Chronix::Namespace::"production"
50//!     );
51//! "#).unwrap();
52//!
53//! let operator = ChronixPrincipal::new("alice").with_role("operator");
54//! let production = ChronixNamespace::new("production");
55//! assert!(engine
56//!     .authorize_namespace(&operator, ChronixAction::Write, &production)
57//!     .is_allowed());
58//! assert!(engine
59//!     .authorize_namespace(&operator, ChronixAction::Delete, &production)
60//!     .is_denied());
61//! ```
62
63#![warn(missing_docs)]
64#![deny(unsafe_code)]
65
66mod engine;
67pub mod error;
68mod model;
69#[cfg(test)]
70mod perf;
71
72pub use engine::{AuthzEngine, SCHEMA_SRC, schema_action_names};
73pub use error::AuthzError;
74pub use model::{ChronixAction, ChronixNamespace, ChronixPrincipal, ChronixSystem, Decision};