Skip to content

Latest commit

 

History

History
116 lines (79 loc) · 8.13 KB

File metadata and controls

116 lines (79 loc) · 8.13 KB

Resource Group Model — AuthZ Perspective

This document describes how Cyber Ware's authorization system uses Resource Groups (RG) for access control. For the full RG module design (domain model, API contracts, database schemas, type system), see RG Technical Design.


Overview

Cyber Ware uses resource groups as an optional organizational layer for grouping resources. The primary purpose from the AuthZ perspective is access control — granting permissions at the group level rather than per-resource.

Tenant T1
├── [Group A]
│   ├── Resource 1
│   ├── Resource 2
│   └── [Group A.1]
│       └── Resource 3
├── [Group B]
│   ├── Resource 1
│   └── Resource 4
└── (ungrouped resources)

Key principles:

  • Optional — resources may exist without group membership
  • Many-to-many — a resource can belong to multiple groups
  • Hierarchical — groups form a strict forest (single parent, no cycles); multiple roots are allowed, but among them there is at most one tenant-type root (the "main tenant"). All other tenants are sub-tenants below that main tenant; non-tenant roots may coexist and carry the main tenant's tenant_id but are not tenants themselves — see RG DESIGN §Tenant Root Uniqueness.
  • Tenant-scoped — groups exist within tenant boundaries
  • Typed — groups have dynamic GTS types with configurable parent/membership rules

For topology details (forest invariants, type system, query profiles), see RG DESIGN §Domain Model.


How AuthZ Uses Resource Groups

AuthZ consumes RG data as a PIP (Policy Information Point) source. RG is policy-agnostic — it stores hierarchy and membership data without evaluating access decisions. AuthZ plugin reads this data to resolve group-based predicates.

Projection Tables

RG tables are the canonical source of truth, owned by the RG module. External consumers (AuthZ resolver, domain services) may maintain projection copies in their databases — synchronized from RG via read contracts (ResourceGroupReadHierarchy).

Projectable tables:

  • resource_group — group entities with hierarchy (parent_id) and tenant scope (tenant_id)
  • resource_group_closure — pre-computed ancestor-descendant pairs with depth, enabling efficient subtree queries
  • resource_group_membership — resource-to-group M:N links (see guidance below)

Progressive projection strategy

Whether and which tables to project depends on the deployment topology and access patterns. Do not add projections speculatively — each projection creates an additional database, synchronization load, and operational complexity.

Deployment Recommended projections Rationale
Monolith (single shared DB) None — all tables are already co-located PEP JOINs against canonical tables directly; no extra databases or sync needed
Microservices (separate DBs, typical case) resource_group + resource_group_closure Enables in_group_subtree predicates locally; hierarchy tables are small (~100 K rows). Membership resolved by PDP via capability degradation → in predicates
Microservices with membership filtering/pagination resource_group + resource_group_closure + resource_group_membership Only when profiling confirms the two-request pattern (RG API → domain service) is unacceptable for latency budget. Membership table grows as M_resources × N_groups_per_resource and is expected to be 10× or more larger than hierarchy tables — see RG DESIGN §Storage Estimates for concrete numbers

Important: When a domain service query includes filters by resource group attributes (e.g., GET /tasks?status=pending&project={projectX}&after=…&limit=50), the two-request pattern means N additional round-trips to the RG Membership API (one per filter page or group), not just +1. If this N-request fan-out violates the latency budget, that is the signal to project the membership table locally.

Architecture guidance: default to consuming degraded in predicates from PDP. The in_group and in_group_subtree predicates are natively executable within the RG module; domain services that choose not to project the membership table rely on PDP capability degradation.

PEP within the RG module compiles in_group/in_group_subtree predicates into SQL subqueries using the membership table. Domain services without the membership projection receive degraded in predicates and do not need group-related projection tables for authorization filtering.

Access Inheritance

  • Explicit membership, inherited access — a resource is added to a specific group (explicit). Access is inherited top-down: a user with access to parent group G1 can access resources in all descendant groups via in_group_subtree predicate.
  • Flat group accessin_group predicate checks direct membership only (no hierarchy traversal).

Integration Path

AuthZ plugin reads RG hierarchy via ResourceGroupReadHierarchy trait (narrow, hierarchy-only read contract). In monolith deployments (current p1 reality), it's a direct in-process call via ClientHub and the trait surface itself bypasses PolicyEnforcer (the plugin cannot evaluate itself). In a future microservice deployment (p2, deferred / not implemented yet), the same trait will be backed by an MTLS-authenticated request to the RG service. See RG DESIGN §RG Authentication Modes: JWT vs MTLS.


Relationship with Tenant Model

Tenants and Resource Groups serve different purposes:

Aspect Tenant Resource Group
Purpose Ownership, isolation, billing Grouping for access control
Scope System-wide Per-tenant
Resource relationship Ownership (1:N) Membership (M:N)
Hierarchy Single-root tree Forest (multiple roots per tenant)
Type system Fixed (built-in tenant type) Dynamic (GTS-based, vendor-defined types)

Resource groups operate within tenant boundaries — groups are tenant-scoped, cross-tenant groups are forbidden, and authorization always includes a tenant constraint alongside group predicates.

Key rules:

  1. Groups are tenant-scoped — a group belongs to exactly one tenant
  2. Cross-tenant groups are forbidden — a group cannot span multiple tenants
  3. Tenant constraint always applies — authorization always includes a tenant constraint alongside group predicates

Further reading:


References