Back to Blog

Permission Configuration Guide

coomia-dip uses a three-layer permission model: RBAC (Role-Based) controls feature access, ABAC (Attribute-Based) controls data access policies, and Row-Level Security (RLS) controls record-level visibility. This guide walks through configuring and managing all three layers with complete examples, including role definitions, policy writing, permission inheritance, and audit logging.

CoomiaPublished on January 20, 20268 min read
Share this articleTwitter / X

Series: S12 Developer Tutorials · Article 11 | Level: Intermediate | Reading Time: 15 min

Permission Configuration Guide

#TL;DR

coomia-dip uses a three-layer permission model: RBAC (Role-Based) controls feature access, ABAC (Attribute-Based) controls data access policies, and Row-Level Security (RLS) controls record-level visibility. This guide walks through configuring and managing all three layers with complete examples, including role definitions, policy writing, permission inheritance, and audit logging.

#1. Permission Model Overview

#1.1 Three-Layer Permission Architecture

Code
┌──────────────────────────────────────┐
│        Layer 1: RBAC                 │
│     (Role → Feature/API Access)      │
├──────────────────────────────────────┤
│        Layer 2: ABAC                 │
│     (Attribute Conditions → Policy)  │
├──────────────────────────────────────┤
│        Layer 3: Row-Level Security   │
│     (User Context → Row Filtering)   │
└──────────────────────────────────────┘

#1.2 Permission Check Flow

Code
User Request
    │
    ▼
① RBAC Check: Does the user's role permit this operation?
    │ Pass
    ▼
② ABAC Check: Do user attributes satisfy the access policy?
    │ Pass
    ▼
③ RLS Filter: Automatically inject row-level filter conditions
    │
    ▼
Return filtered data

#2. RBAC Configuration

#2.1 Defining Roles

YAML
# permissions/roles.yaml
roles:
  - name: platform_admin
    display_name: Platform Administrator
    description: Full access to all features
    permissions:
      - "*"

  - name: data_admin
    display_name: Data Administrator
    permissions:
      - "schema:*"
      - "object:read"
      - "object:create"
      - "object:update"
      - "object:delete"
      - "relation:*"
      - "pipeline:*"
      - "metric:*"
      - "dashboard:read"
      - "dashboard:create"

  - name: data_analyst
    display_name: Data Analyst
    permissions:
      - "object:read"
      - "relation:read"
      - "metric:read"
      - "metric:query"
      - "dashboard:read"
      - "dashboard:create"
      - "oql:execute"
      - "function:invoke"

  - name: business_user
    display_name: Business User
    permissions:
      - "object:read"
      - "action:execute"
      - "dashboard:read"
      - "metric:read"

  - name: viewer
    display_name: Read-Only User
    permissions:
      - "object:read"
      - "dashboard:read"
      - "metric:read"

#2.2 Python API Role Management

Python
from ontology_sdk import OntoPlatform
from ontology_sdk.permissions import Role, Permission

platform = OntoPlatform(control_plane_url="localhost:50051")
pm = platform.permissions

# Create role
pm.create_role(
    Role(
        name="project_manager",
        display_name="Project Manager",
        permissions=[
            Permission("object:read"),
            Permission("object:create", resource_type="Project"),
            Permission("object:update", resource_type="Project"),
            Permission("action:execute"),
            Permission("dashboard:read"),
            Permission("dashboard:create"),
            Permission("metric:read"),
            Permission("metric:query"),
        ]
    )
)

# Role inheritance
pm.create_role(
    Role(
        name="senior_analyst",
        display_name="Senior Analyst",
        inherits=["data_analyst"],
        additional_permissions=[
            Permission("pipeline:create"),
            Permission("pipeline:execute"),
            Permission("function:create"),
        ]
    )
)

# Assign roles to users
pm.assign_role("user-001", "project_manager")
pm.assign_role("user-002", ["data_analyst", "viewer"])

# View user permissions
user_perms = pm.get_user_permissions("user-001")
print(f"Permissions: {[p.name for p in user_perms.permissions]}")
print(f"Roles: {user_perms.roles}")

#2.3 Fine-Grained Resource Permissions

Python
pm.create_role(
    Role(
        name="hr_manager",
        display_name="HR Manager",
        permissions=[
            Permission("object:read", resource_type="Employee"),
            Permission("object:create", resource_type="Employee"),
            Permission("object:update", resource_type="Employee"),
            Permission("object:delete", resource_type="Employee"),
            Permission("object:read", resource_type="Department"),
            Permission("object:update", resource_type="Department"),
            Permission("action:execute", resource_pattern="hr_*"),
            Permission("dashboard:read", resource_pattern="hr_*"),
        ]
    )
)

#3. ABAC Policy Configuration

#3.1 ABAC Policy Structure

YAML
# permissions/policies/data_access.yaml
policies:
  - name: department_data_isolation
    display_name: Department Data Isolation
    description: Users can only access data from their own department
    effect: allow
    target:
      object_types: [Employee, Task, Project]
    conditions:
      all:
        - subject.department == resource.department
        - subject.status == "active"
    priority: 100

  - name: sensitive_salary_access
    display_name: Salary Data Restriction
    description: Only HR and management can view salary fields
    effect: deny
    target:
      object_types: [Employee]
      properties: [salary, bonus, stock_options]
    conditions:
      none:
        - subject.role IN ["hr_manager", "platform_admin", "cfo"]
    priority: 200

  - name: customer_tier_access
    display_name: Customer Tier Access Control
    description: Regular users can only access Silver tier and below
    effect: deny
    target:
      object_types: [Customer]
    conditions:
      all:
        - resource.tier IN ["platinum", "gold"]
        - subject.role NOT IN ["account_manager", "sales_director", "platform_admin"]
    priority: 150

#3.2 Python API Policy Management

Python
from ontology_sdk.permissions import Policy, Condition

# Create ABAC policy
pm.create_policy(
    Policy(
        name="department_data_isolation",
        display_name="Department Data Isolation",
        effect="allow",
        target_object_types=["Employee", "Task", "Project"],
        conditions=[
            Condition.equals("subject.department", "resource.department"),
            Condition.equals("subject.status", "active"),
        ],
        priority=100,
    )
)

# Property-level policy (field masking)
pm.create_policy(
    Policy(
        name="sensitive_field_masking",
        display_name="Sensitive Field Masking",
        effect="mask",
        target_object_types=["Employee"],
        target_properties=["phone", "ssn", "bank_account"],
        conditions=[
            Condition.not_in("subject.role", ["hr_manager", "platform_admin"]),
        ],
        masking_rules={
            "phone": "partial",        # 138****1234
            "ssn": "partial",          # ***-**-1234
            "bank_account": "full",    # ****************
        },
        priority=200,
    )
)

# Time-based policy
pm.create_policy(
    Policy(
        name="after_hours_readonly",
        display_name="After-Hours Read-Only",
        effect="deny",
        target_actions=["object:create", "object:update", "object:delete"],
        conditions=[
            Condition.time_outside("08:00", "20:00", timezone="UTC"),
            Condition.not_in("subject.role", ["platform_admin"]),
        ],
        priority=50,
    )
)

#3.3 Policy Evaluation

Python
# Check access (without executing)
result = pm.check_access(
    subject={"user_id": "user-001", "role": "data_analyst", "department": "Engineering"},
    action="object:read",
    resource={"type": "Employee", "department": "Engineering", "properties": ["name", "salary"]}
)

print(f"Access allowed: {result.allowed}")
print(f"Applied policies: {[p.name for p in result.applied_policies]}")
print(f"Masked properties: {result.masked_properties}")

# Batch permission check
checks = [
    {"action": "object:read", "resource": {"type": "Project"}},
    {"action": "object:update", "resource": {"type": "Project"}},
    {"action": "object:delete", "resource": {"type": "Project"}},
    {"action": "pipeline:execute", "resource": {"name": "employee_import"}},
]

batch_results = pm.check_access_batch(
    subject={"user_id": "user-001", "role": "business_user"},
    checks=checks
)

for check, result in zip(checks, batch_results):
    status = "ALLOW" if result.allowed else "DENY"
    print(f"  {check['action']}: {status}")

#4. Row-Level Security (RLS)

#4.1 RLS Rule Definition

YAML
# permissions/rls/department_isolation.yaml
rls_rules:
  - name: dept_employee_filter
    display_name: Department Employee Visibility
    object_type: Employee
    filter:
      department: $user.department
    apply_to:
      roles: [business_user, data_analyst]
    exclude:
      roles: [platform_admin, hr_manager]

  - name: region_customer_filter
    display_name: Regional Customer Visibility
    object_type: Customer
    filter:
      region: $user.region
    apply_to:
      roles: [sales_rep, regional_manager]

  - name: project_participant_filter
    display_name: Project Participant Visibility
    object_type: Project
    filter_query: |
      FIND Project
      TRAVERSE participates_in <- Employee
      WHERE Employee.rid = $user.employee_rid
    apply_to:
      roles: [project_member]

#4.2 Python API RLS Management

Python
from ontology_sdk.permissions import RLSRule, RLSFilter

# Create RLS rule
pm.create_rls_rule(
    RLSRule(
        name="dept_employee_filter",
        display_name="Department Employee Visibility",
        object_type="Employee",
        filter=RLSFilter.equals("department", "$user.department"),
        apply_to_roles=["business_user", "data_analyst"],
        exclude_roles=["platform_admin", "hr_manager"],
    )
)

# Complex RLS (multiple conditions)
pm.create_rls_rule(
    RLSRule(
        name="multi_condition_filter",
        display_name="Multi-Condition Data Filter",
        object_type="Order",
        filter=RLSFilter.all_of([
            RLSFilter.equals("region", "$user.region"),
            RLSFilter.greater_than("total_amount", 0),
            RLSFilter.in_list("status", ["confirmed", "shipped", "delivered"]),
        ]),
        apply_to_roles=["sales_rep"],
    )
)

# Relation-based RLS
pm.create_rls_rule(
    RLSRule(
        name="manager_team_visibility",
        display_name="Manager Team Visibility",
        object_type="Employee",
        filter_query="""
            FIND Employee
            TRAVERSE reports_to -> Employee AS manager
            WHERE manager.rid = $user.employee_rid
            UNION
            FIND Employee WHERE rid = $user.employee_rid
        """,
        apply_to_roles=["team_manager"],
    )
)

#4.3 Automatic RLS Injection

RLS rules are automatically injected into all queries:

Python
# User A (sales_rep, region=East) executes query
# Original OQL:
results = platform.oql.execute("FIND Customer SELECT name, tier, revenue")

# Actually executed OQL (RLS auto-injected):
# FIND Customer WHERE region = 'East' SELECT name, tier, revenue

# User B (platform_admin) executes the same query
# Original OQL = Actual OQL (admin is exempt from RLS)

#5. Permission Groups and Inheritance

#5.1 Organizational Permission Structure

Python
# Create permission groups
pm.create_group(
    name="engineering_dept",
    display_name="Engineering Department",
    members=["user-001", "user-002", "user-003"],
    roles=["data_analyst"],
    attributes={"department": "Engineering", "region": "Shanghai"}
)

pm.create_group(
    name="engineering_leads",
    display_name="Engineering Tech Leads",
    parent_group="engineering_dept",
    members=["user-001"],
    additional_roles=["project_manager"],
    attributes={"level": "lead"}
)

# Permissions are automatically inherited
# engineering_leads has: data_analyst + project_manager roles

#5.2 Multi-Tenant Permission Isolation

Python
pm.create_tenant_policy(
    tenant_id="tenant-001",
    name="tenant_isolation",
    rules=[
        RLSRule(
            object_type="*",
            filter=RLSFilter.equals("tenant_id", "$user.tenant_id"),
            apply_to_roles=["*"],
            exclude_roles=["super_admin"],
        ),
        Policy(
            name="tenant_user_management",
            effect="allow",
            target_actions=["user:*"],
            conditions=[
                Condition.equals("resource.tenant_id", "subject.tenant_id"),
            ],
        ),
    ]
)

#6. Audit Logging

#6.1 Viewing Audit Logs

Python
# Query permission-related audit logs
logs = pm.audit_log.query(
    time_range=("2025-01-01", "2025-03-31"),
    user_id="user-001",
    actions=["object:read", "object:update"],
    result="denied",
    limit=50
)

for log in logs:
    print(f"[{log.timestamp}] {log.user_id} -> {log.action}")
    print(f"  Resource: {log.resource_type}:{log.resource_id}")
    print(f"  Result: {log.result}")
    print(f"  Reason: {log.reason}")
    print(f"  Policy: {log.applied_policy}")
    print("---")

# Permission change audit
changes = pm.audit_log.query_changes(
    time_range=("2025-01-01", "2025-03-31"),
    change_types=["role_assigned", "role_revoked", "policy_created", "policy_updated"]
)

for change in changes:
    print(f"[{change.timestamp}] {change.operator} {change.change_type}")
    print(f"  Target: {change.target}")
    print(f"  Details: {change.details}")

#6.2 Permission Reports

Python
# Generate permission matrix report
matrix = pm.generate_permission_matrix(
    roles=["data_analyst", "project_manager", "business_user"],
    resource_types=["Project", "Employee", "Customer", "Order"]
)

print("Permission Matrix:")
header = f"{'Role':<20} {'Project':<15} {'Employee':<15} {'Customer':<15} {'Order':<15}"
print(header)
for role_row in matrix.rows:
    perms = [','.join(role_row.permissions.get(rt, ['-'])) for rt in matrix.resource_types]
    print(f"{role_row.role:<20} {perms[0]:<15} {perms[1]:<15} {perms[2]:<15} {perms[3]:<15}")

# User permission detail report
user_report = pm.generate_user_report("user-001")
print(f"\nUser: {user_report.user_name}")
print(f"Roles: {user_report.roles}")
print(f"Groups: {user_report.groups}")
print(f"Effective permissions: {len(user_report.effective_permissions)}")
print(f"RLS rules: {len(user_report.rls_rules)}")
print(f"ABAC policies: {len(user_report.applicable_policies)}")

#7. Complete Example: Enterprise Permission Setup

Python
from ontology_sdk import OntoPlatform
from ontology_sdk.permissions import Role, Policy, RLSRule, Condition, RLSFilter, Permission

platform = OntoPlatform(control_plane_url="localhost:50051")
pm = platform.permissions

# === Step 1: Define Role Hierarchy ===
roles = [
    Role(name="admin", display_name="Administrator", permissions=[Permission("*")]),
    Role(name="dept_manager", display_name="Department Manager", permissions=[
        Permission("object:read"), Permission("object:update"),
        Permission("action:execute"), Permission("dashboard:*"),
        Permission("metric:*"), Permission("oql:execute"),
    ]),
    Role(name="employee", display_name="Employee", permissions=[
        Permission("object:read"), Permission("action:execute"),
        Permission("dashboard:read"), Permission("metric:read"),
    ]),
]
for role in roles:
    pm.create_role(role)

# === Step 2: ABAC Policies ===
policies = [
    Policy(
        name="dept_isolation",
        effect="allow",
        target_object_types=["Employee", "Task"],
        conditions=[Condition.equals("subject.department", "resource.department")],
        priority=100,
    ),
    Policy(
        name="salary_protection",
        effect="mask",
        target_object_types=["Employee"],
        target_properties=["salary", "bonus"],
        conditions=[Condition.not_in("subject.role", ["admin", "hr_manager"])],
        masking_rules={"salary": "full", "bonus": "full"},
        priority=200,
    ),
]
for policy in policies:
    pm.create_policy(policy)

# === Step 3: RLS Rules ===
rls_rules = [
    RLSRule(
        name="dept_filter",
        object_type="Employee",
        filter=RLSFilter.equals("department", "$user.department"),
        apply_to_roles=["employee", "dept_manager"],
        exclude_roles=["admin"],
    ),
    RLSRule(
        name="project_access",
        object_type="Project",
        filter_query="""
            FIND Project TRAVERSE participates_in <- Employee
            WHERE Employee.rid = $user.employee_rid
        """,
        apply_to_roles=["employee"],
    ),
]
for rule in rls_rules:
    pm.create_rls_rule(rule)

# === Step 4: Assign Roles ===
pm.assign_role("user-admin", "admin")
pm.assign_role("user-mgr-001", "dept_manager")
pm.assign_role("user-emp-001", "employee")

# === Verify ===
result = pm.check_access(
    subject={"user_id": "user-emp-001", "role": "employee", "department": "Engineering"},
    action="object:read",
    resource={"type": "Employee", "department": "Engineering"}
)
print(f"Employee access own department: {result.allowed}")  # True

result2 = pm.check_access(
    subject={"user_id": "user-emp-001", "role": "employee", "department": "Engineering"},
    action="object:read",
    resource={"type": "Employee", "department": "Finance"}
)
print(f"Employee access other department: {result2.allowed}")  # False

#Key Takeaways

  1. Three-layer defense: RBAC for feature access, ABAC for data policies, RLS for record visibility
  2. Declarative policies: YAML-defined policies, Python API management, hot-update support
  3. Automatic injection: RLS rules auto-inject into all queries -- developers never filter manually
  4. Field masking: ABAC supports property-level masking policies
  5. Complete audit trail: All permission operations and changes are traceable
  6. Multi-tenant support: Tenant-level isolation policies work out of the box

#Next Article

Next: S12-12 Data Import Guide — Learn how to connect various data sources to the coomia-dip platform.

Tags: Permissions RBAC ABAC RLS Security Data Isolation coomia-dip