Complete documentation site covering all aspects of Barycenter: Getting Started, Authentication, OAuth 2.0/OIDC, Authorization Policy Engine, Administration, Deployment, Security, Development, and Reference sections (96 markdown files). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.2 KiB
KDL Policy Language
Barycenter's authorization policies are written in KDL (KDL Document Language), a node-based configuration language that provides a clean, readable syntax for expressing access control rules. Policy files use the .kdl extension and are loaded from the configured policies_dir directory at startup.
Why KDL?
KDL strikes a balance between the simplicity of TOML and the expressiveness of HCL. Its node-based structure maps naturally to the concepts in an authorization policy: resources have child nodes for relations and permissions, roles contain permission lists, and grants are single-line declarations with named attributes.
Key advantages for policy authoring:
- Readable: Node names (
resource,role,grant,rule) read as natural-language declarations. - Structured: Child blocks group related configuration without deeply nested braces.
- Comments: KDL supports
//line comments and/* */block comments for documenting policy intent. - Familiar: The syntax will feel natural to anyone who has worked with CSS, HCL, or similar formats.
The Four Node Types
Every policy file is composed of four types of top-level nodes. Each node type serves a distinct role in the authorization model:
graph LR
R["resource\n(types & permissions)"] --> Role["role\n(permission groups)"]
Role --> G["grant\n(role assignments)"]
R --> Rule["rule\n(ABAC conditions)"]
style R fill:#e8f4f8,stroke:#2980b9
style Role fill:#eaf5ea,stroke:#27ae60
style G fill:#fdf2e9,stroke:#e67e22
style Rule fill:#f5eef8,stroke:#8e44ad
resource
A resource node declares a type of object in your system, along with the relations and permissions that apply to it. Resources are the foundation of the policy model -- they define what can be acted upon and what actions exist.
resource "document" {
relations {
- "owner"
- "editor"
- "viewer"
}
permissions {
- "read"
- "write"
- "delete"
- "share"
}
}
See Resources and Permissions for full syntax and examples.
role
A role node groups permissions together and optionally inherits from other roles. Roles use fully-qualified permission names in the format type:permission to reference the permissions declared on resources.
role "document_viewer" {
permissions {
- "document:read"
}
}
role "document_editor" {
includes {
- "document_viewer"
}
permissions {
- "document:write"
- "document:share"
}
}
See Roles and Inheritance for details on composition and inheritance chains.
grant
A grant node creates a relationship tuple that assigns a role to a principal on a specific resource instance. Grants are the data layer of the authorization model -- they express who has what role on which object.
grant "document_editor" on="document/quarterly-report" to="user/alice"
grant "document_viewer" on="document/quarterly-report" to="group/accounting#member"
See Grants and Relationship Tuples for the full reference syntax and tuple indexing.
rule
A rule node defines an attribute-based policy with a condition expression. Rules can allow or deny access based on properties of the request context, such as the current time, IP address, or custom attributes.
rule "RestrictEditingToBusinessHours" effect="allow" {
permissions {
- "document:write"
}
principals {
- "group:contractors"
}
condition "request.time.hour >= 9 && request.time.hour < 17"
}
See ABAC Rules and Conditions for the complete rule syntax and condition language.
File Organization
All .kdl files in the policies_dir directory are loaded and merged at startup. There is no required file naming convention, but a common pattern is to organize by resource type or domain:
policies/
resources.kdl # resource type definitions
roles.kdl # role definitions with inheritance
grants-team-a.kdl # grants for team A
grants-team-b.kdl # grants for team B
rules.kdl # ABAC rules and conditions
You can also put everything in a single file, or split it however makes sense for your organization. The engine merges all files into a single AuthzState before building its indexes.
Loading Order
Files are loaded in alphabetical order, but the order does not affect evaluation semantics. All nodes are collected and indexed together. However, there are dependencies between node types:
| Node Type | May Reference |
|---|---|
resource |
Nothing (standalone declarations) |
role |
Permissions from resource nodes, other role nodes via includes |
grant |
role names, resource types and IDs |
rule |
Permissions from resource nodes |
If a role references a permission that does not exist on any resource, or a grant references an undefined role, the engine will log a warning at startup. Malformed references do not prevent loading but will never match during evaluation.
Immutability
Policies are immutable after loading. The AuthzState structure that holds all resources, roles, rules, and tuple indexes is built once during startup and shared as read-only state across all request handlers.
To change policies:
- Edit the
.kdlfiles inpolicies_dir. - Commit the changes to version control.
- Restart (or reload) the Barycenter service.
This design ensures that policy evaluation is lock-free and that all authorization decisions during a given process lifetime are consistent. It also makes policy changes fully auditable through your version control system.
Example: Complete Policy File
Here is a minimal but complete policy file that demonstrates all four node types working together:
// Define a resource type for virtual machines
resource "vm" {
relations {
- "owner"
- "viewer"
}
permissions {
- "start"
- "stop"
- "view_console"
}
}
// Define roles with inheritance
role "vm_viewer" {
permissions {
- "vm:view_console"
}
}
role "vm_admin" {
includes {
- "vm_viewer"
}
permissions {
- "vm:start"
- "vm:stop"
}
}
// Assign roles to users and groups
grant "vm_admin" on="vm/prod-web-1" to="user/alice"
grant "vm_viewer" on="vm/prod-web-1" to="group/sre#member"
// Restrict stop operations to business hours
rule "AllowStopDuringBusinessHoursOnly" effect="deny" {
permissions {
- "vm:stop"
}
principals {
- "*"
}
condition "request.time.hour < 6 || request.time.hour >= 22"
}
With this policy loaded, the check request { principal: "user/alice", permission: "vm:start", resource: "vm/prod-web-1" } would be allowed (Alice has vm_admin which includes vm:start), while { principal: "user/alice", permission: "vm:stop", resource: "vm/prod-web-1", context: { "request.time.hour": 23 } } would be denied by the ABAC rule.