Roles define the identity-based access permissions for principals in your system. They are the primary mechanism for determining what actions a user or service can perform and are evaluated during Phase 2 (Identity Phase) of Policy Conjunction.
Roles serve a dual purpose in the PolicyEngine:
Policy Selection: A role links a principal's identity to a policy. When a principal is assigned a role, the role's associated policy is evaluated to determine access.
Policy Parameterization: A role can carry annotations that flow into the PORC, allowing generic policies to make context-specific decisions based on the role's configuration.
When a principal is assigned a role, the role's associated policy is evaluated to determine whether the principal can perform the requested operation. Roles answer the question: "Based on who this principal is, what are they allowed to do?"
Roles are evaluated in Phase 2 (Identity Phase) of Policy Conjunction. When a request arrives:
mroles)Principal with roles: [editor, viewer]
Identity Phase Evaluation:
├── editor role policy → GRANT (can edit documents)
├── viewer role policy → DENY (read-only)
Identity Phase Result: GRANT (at least one role granted)
When a principal has multiple roles, the policies are evaluated with OR semantics within the phase:
| Role Evaluations | Phase Result |
|---|---|
| All DENY | |
| At least one GRANT |
This means permissions are effectively additive—a principal gains the union of all their roles' permissions.
Roles are defined in the PolicyDomain under spec.roles:
spec:
roles:
- mrn: "mrn:iam:role:admin"
name: admin
description: "Full administrative access"
policy: "mrn:iam:policy:allow-all"
- mrn: "mrn:iam:role:editor"
name: editor
description: "Can create and modify content"
policy: "mrn:iam:policy:editor-access"
- mrn: "mrn:iam:role:viewer"
name: viewer
description: "Read-only access"
policy: "mrn:iam:policy:read-only"
Each role requires:
Roles are assigned to principals via JWT claims. The PolicyEngine expects roles in the mroles claim:
# PORC expression showing role assignment
principal:
sub: "user123"
mroles:
- "mrn:iam:role:editor"
- "mrn:iam:role:viewer"
The integration layer (PEP) is responsible for extracting role information from the authentication token and including it in the PORC.
Roles can be assigned to principals in two ways:
mroles JWT claimmgroups claimUsing groups simplifies management when many principals share the same set of roles.
Create roles with increasing levels of access:
roles:
- mrn: "mrn:iam:role:viewer"
name: viewer
policy: "mrn:iam:policy:read-only"
- mrn: "mrn:iam:role:editor"
name: editor
policy: "mrn:iam:policy:read-write"
- mrn: "mrn:iam:role:admin"
name: admin
policy: "mrn:iam:policy:full-access"
Organize roles by business function:
roles:
- mrn: "mrn:iam:role:finance-user"
name: finance-user
policy: "mrn:iam:policy:finance-access"
- mrn: "mrn:iam:role:hr-user"
name: hr-user
policy: "mrn:iam:policy:hr-access"
- mrn: "mrn:iam:role:engineering-user"
name: engineering-user
policy: "mrn:iam:policy:engineering-access"
Define roles for service accounts and automated processes:
roles:
- mrn: "mrn:iam:role:batch-processor"
name: batch-processor
description: "Automated batch processing service"
policy: "mrn:iam:policy:batch-operations"
- mrn: "mrn:iam:role:monitoring-agent"
name: monitoring-agent
description: "System monitoring service"
policy: "mrn:iam:policy:monitoring-read"
Understanding the difference between roles and scopes is important:
| Aspect | Roles (Identity Phase) | Scopes (Scope Phase) |
|---|---|---|
| Purpose | Define what a principal can do | Constrain how access is exercised |
| Assignment | Assigned to principals | Associated with access method |
| Effect | Grant permissions | Limit permissions |
| Mandatory | Yes (Phase 2) | No (Phase 4) |
| Default | DENY if missing | GRANT if missing |
Principal: admin role (can read, write, delete)
Access Token Scope: read-only
Identity Phase (roles): GRANT (admin can delete)
Scope Phase: DENY (read-only forbids delete)
Final Decision: DENY (scope constrains identity)
Roles define the maximum permissions; scopes can only restrict, never expand.
Access role information in Rego via input.principal.mroles:
package authz
default allow = false
# Allow if principal has admin role
allow {
"mrn:iam:role:admin" in input.principal.mroles
}
# Allow read operations for viewers
allow {
"mrn:iam:role:viewer" in input.principal.mroles
input.operation.method == "read"
}
# Check for any of multiple roles
allow {
allowed_roles := {"mrn:iam:role:editor", "mrn:iam:role:admin"}
some role in input.principal.mroles
role in allowed_roles
}
Assign the minimum roles necessary for each principal to perform their function. Start with restrictive roles and expand based on observed needs using AccessRecords:
# Good: Specific role for specific function
- mrn: "mrn:iam:role:report-viewer"
policy: "mrn:iam:policy:reports-read"
# Avoid: Overly broad role
- mrn: "mrn:iam:role:super-user"
policy: "mrn:iam:policy:allow-all"
The PolicyEngine's observable architecture makes least privilege practical:
See Iterative Policy Refinement for a detailed workflow.
Name roles based on their purpose, not their technical implementation:
# Good: Describes the business role
- name: content-editor
- name: billing-admin
# Avoid: Technical or generic names
- name: role1
- name: policy-evaluator
Include descriptions to clarify what each role is for:
roles:
- mrn: "mrn:iam:role:data-steward"
name: data-steward
description: "Can manage data classifications and retention policies"
policy: "mrn:iam:policy:data-governance"
Balance between too many fine-grained roles and too few coarse roles:
When multiple principals need the same set of roles, use Groups instead of assigning roles individually.
Roles can carry annotations that flow to the principal during evaluation:
roles:
- mrn: "mrn:iam:role:regional-admin"
name: regional-admin
policy: "mrn:iam:policy:regional-access"
annotations:
- name: "region"
value: "\"us-west\""
- name: "access_level"
value: "\"admin\""
Role annotations have the lowest precedence in the identity annotation hierarchy (Roles → Groups → Scopes → Principal). This makes them ideal for establishing default metadata that can be overridden by more specific sources.
For schema details, see the Roles Schema Reference.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |