| Crates.io | simple-zanzibar |
| lib.rs | simple-zanzibar |
| version | 0.1.0 |
| created_at | 2025-06-15 03:13:50.13212+00 |
| updated_at | 2025-06-15 03:13:50.13212+00 |
| description | A simplified Rust implementation of Google's Zanzibar authorization system with DSL support |
| homepage | https://github.com/tyrchen/simple-zanzibar |
| repository | https://github.com/tyrchen/simple-zanzibar |
| max_upload_size | |
| id | 1712879 |
| size | 76,241 |
A simplified Rust implementation of Google's Zanzibar authorization system, featuring a human-readable DSL for policy definition and comprehensive support for relationship-based access control (ReBAC).
Google's Zanzibar is a global authorization system that provides consistent, scalable authorization decisions across Google's services. It's based on the concept of relationship tuples that express relationships between objects and users.
doc:readme, folder:photos)owner, viewer, editor)user:alice, group:engineers)doc:readme#owner@user:alice)graph TB
subgraph "Simple Zanzibar Architecture"
DSL[DSL Parser] --> Config[Namespace Config]
Config --> Service[Zanzibar Service]
Service --> Store[Tuple Store]
Service --> Eval[Evaluation Engine]
Store --> Memory[In-Memory Store]
Store --> Future[Future: Database Store]
Eval --> Check[Check API]
Eval --> Expand[Expand API]
Check --> Decision{Authorization Decision}
Expand --> Userset[Expanded Userset]
end
subgraph "External Interface"
Client[Client Application] --> Service
Policy[Policy Definition] --> DSL
end
style Service fill:#e1f5fe
style DSL fill:#f3e5f5
style Eval fill:#e8f5e8
style Store fill:#fff3e0
sequenceDiagram
participant Client
participant Service as ZanzibarService
participant Parser as DSL Parser
participant Store as Tuple Store
participant Eval as Evaluation Engine
Note over Client,Eval: Policy Setup
Client->>Service: add_dsl(policy)
Service->>Parser: parse_dsl(policy)
Parser-->>Service: NamespaceConfig
Note over Client,Eval: Tuple Management
Client->>Service: write_tuple(tuple)
Service->>Store: write_tuple(tuple)
Store-->>Service: Ok()
Note over Client,Eval: Authorization Check
Client->>Service: check(object, relation, user)
Service->>Eval: check(object, relation, user, config, store)
Eval->>Store: read_tuples(filter)
Store-->>Eval: Vec<RelationTuple>
Eval->>Eval: recursive_evaluation()
Eval-->>Service: bool
Service-->>Client: Authorization Result
erDiagram
NAMESPACE {
string name
map relations
}
RELATION_CONFIG {
string name
optional userset_rewrite
}
USERSET_EXPRESSION {
enum type
optional relation
optional expressions
}
OBJECT {
string namespace
string id
}
RELATION {
string name
}
USER {
enum type
string user_id
optional object
optional relation
}
RELATION_TUPLE {
object object
relation relation
user user
}
NAMESPACE ||--o{ RELATION_CONFIG : contains
RELATION_CONFIG ||--o| USERSET_EXPRESSION : has
USERSET_EXPRESSION ||--o{ USERSET_EXPRESSION : composed_of
RELATION_TUPLE ||--|| OBJECT : references
RELATION_TUPLE ||--|| RELATION : has
RELATION_TUPLE ||--|| USER : assigned_to
Add this to your Cargo.toml:
[dependencies]
simple-zanzibar = "0.1.0"
use simple_zanzibar::{ZanzibarService, model::{Object, Relation, RelationTuple, User}};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut service = ZanzibarService::new();
// Define policy using DSL
let policy = r#"
namespace doc {
relation owner {}
relation viewer {
rewrite union(this, computed_userset(relation: "owner"))
}
}
"#;
service.add_dsl(policy)?;
// Create objects and users
let doc = Object { namespace: "doc".to_string(), id: "readme".to_string() };
let alice = User::UserId("alice".to_string());
// Grant permission
service.write_tuple(RelationTuple {
object: doc.clone(),
relation: Relation("owner".to_string()),
user: alice.clone(),
})?;
// Check permission
let can_view = service.check(
&doc,
&Relation("viewer".to_string()),
&alice
)?;
println!("Alice can view doc: {}", can_view); // true
Ok(())
}
The Simple Zanzibar DSL allows you to define authorization policies in a human-readable format.
namespace <namespace_name> {
relation <relation_name> {
rewrite <userset_expression>
}
}
thisDirect relationship - users explicitly granted this relation.
relation owner {
rewrite this
}
computed_userset(relation: "relation_name")Users who have another relation on the same object.
relation viewer {
rewrite computed_userset(relation: "owner")
}
tuple_to_userset(tupleset: "relation1", computed_userset: "relation2")Users who have relation2 on objects that have relation1 with the current object.
relation viewer {
rewrite tuple_to_userset(tupleset: "parent", computed_userset: "viewer")
}
union(expr1, expr2, ...)Users who satisfy any of the expressions.
relation viewer {
rewrite union(
this,
computed_userset(relation: "owner"),
computed_userset(relation: "editor")
)
}
intersection(expr1, expr2, ...)Users who satisfy all expressions.
relation admin {
rewrite intersection(
computed_userset(relation: "owner"),
computed_userset(relation: "manager")
)
}
exclusion(base_expr, exclude_expr)Users in base_expr but not in exclude_expr.
relation editor {
rewrite exclusion(
computed_userset(relation: "viewer"),
computed_userset(relation: "banned")
)
}
// File system with hierarchical permissions
namespace file {
relation owner {}
relation parent {}
relation viewer {
rewrite union(
this,
computed_userset(relation: "owner"),
computed_userset(relation: "editor"),
tuple_to_userset(tupleset: "parent", computed_userset: "viewer")
)
}
relation editor {
rewrite union(
this,
computed_userset(relation: "owner")
)
}
}
namespace folder {
relation owner {}
relation parent {}
relation viewer {
rewrite union(
this,
computed_userset(relation: "owner"),
tuple_to_userset(tupleset: "parent", computed_userset: "viewer")
)
}
}
The main service for handling authorization.
impl ZanzibarService {
// Create a new service
pub fn new() -> Self
// Load policy from DSL
pub fn add_dsl(&mut self, dsl: &str) -> Result<(), ZanzibarError>
// Add namespace configuration
pub fn add_config(&mut self, config: NamespaceConfig)
// Write a relation tuple
pub fn write_tuple(&mut self, tuple: RelationTuple) -> Result<(), ZanzibarError>
// Delete a relation tuple
pub fn delete_tuple(&mut self, tuple: &RelationTuple) -> Result<(), ZanzibarError>
// Check if user has relation to object
pub fn check(&self, object: &Object, relation: &Relation, user: &User) -> Result<bool, ZanzibarError>
// Expand userset for object and relation
pub fn expand(&self, object: &Object, relation: &Relation) -> Result<ExpandedUserset, ZanzibarError>
}
// Object represents a resource
pub struct Object {
pub namespace: String,
pub id: String,
}
// Relation represents a permission type
pub struct Relation(pub String);
// User can be a direct user ID or a userset
pub enum User {
UserId(String),
Userset(Object, Relation),
}
// RelationTuple represents a permission assertion
pub struct RelationTuple {
pub object: Object,
pub relation: Relation,
pub user: User,
}
cargo run --example file_permissions
This example demonstrates:
use simple_zanzibar::{ZanzibarService, model::*};
// Define your domain objects
let document = Object {
namespace: "document".to_string(),
id: "proposal.pdf".to_string()
};
let user = User::UserId("john.doe".to_string());
// Set up your service with policies
let mut service = ZanzibarService::new();
service.add_dsl(r#"
namespace document {
relation owner {}
relation collaborator {}
relation viewer {
rewrite union(
this,
computed_userset(relation: "owner"),
computed_userset(relation: "collaborator")
)
}
}
"#)?;
// Grant permissions
service.write_tuple(RelationTuple {
object: document.clone(),
relation: Relation("collaborator".to_string()),
user: user.clone(),
})?;
// Check permissions
let can_view = service.check(
&document,
&Relation("viewer".to_string()),
&user
)?;
Run the test suite:
# Run all tests
cargo test
# Run specific test categories
cargo test --test integration_tests
cargo test --test storage_tests
cargo test --test eval_tests
cargo test --test parser_tests
# Run with output
cargo test -- --nocapture
HashSet for fast lookupsTupleStore trait allows custom storage backendspestContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
pest and thiserrorSimple Zanzibar - Making authorization simple, scalable, and secure. ๐