Cedrus is a REST API server for Cedar Policy authorization, designed for internal infrastructure. It provides a multi-tenant authorization service inspired by Amazon Verified Permissions.
Cedrus allows you to:
- Manage authorization policies using Cedar Policy language
- Organize policies by project with isolated storage per project
- Entity Storage entities can be stored and modified at any time
- Evaluate authorization requests in real-time
- Integrate with OIDC providers (Keycloak, AWS Cognito, etc.) for user authentication
- Scale horizontally with distributed cache and pub/sub synchronization
cedrus provides a production-ready HTTP server that exposes Cedrus Core functionality through a RESTful API. It includes:
- Axum web framework: High-performance async HTTP server
- OpenAPI/Swagger UI: Interactive API documentation
- Authentication middleware: JWT bearer tokens and API key support
- CORS support: Cross-origin resource sharing
- Compression: Response compression for better performance
- Request tracing: Built-in logging and observability
The server exposes the following endpoint groups:
- Projects: Create, read, update, delete projects
- Identity Sources: Configure OIDC/Cognito authentication per project
- Schemas: Manage Cedar schemas (JSON and Cedar syntax)
- Entities: CRUD operations for entities
- Policies: Manage static policies (JSON and Cedar syntax)
- Templates: Manage policy templates (JSON and Cedar syntax)
- Template Links: Link templates to specific entities
- Authorization: Real-time authorization checks (single and batch)
- cedrus-cedar: Core library for Cedar JSON/Protobuf serialization and Cedar policy bindings
- cedrus-core: Business logic including database operations, caching, and authorization engine
- cedrus-http: Axum-based HTTP server with OpenAPI documentation
- Project: Isolated namespace containing schemas, entities, policies, and templates
- Entity: Represents principals (users), resources, and groups in your authorization model
- Policy: Cedar policy rules that define who can do what
- Template: Reusable policy patterns with slots for principals/resources
- Template Link: Instantiation of a template with specific values
Cedrus requires a database to persist policies and entities. Supported options:
CouchDB (recommended for local development):
docker run --name cedrus-couchdb \
-e COUCHDB_USER=admin \
-e COUCHDB_PASSWORD=admin \
-p 5984:5984 \
-d couchdbDynamoDB (recommended for AWS deployments):
- Use AWS DynamoDB service or DynamoDB Local for testing
For production deployments with multiple instances:
Valkey/Redis:
docker run --name cedrus-cache \
-p 6379:6379 \
-d valkey/valkey:latestCedrus is an authorization server and requires an authentication provider (OIDC).
Keycloak (example):
docker run --name cedrus-keycloak \
-p 8080:8080 \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:26.4.2 start-devAfter starting Keycloak:
- Access http://localhost:8080
- Create a realm (e.g., "myrealm")
- Create a client (e.g., "myclient")
- Configure client for OIDC authentication
# Clone the repository
git clone <repository-url>
cd cedrus
# Build release binary
cargo build --release
# Install binary (optional)
sudo cp target/release/cedrus /usr/local/bin/Create a configuration file (e.g., cedrus.config.json):
{
"server": {
"port": 3000,
"host": "0.0.0.0",
"apiKey": "YOUR_BASE64_ADMIN_API_KEY"
},
"db": {
"couchDbConfig": {
"dbName": "cedrus",
"uri": "http://localhost:5984",
"username": "admin",
"password": "admin"
}
},
"identitySource": {
"principalEntityType": "Cedrus::User",
"configuration": {
"openIdConnectConfiguration": {
"issuer": "http://localhost:8080/realms/myrealm",
"tokenSelection": {
"identityTokenOnly": {
"clientIds": ["myclient"],
"principalIdClaim": "sub"
}
},
"groupConfiguration": {
"groupClaim": "groups",
"groupEntityType": "Cedrus::Group"
}
}
}
}
}{
"server": {
"port": 3000,
"host": "0.0.0.0",
"apiKey": "YOUR_BASE64_ADMIN_API_KEY"
},
"db": {
"dynamoDbConfig": {
"tableName": "cedrus-table",
"region": "us-east-1"
}
},
"cache": {
"valKeyConfig": {
"urls": ["redis://localhost:6379"],
"cluster": false
}
},
"pubsub": {
"valKeyConfig": {
"urls": ["redis://localhost:6379/?protocol=resp3"],
"channelName": "cedrus",
"cluster": false
}
},
"identitySource": {
"principalEntityType": "Cedrus::User",
"configuration": {
"cognitoUserPoolConfiguration": {
"userPoolArn": "arn:aws:cognito-idp:us-east-1:123456789:userpool/us-east-1_ABC123",
"clientIds": ["your-client-id"],
"groupConfiguration": {
"groupEntityType": "Cedrus::Group"
}
}
}
}
}port: HTTP server port (default: 3000)host: Bind address (use "0.0.0.0" for all interfaces)apiKey: Admin API key for Cedrus management (base64 encoded)
Generate a secure API key:
head -c128 /dev/urandom | base64 --wrap=0CouchDB:
dbName: Database nameuri: CouchDB server URLusername: Admin usernamepassword: Admin password
DynamoDB:
tableName: DynamoDB table nameregion: AWS region (optional, uses default AWS config)endpointUrl: Custom endpoint for DynamoDB Local (optional)
urls: List of Valkey/Redis server URLscluster: Enable cluster mode (true/false)
urls: List of Valkey/Redis server URLs for pub/subchannelName: Channel name for cluster synchronizationcluster: Enable cluster mode (true/false)
OpenID Connect:
{
"openIdConnectConfiguration": {
"issuer": "https://your-oidc-provider.com",
"tokenSelection": {
"identityTokenOnly": {
"clientIds": ["client-id"],
"principalIdClaim": "sub"
}
},
"groupConfiguration": {
"groupClaim": "groups",
"groupEntityType": "Cedrus::Group"
}
}
}AWS Cognito:
{
"cognitoUserPoolConfiguration": {
"userPoolArn": "arn:aws:cognito-idp:region:account:userpool/pool-id",
"clientIds": ["client-id"],
"groupConfiguration": {
"groupEntityType": "Cedrus::Group"
}
}
}See config/cedrus-local.config.json for a complete example.
# Using the binary
cedrus /path/to/cedrus.config.json
# Or with cargo
cargo run --release -- /path/to/cedrus.config.jsonThe server will start on the configured port (default: http://localhost:3000).
Once running, access the interactive API documentation:
Swagger UI: http://localhost:3000/swagger-ui/
The Swagger UI provides:
- Complete API endpoint documentation
- Request/response schemas
- Interactive testing interface
- Authentication configuration
- Open http://localhost:3000/swagger-ui/
- Click "Authorize" button
- Enter your API key or JWT token
- Test endpoints interactively
Cedrus supports two authentication methods:
-
Bearer Token (for end users): Use JWT tokens from your OIDC provider
Authorization: Bearer <jwt-token> -
API Key (for service accounts): Use project-specific API keys
X-API-KEY: <project-api-key>
curl -X POST http://localhost:3000/v1/projects \
-H "X-API-KEY: YOUR_ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "My Application",
"owner": {
"type": "Cedrus::User",
"id": "user-123"
}
}'curl -X PUT http://localhost:3000/v1/projects/{project-id}/schema \
-H "X-API-KEY: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"MyApp": {
"entityTypes": {
"User": {},
"Document": {
"shape": {
"type": "Record",
"attributes": {
"owner": {
"type": "Entity",
"name": "User"
}
}
}
}
},
"actions": {
"viewDocument": {
"appliesTo": {
"principalTypes": ["User"],
"resourceTypes": ["Document"]
}
}
}
}
}'curl -X POST http://localhost:3000/v1/projects/{project-id}/entities \
-H "X-API-KEY: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{
"uid": {"type": "MyApp::User", "id": "alice"},
"attrs": {},
"parents": []
},
{
"uid": {"type": "MyApp::Document", "id": "doc1"},
"attrs": {
"owner": {"type": "MyApp::User", "id": "alice"}
},
"parents": []
}
]'curl -X POST http://localhost:3000/v1/projects/{project-id}/policies \
-H "X-API-KEY: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"owner-can-view": {
"effect": "permit",
"principal": {"op": "All"},
"action": {
"op": "==",
"entity": {"type": "MyApp::Action", "id": "viewDocument"}
},
"resource": {"op": "All"},
"conditions": [{
"kind": "when",
"body": {
"==": {
"left": {".": {"left": {"Var": "resource"}, "attr": "owner"}},
"right": {"Var": "principal"}
}
}
}]
}
}'curl -X POST http://localhost:3000/v1/projects/{project-id}/is-authorized \
-H "X-API-KEY: YOUR_PROJECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"principal": {"type": "MyApp::User", "id": "alice"},
"action": {"type": "MyApp::Action", "id": "viewDocument"},
"resource": {"type": "MyApp::Document", "id": "doc1"}
}'Response:
{
"decision": "Allow",
"diagnostics": {
"reason": ["owner-can-view"],
"errors": []
}
}┌─────────────────────────────────────────────────────────┐
│ Cedrus HTTP Server │
├─────────────────────────────────────────────────────────┤
│ Axum Router │
│ ├─ Authentication Middleware │
│ ├─ CORS Layer │
│ ├─ Compression Layer │
│ └─ Tracing Layer │
├─────────────────────────────────────────────────────────┤
│ REST API Handlers │
│ ├─ Projects │
│ ├─ Schemas │
│ ├─ Entities │
│ ├─ Policies │
│ └─ Authorization │
├─────────────────────────────────────────────────────────┤
│ Cedrus Core (Business Logic) │
└─────────────────────────────────────────────────────────┘
Applied to all /v1/projects/* routes:
-
Checks for
X-API-KEYheader- If present, validates against project API keys
- Maps to project owner entity
-
If no API key, checks for
Authorization: Bearerheader- Validates JWT token with configured OIDC provider
- Extracts user identity from token claims
- Maps to
Cedrus::Userentity
-
Injects principal
EntityUidinto request extensions
Allows cross-origin requests:
- All origins accepted
- All methods allowed
- All headers allowed
Automatically compresses responses for better performance.
Logs all HTTP requests with:
- Request method and path
- Response status code
- Request duration
cargo testcargo build --releaseThe binary will be available at target/release/cedrus.
Cedrus implements a multi-tenant model:
- Admin Project (UUID: 00000000-0000-0000-0000-000000000000): Controls access to Cedrus itself
- User Projects: Each project is isolated with its own schemas, entities, and policies
- Project API Keys: Each project has a unique API key for service-to-service authentication
- Role-Based Access: Users can have different roles across projects
Use DashMap cache (in-memory, no external dependencies):
{
"cache": {"dashMapConfig": {}},
"pubsub": {"dummyConfig": {}}
}Use Valkey/Redis for distributed cache and pub/sub:
{
"cache": {
"valKeyConfig": {
"urls": ["redis://cache-server:6379"],
"cluster": true
}
},
"pubsub": {
"valKeyConfig": {
"urls": ["redis://cache-server:6379/?protocol=resp3"],
"channelName": "cedrus",
"cluster": true
}
}
}- Verify database is running and accessible
- Check firewall rules for database and cache ports
- Ensure OIDC issuer URL is reachable
- Verify JWT token is valid and not expired
- Check OIDC client configuration matches Cedrus config
- Ensure
principalIdClaimmatches the claim in your JWT
- Review policies using the Swagger UI
- Check entity relationships and attributes
- Use the Cedar policy playground to test policy logic
- Check configuration file syntax (valid JSON)
- Verify database is accessible
- Ensure port is not already in use
- Check file permissions on config file
- Verify OIDC issuer URL is correct and reachable
- Check client IDs match your OIDC configuration
- Ensure JWT tokens are not expired
- Verify API keys are correct
- Check policies are correctly defined
- Verify entities exist and have correct attributes
- Review entity parent relationships
- Use Swagger UI to inspect current policies
axum: Web frameworkcedrus-core: Business logiccedrus-cedar: Type definitionstower-http: HTTP middlewareutoipa: OpenAPI documentationutoipa-swagger-ui: Swagger UI integrationjwt-authorizer: JWT validationtokio: Async runtime
This server can be:
- Deployed standalone: As a microservice
- Embedded in applications: Using cedrus-core directly
- Used as a sidecar: For authorization in Kubernetes
Apache-2.0
Stratus Media Solutions SL. All Rights Reserved.
