Access Control Implementation Guide
On this page
- Quick Start
- 1. Add Dependency
- 2. Create a Policy
- 3. Enforce the Policy
- Common Patterns
- Pattern 1: Multi-Tenant SaaS Application
- Pattern 2: Hide Sensitive Columns
- Pattern 3: Custom Row Filters
- Pattern 4: Wildcard Column Filtering
- Pattern 5: Stream-Level Access Control
- Advanced Usage
- Custom Policy with Multiple Filters
- Query Rewriting with kimberlite-query
- Testing Access Control
- Unit Testing Policies
- Troubleshooting
- Error: “Access denied”
- Error: “No authorized columns in query”
- Query returns empty results
- Best Practices
- 1. Use Standard Policies First
- 2. Test Policy Changes
- 3. Enable Audit Logging in Production
- 4. Monitor Access Denials
- See Also
This guide shows you how to implement Role-Based Access Control (RBAC) in your Kimberlite applications.
Quick Start
1. Add Dependency
[dependencies]
kimberlite-rbac = "0.4"
2. Create a Policy
use StandardPolicies;
use TenantId;
// For a standard user
let tenant_id = new;
let policy = user;
// For an admin
let admin_policy = admin;
3. Enforce the Policy
use PolicyEnforcer;
let enforcer = new;
// Check stream access
enforcer.enforce_stream_access?;
// Filter columns
let requested = vec!;
let allowed = enforcer.filter_columns;
// Generate WHERE clause
let where_clause = enforcer.generate_where_clause;
// Result: "tenant_id = 42"
Common Patterns
Pattern 1: Multi-Tenant SaaS Application
Use Case: Each customer (tenant) should only access their own data.
use StandardPolicies;
use TenantId;
// Extract tenant ID from authenticated user
let user = get_authenticated_user;
let tenant_id = user.tenant_id;
// Create tenant-isolated policy
let policy = user;
let enforcer = new;
// All queries automatically filtered:
// SELECT * FROM orders WHERE tenant_id = 42
Pattern 2: Hide Sensitive Columns
Use Case: Business analysts can see aggregate data but not PII.
use AccessPolicy;
use Role;
let policy = new
.allow_stream
.allow_column
.deny_column
.deny_column
.deny_column;
let enforcer = new;
// Query: SELECT name, email, ssn FROM users
// Rewritten: SELECT name, email FROM users
Pattern 3: Custom Row Filters
Use Case: Show only active records to certain users.
use ;
use Role;
let policy = new
.allow_stream
.allow_column
.with_row_filter;
let enforcer = new;
// Original: SELECT * FROM users
// Rewritten: SELECT * FROM users WHERE status = 'active'
Pattern 4: Wildcard Column Filtering
Use Case: Deny all columns with a specific prefix.
use AccessPolicy;
use Role;
let policy = new
.allow_stream
.allow_column
.deny_column // Deny all PII columns
.deny_column; // Deny all internal columns
// Denies: pii_ssn, pii_address, internal_notes
// Allows: public_name, public_email
Pattern 5: Stream-Level Access Control
Use Case: Auditors can only access audit logs.
use StandardPolicies;
let policy = auditor;
let enforcer = new;
// Allows: audit_log, audit_access, audit_system
enforcer.enforce_stream_access?; // ✓ OK
// Denies: users, orders, payments
let result = enforcer.enforce_stream_access;
assert!; // ✗ Access denied
Advanced Usage
Custom Policy with Multiple Filters
use ;
use Role;
use TenantId;
let policy = new
.with_tenant
// Stream filters
.allow_stream
.allow_stream
.deny_stream
// Column filters
.allow_column
.deny_column
.deny_column
// Row filters (combined with AND)
.with_row_filter
.with_row_filter;
// WHERE tenant_id = 42 AND status = 'active'
Query Rewriting with kimberlite-query
Integration Example:
use RbacFilter;
use StandardPolicies;
use TenantId;
use Parser;
use GenericDialect;
// 1. Create policy
let policy = user;
// 2. Create RBAC filter
let filter = new;
// 3. Parse SQL
let dialect = GenericDialect ;
let sql = "SELECT name, ssn FROM users";
let mut stmt = parse_sql?
.into_iter
.next
.unwrap;
// 4. Rewrite query
let rewritten = filter.rewrite_statement?;
// Result: SELECT name FROM users WHERE tenant_id = 42
// (ssn column removed, WHERE clause injected)
Testing Access Control
Unit Testing Policies
Troubleshooting
Error: “Access denied”
Cause: Policy does not allow access to the requested stream or columns.
Solution: Check policy configuration:
let policy = enforcer.policy;
println!;
println!;
println!;
println!;
Error: “No authorized columns in query”
Cause: All requested columns are denied by the policy.
Solution: Add allow rules for required columns:
let policy = new
.allow_stream
.allow_column // ✓ Explicitly allow
.allow_column; // ✓ Explicitly allow
Query returns empty results
Cause: Row-level security filter excludes all rows.
Solution: Verify row filter logic:
let filters = enforcer.row_filters;
for filter in filters
Best Practices
1. Use Standard Policies First
Start with StandardPolicies before creating custom policies:
// ✓ Good
let policy = user;
// ✗ Avoid (unless you have specific requirements)
let policy = new
.with_tenant
.allow_stream
.allow_column;
2. Test Policy Changes
Always test RBAC policies in a staging environment before production:
3. Enable Audit Logging in Production
// Production: Audit enabled (default)
let enforcer = new;
// Testing only: Audit disabled
let enforcer = new.without_audit;
4. Monitor Access Denials
Set up alerts for excessive access denials:
SELECT role, stream, COUNT(*) as denials
FROM audit_access_log
WHERE decision = 'DENY'
AND timestamp > NOW - INTERVAL '1 hour'
GROUP BY role, stream
HAVING COUNT(*) > 100;
See Also
- RBAC Concepts - Roles, permissions, and compliance
- Data Classification - Classification levels
- Compliance Overview - Multi-framework compliance
- Audit Trails - Audit trail recipes
Next Steps:
- Define your application’s roles and permissions
- Create access policies for each role
- Test policies with unit tests
- Deploy with audit logging enabled
- Monitor access patterns in production