Three-Layer Permission Model: RBAC+ABAC+ReBAC Unified Design
coomia-dip implements a unified three-layer permission model: RBAC controls "who can do what," ABAC governs "under what conditions," and ReBAC determines "based on what relationships." These three layers are orchestrated by the PolicyEngineService with 8 operator types and zero-intrusion query rewriting for data access control. This article provides a comprehensive analysis from architecture design and data modeling through policy evaluation workflows to production best practices.
“Series: S6 Platform Engineering · Article 1 | Level: Advanced | Reading Time: 18 min
Three-Layer Permission Model: RBAC+ABAC+ReBAC Unified Design
#TL;DR
coomia-dip implements a unified three-layer permission model: RBAC controls "who can do what," ABAC governs "under what conditions," and ReBAC determines "based on what relationships." These three layers are orchestrated by the PolicyEngineService with 8 operator types and zero-intrusion query rewriting for data access control. This article provides a comprehensive analysis from architecture design and data modeling through policy evaluation workflows to production best practices.
#1. Why a Three-Layer Permission Model
#1.1 Limitations of Single Models
In traditional enterprise applications, RBAC (Role-Based Access Control) is the most common permission model. However, as data platforms evolve, a single RBAC model faces significant challenges:
- Insufficient granularity: RBAC can only control at the "role-resource" level and cannot enforce fine-grained control based on data attributes (such as classification level or geographic region)
- Relationship blindness: RBAC cannot express authorization like "User A is the owner of Project X, therefore can access all data under Project X"
- Policy explosion: When different departments, data levels, and time periods require different permissions, the number of roles grows exponentially
#1.2 Complementary Three-Layer Design
coomia-dip adopts a complementary three-layer permission model, where each layer addresses specific authorization challenges:
+--------------------------------------------------+
| PolicyEngineService |
| (Unified Policy Evaluation Engine, |
| 8 Operator Types) |
+--------------------------------------------------+
| | |
+--------+ +---------+ +---------+
| RBAC | | ABAC | | ReBAC |
| Role | | Attribute| | Relation|
| Layer | | Layer | | Layer |
+--------+ +---------+ +---------+
| | | | | |
| Roles | | Subject | | Object |
| Perms | | Resource| | Relation|
| Rsrcs | | Environ.| | Tuples |
+--------+ +---------+ +---------+
| Layer | Question Answered | Typical Scenario |
|---|---|---|
| RBAC | Who can do what? | Admins can create Ontologies |
| ABAC | Under what conditions? | Only during work hours, from intranet, on non-confidential data |
| ReBAC | Based on what relationships? | Project owners can access all datasets under their project |
#1.3 Comparison with Palantir Foundry
Palantir Foundry's permission system also employs a multi-layer design, but its implementation is closed-source. coomia-dip achieves equivalent capabilities through open-source:
| Capability | Palantir Foundry | coomia-dip |
|---|---|---|
| Role-based control | Multipass + Project roles | RBAC layer |
| Attribute-based control | Marking + Classification | ABAC layer |
| Relationship-based control | Project membership | ReBAC layer (Zanzibar-style) |
| Query rewriting | Built-in but opaque | Zero-intrusion query rewrite |
| Data masking | Built-in | 6 masking modes |
| Data classification | Multi-tier classification | 7-tier classification (A1-D) |
#2. PolicyEngineService Architecture
#2.1 Service Positioning
PolicyEngineService is the core security service within Control Layer (Control Layer), responsible for orchestrating policy evaluation across all three permission layers. It runs within a Spring Boot 3.x application and provides internal service calls via gRPC.
+-------------------------------------------------------------+
| Control Layer: Control Layer |
| |
| +-------------------+ +------------------+ +----------+ |
| | PolicyEngine | | Classification | | DataMask | |
| | Service | | Service | | Service | |
| | | | | | | |
| | - evaluatePolicy | | - classify | | - mask | |
| | - checkAccess | | - getLevel | | - unmask | |
| | - rewriteQuery | | - autoClassify | | | |
| +-------------------+ +------------------+ +----------+ |
| | | | |
| +----------------------------------------------------+ |
| | Policy Decision Point (PDP) | |
| | 8 Operators: eq, ne, gt, lt, in, contains, | |
| | matches, between | |
| +----------------------------------------------------+ |
+-------------------------------------------------------------+
#2.2 Eight Policy Operators
PolicyEngineService supports 8 policy operators covering all comparison requirements for enterprise-grade permission management:
+----------+-----------------+----------------------------------+
| Operator | Type | Description |
+----------+-----------------+----------------------------------+
| eq | Equality | Exact attribute value match |
| ne | Inequality | Attribute value mismatch |
| gt | Greater than | Numeric/date greater than |
| lt | Less than | Numeric/date less than |
| in | Set membership | Attribute value in given set |
| contains | Containment | String/set contains sub-element |
| matches | Regex match | Attribute matches regex pattern |
| between | Range check | Attribute in range [min, max] |
+----------+-----------------+----------------------------------+
#2.3 Policy Evaluation Flow
A complete policy evaluation flow proceeds as follows:
Request Arrives
|
v
+-------------------+
| 1. Identity | Extract subject info from JWT/mTLS
| Resolution |
+-------------------+
|
v
+-------------------+
| 2. RBAC Check | Query role-permission mappings
| (Fast Path) | Hit -> Direct allow/deny
+-------------------+
|
v (needs fine-grained control)
+-------------------+
| 3. ABAC Eval | Collect subject/resource/env attributes
| (Attr Match) | Evaluate policy expressions with 8 ops
+-------------------+
|
v (needs relationship check)
+-------------------+
| 4. ReBAC Check | Traverse relationship graph
| (Rel Traverse) | Check subject-resource relation paths
+-------------------+
|
v
+-------------------+
| 5. Policy Decision| Merge three-layer results
| (Decision) | DENY > ALLOW > NOT_APPLICABLE
+-------------------+
|
v
+-------------------+
| 6. Obligation | Trigger masking, auditing, etc.
| Enforcement |
+-------------------+
#2.4 Policy Combination Semantics
Results from the three layers are combined using the following semantics:
public enum PolicyDecision {
ALLOW, // Explicitly allow
DENY, // Explicitly deny
NOT_APPLICABLE // Not applicable
}
// Combination rule: DENY-overrides
// Any layer returns DENY -> final DENY
// At least one ALLOW and no DENY -> final ALLOW
// All NOT_APPLICABLE -> final DENY (default deny)
This is the classic DENY-overrides combination strategy, ensuring security takes precedence.
#3. Data Model Design
#3.1 Core Entity Relationships
+-------------+ +---------------+ +-------------+
| Subject |---->| RoleBinding |---->| Role |
| (Principal) | | (Role Binding)| | (Role) |
+-------------+ +---------------+ +-------------+
|
v
+-------------+
| Permission |
| (Permission)|
+-------------+
|
v
+-------------+ +---------------+ +-------------+
| Resource |<----| PolicyRule |---->| Condition |
| (Resource) | | (Policy Rule) | | (Condition) |
+-------------+ +---------------+ +-------------+
|
v
+-------------+ +-------------+
| Relation | | Operator |
| Tuple | | (Operator) |
| (Rel Tuple) | +-------------+
+-------------+
#3.2 gRPC Interface Definition
Core gRPC interfaces for PolicyEngineService:
syntax = "proto3";
package com.onto.control.policy;
service PolicyEngineService {
// Evaluate access policy
rpc EvaluatePolicy(PolicyEvaluationRequest)
returns (PolicyEvaluationResponse);
// Batch access check
rpc BatchCheckAccess(BatchAccessCheckRequest)
returns (BatchAccessCheckResponse);
// Query rewrite (zero-intrusion data filtering)
rpc RewriteQuery(QueryRewriteRequest)
returns (QueryRewriteResponse);
// Get effective permissions for a subject
rpc GetEffectivePermissions(EffectivePermissionsRequest)
returns (EffectivePermissionsResponse);
}
message PolicyEvaluationRequest {
Subject subject = 1; // Subject information
string action = 2; // Operation type
Resource resource = 3; // Resource information
EnvironmentContext env = 4; // Environment context
}
message PolicyEvaluationResponse {
Decision decision = 1; // ALLOW / DENY
repeated Obligation obligations = 2; // Additional obligations
string reason = 3; // Decision reason
int64 evaluation_time_ms = 4; // Evaluation time
}
message Subject {
string id = 1;
string type = 2; // USER, SERVICE, GROUP
map<string, string> attributes = 3;
repeated string roles = 4;
}
message Resource {
string id = 1;
string type = 2; // ONTOLOGY, DATASET, OBJECT, FIELD
map<string, string> attributes = 3;
string classification = 4; // Data classification level
}
#4. Three-Layer Model Coordination
#4.1 Scenario 1: Data Analyst Viewing Customer Data
Consider the following scenario: a data analyst needs to view the phone number field in a customer dataset.
Subject: analyst_001 (Role: DATA_ANALYST)
Action: READ
Resource: customer_dataset.phone_number (Classification: B2-Internal Sensitive)
Evaluation Process:
---------------------------------------------------------
[RBAC] DATA_ANALYST role has READ permission? -> ALLOW
[ABAC] Is it currently work hours? -> ALLOW (09:00-18:00)
[ABAC] Classification B2 <= User clearance B3? -> ALLOW
[ABAC] Is request from intranet? -> ALLOW (10.0.x.x)
[ReBAC] Is user a member of the dataset's project? -> ALLOW
Final Decision: ALLOW
Obligations: Apply PARTIAL_MASK to phone_number field
---------------------------------------------------------
#4.2 Scenario 2: External Partner Viewing Sales Report
Subject: partner_vendor_01 (Role: EXTERNAL_PARTNER)
Action: READ
Resource: sales_report_2024 (Classification: B1-Internal General)
Evaluation Process:
---------------------------------------------------------
[RBAC] EXTERNAL_PARTNER role has READ permission? -> ALLOW (limited)
[ABAC] Is it within contract validity period? -> ALLOW
[ABAC] Classification B1 <= External visible A2? -> DENY !!!
[ReBAC] Does external partner have collaboration? -> ALLOW
Final Decision: DENY (ABAC layer denied, DENY-overrides)
Reason: Data classification level exceeds external partner clearance
---------------------------------------------------------
#4.3 Scenario 3: Project Manager Cross-Project Access
Subject: pm_zhang (Role: PROJECT_MANAGER)
Action: READ
Resource: project_alpha/model_config (Classification: C1-Confidential)
Evaluation Process:
---------------------------------------------------------
[RBAC] PROJECT_MANAGER role has READ permission? -> ALLOW
[ABAC] C1 confidential data requires special approval? -> NOT_APPLICABLE
[ReBAC] Is pm_zhang a member of project_alpha? -> Check graph...
pm_zhang -> member_of -> project_beta (is beta member)
pm_zhang -> member_of -> project_alpha (NOT alpha member)
=> DENY
Final Decision: DENY (ReBAC layer denied)
Reason: Subject is not a member of the target project
---------------------------------------------------------
#5. Performance Optimization
#5.1 Multi-Level Cache Architecture
Permission evaluation is a high-frequency operation. coomia-dip employs multi-level caching:
+-------------------+ +-------------------+ +-------------------+
| L1: Local Cache | | L2: Redis | | L3: Database |
| (Caffeine) | | (Cluster) | | (PostgreSQL) |
| | | | | |
| TTL: 30s | | TTL: 5min | | Persistent |
| Capacity: 10K | | Capacity: 100K | | Storage |
| Hit Rate: ~85% | | Hit Rate: ~12% | | Hit Rate: ~3% |
+-------------------+ +-------------------+ +-------------------+
| | |
+------------------------+-------------------------+
|
Invalidation Strategy:
- Role change -> Clear subject cache
- Policy change -> Clear all policy cache
- Relation change -> Clear relation path cache
#5.2 RBAC Fast Path
For pure RBAC scenarios (no ABAC/ReBAC required), PolicyEngineService provides a fast path optimization:
public PolicyDecision evaluateFastPath(Subject subject, String action,
Resource resource) {
// Fast path: direct RBAC cache lookup
Set<Permission> permissions = rbacCache.getPermissions(subject.getRoles());
for (Permission perm : permissions) {
if (perm.matches(action, resource.getType())) {
// Check if ABAC/ReBAC evaluation needed
if (!perm.hasConditions() && !perm.requiresRelationCheck()) {
return PolicyDecision.ALLOW; // Fast allow
}
}
}
// Fallback to full evaluation
return evaluateFullPath(subject, action, resource);
}
The fast path completes evaluation in < 1ms, covering approximately 70% of requests.
#5.3 Performance Benchmarks
| Scenario | Avg Latency | P99 Latency | Throughput |
|---|---|---|---|
| RBAC fast path | 0.3ms | 1.2ms | 50K QPS |
| RBAC + ABAC | 2.1ms | 8.5ms | 15K QPS |
| RBAC + ABAC + ReBAC | 5.8ms | 22ms | 5K QPS |
| Query rewrite | 3.2ms | 15ms | 10K QPS |
| Batch check (100 resources) | 12ms | 45ms | 2K QPS |
#6. Integration with Other Services
#6.1 Integration Architecture
+-------------------+ +-------------------+
| API Gateway |---->| PolicyEngine |
| (59 REST endpoints)| | Service |
+-------------------+ +---+-----+-----+---+
| | |
+-------------+ | +-------------+
| | |
v v v
+-------------------+ +-------------------+ +-------------------+
| Classification | | AuditService | | DataMask |
| Service | | (13 event types) | | Service |
| (7-tier) | | (3 Kafka topics) | | (6 masking modes) |
+-------------------+ +-------------------+ +-------------------+
#6.2 Audit Integration
Every policy evaluation generates an audit event:
AuditEvent policyAudit = AuditEvent.builder()
.eventType(AuditEventType.POLICY_EVALUATION)
.subject(request.getSubject().getId())
.action(request.getAction())
.resource(request.getResource().getId())
.decision(response.getDecision().name())
.reason(response.getReason())
.evaluationTimeMs(response.getEvaluationTimeMs())
.timestamp(Instant.now())
.build();
auditService.publishAsync(policyAudit); // Async publish to Kafka
#6.3 SDK Integration
The Python SDK provides a concise permission check interface through the OntoPlatform facade:
from ontology_sdk import OntoPlatform
platform = OntoPlatform(endpoint="grpc://control-Layer:9090")
# Check access permission
result = await platform.policy.check_access(
subject_id="analyst_001",
action="READ",
resource_id="customer_dataset",
resource_type="DATASET"
)
if result.allowed:
data = await platform.ontology.query("Customer", limit=100)
# Data is automatically masked (based on policy obligations)
else:
print(f"Access denied: {result.reason}")
#7. Policy Management and Governance
#7.1 Policy Lifecycle
+--------+ +---------+ +--------+ +--------+
| Draft |---->| Pending |---->| Active |---->| Archived|
| DRAFT | | PENDING | | ACTIVE | | ARCHIVED|
+--------+ +---------+ +--------+ +--------+
^ |
| v
+------- Needs Changes <-- +-----------+
| Deprecated|
| DEPRECATED|
+-----------+
#7.2 Policy Version Control
All policy changes go through version control with rollback support:
policy:
id: "POL-DATASET-READ-001"
version: 3
name: "Dataset Read Policy"
description: "Controls read access to datasets"
status: ACTIVE
effective_from: "2026-01-01T00:00:00Z"
rules:
- effect: ALLOW
subjects:
roles: [DATA_ANALYST, DATA_ENGINEER]
actions: [READ, EXPORT]
resources:
types: [DATASET]
conditions:
- attribute: "resource.classification"
operator: "lt"
value: "C1"
- attribute: "environment.time"
operator: "between"
value: ["09:00", "18:00"]
obligations:
- type: MASK
params:
fields: ["phone", "email", "id_card"]
mode: PARTIAL_MASK
#7.3 Policy Conflict Detection
When a new policy may conflict with existing policies, the system automatically detects and alerts:
New Policy: "Allow DATA_ANALYST to read all DATASETs"
Existing Policy: "Deny anyone from reading DATASETs with classification >= C1"
Conflict Detection Result:
Type: POTENTIAL_CONFLICT
Impact: Datasets with classification >= C1
Recommendation: Add classification < C1 condition to new policy
Current Behavior: DENY-overrides guarantees safety (existing policy wins)
#8. Production Deployment Recommendations
#8.1 High-Availability Deployment
+-------------------+
| Load Balancer |
+-------------------+
| | |
+---------+ | +---------+
| | |
+---------v-----+ +-------v-------+ +------v--------+
| PolicyEngine | | PolicyEngine | | PolicyEngine |
| Instance 1 | | Instance 2 | | Instance 3 |
+---------------+ +---------------+ +---------------+
| | |
+-------+--------+--------+-------+
| |
+-------v-------+ +------v--------+
| Redis | | PostgreSQL |
| Cluster | | (Primary + |
| (3 nodes) | | 2 Replicas) |
+---------------+ +---------------+
#8.2 Monitoring Metrics
| Metric | Threshold | Alert Level |
|---|---|---|
| Policy eval latency P99 | > 50ms | WARNING |
| Policy eval latency P99 | > 200ms | CRITICAL |
| Cache hit rate | < 70% | WARNING |
| Policy eval DENY ratio | > 30% | INFO |
| Policy change frequency | > 10/min | WARNING |
#8.3 Capacity Planning
Estimation Formula:
QPS = Active Users x Avg Operations/min x Evaluations/Operation
Example:
1000 Active Users x 10 Ops/min x 2 Evals/Op = 333 QPS
Recommended Configuration:
< 500 QPS: 2 instances, 2 CPU, 4GB RAM
< 2000 QPS: 3 instances, 4 CPU, 8GB RAM
< 10000 QPS: 5 instances, 8 CPU, 16GB RAM
#9. Comparison with Mainstream Solutions
| Feature | coomia-dip | Open Policy Agent | Casbin | Keycloak |
|---|---|---|---|---|
| RBAC | Native | Requires policy writing | Native | Native |
| ABAC | Native | Native | Limited | Limited |
| ReBAC | Native | Custom required | Not supported | Not supported |
| Query rewrite | Native | Not supported | Not supported | Not supported |
| Data masking | 6 modes | Not supported | Not supported | Not supported |
| Data classification | 7-tier | Not supported | Not supported | Not supported |
| gRPC integration | Native | Needs adapter | Embedded | REST |
| Audit trail | 13 event types | Decision logs | None | Limited |
#10. Future Evolution
#10.1 Near-Term Roadmap
- Policy as Code: Git-managed policy versions with CI/CD auto-deployment
- Policy Simulation: Test policy change impacts without affecting production
- Cross-Platform Federated Permissions: Support permission federation across multiple coomia-dip instances
#10.2 Long-Term Vision
- AI-Driven Policy Recommendations: Automatically recommend permission policies based on access patterns
- Zero Trust Network Integration: Deep integration with Service Mesh (Istio)
- Compliance Automation: Automatic generation of MLPS Level 3 / GDPR compliance reports
#Key Takeaways
- Three-layer complementarity: RBAC handles coarse-grained role control, ABAC handles attribute-conditional refinement, ReBAC handles relationship graph authorization -- together they cover all enterprise authorization scenarios
- DENY-overrides: Security-first policy combination semantics where any layer's denial is final
- Fast path optimization: 70% of requests take the RBAC fast path with latency < 1ms
- Zero-intrusion query rewriting: Business code is unaware of permission logic; queries are automatically rewritten based on policies
- Complete audit trail: Every policy evaluation generates audit events ensuring compliance traceability
- Palantir parity: Open-source implementation equivalent to Foundry's Multipass + Marking + Project membership capabilities
#Next Article
The next article S6-02: RBAC Implementation: Modeling Roles, Permissions, and Resources will dive deep into the complete RBAC layer implementation, including role inheritance, permission models, resource hierarchies, and integration with Spring Security.
Tags: #PermissionModel #RBAC #ABAC #ReBAC #PolicyEngine #AccessControl #coomia-dip #PlatformEngineering #SecurityArchitecture #Palantir