PolicyDomains
A PolicyDomain is a self-contained bundle that defines all policy-related artifacts for a specific domain or service.
Overview
PolicyDomains provide:
- Modularity: Package related policies together
- Portability: Deploy policies as a single unit
- Reusability: Share libraries across policies within a domain
- Versioning: Track changes to policy bundles
PolicyDomain Structure
apiVersion: iamlite.manetu.io/v1alpha4
kind: PolicyDomain
metadata:
name: my-domain
spec:
policy-libraries: [] # Reusable Rego code
policies: [] # Access control policies
roles: [] # Role-to-policy mappings
groups: [] # Group-to-role mappings
resource-groups: [] # Resource-to-policy mappings
resources: [] # Resource selector routing (v1alpha4+)
scopes: [] # Access-method constraint policies
operations: [] # Operation routing
mappers: [] # Input transformation
API Version and Kind
Every PolicyDomain document must specify an API version and kind:
apiVersion: iamlite.manetu.io/v1alpha4
kind: PolicyDomain # or PolicyDomainReference
Supported API versions: v1alpha3, v1alpha4
Supported kinds:
| Kind | Description |
|---|---|
PolicyDomain | Deployment format with inline Rego code |
PolicyDomainReference | Development format that can reference external .rego files |
See PolicyDomain vs PolicyDomainReference for detailed guidance on when to use each format.
Metadata
metadata:
name: my-service-policies
The name uniquely identifies the domain. It's used for:
- Cross-domain references
- Logging and debugging
- Bundle identification
Components Overview
Policy Libraries
Reusable Rego code shared across policies:
spec:
policy-libraries:
- mrn: "mrn:iam:library:helpers"
name: helpers
rego: |
package helpers
# Shared functions...
Policies
The Rego code that makes access decisions:
spec:
policies:
- mrn: "mrn:iam:policy:main"
name: main
dependencies:
- "mrn:iam:library:helpers"
rego: |
package authz
# Policy logic...
Roles, Groups, Resource Groups, Resources, Scopes
Identity and resource mappings:
spec:
roles:
- mrn: "mrn:iam:role:admin"
name: admin
policy: "mrn:iam:policy:allow-all"
groups:
- mrn: "mrn:iam:group:admins"
name: admins
roles:
- "mrn:iam:role:admin"
resource-groups:
- mrn: "mrn:iam:resource-group:default"
name: default
default: true
policy: "mrn:iam:policy:allow-all"
# v1alpha4+: Route resources to groups by MRN pattern
resources:
- name: sensitive-data
selector:
- "mrn:data:sensitive:.*"
group: "mrn:iam:resource-group:restricted"
scopes:
- mrn: "mrn:iam:scope:api"
name: api
policy: "mrn:iam:policy:allow-all"
Operations and Mappers
Request routing and transformation:
spec:
operations:
- name: api
selector: [".*"]
policy: "mrn:iam:policy:main"
mappers:
- name: http-mapper
selector: [".*"]
rego: |
package mapper
# Transform input to PORC...
Using YAML Anchors
YAML anchors increase PolicyDomain maintainability:
spec:
policies:
- mrn: &allow-all "mrn:iam:policy:allow-all"
name: allow-all
rego: |
package authz
default allow = true
roles:
- mrn: "mrn:iam:role:admin"
name: admin
policy: *allow-all # Reference the anchor
PolicyDomain vs PolicyDomainReference
The PolicyEngine supports two document formats that serve different purposes in the development and deployment workflow.
Key Differences
| Aspect | PolicyDomain | PolicyDomainReference |
|---|---|---|
| Rego code | Inline rego field only | Either rego (inline) or rego_filename (external file) |
| Primary use | Deployment, runtime evaluation | Development, source control |
| Kubernetes Operator | Supported (Premium) | Must convert with mpe build first |
| Community tooling | Fully supported | Fully supported |
PolicyDomainReference Format
PolicyDomainReference is a superset of PolicyDomain that allows referencing external .rego files instead of embedding Rego code inline. This is the recommended format for development because:
- IDE support: Separate
.regofiles get proper syntax highlighting - Easier testing: Test individual Rego files with standard OPA tooling
- Cleaner diffs: Policy logic changes are isolated from YAML structure
- Better organization: Keep complex policies in dedicated files
apiVersion: iamlite.manetu.io/v1alpha4
kind: PolicyDomainReference
metadata:
name: my-domain
spec:
policy-libraries:
- mrn: "mrn:iam:library:helpers"
name: helpers
rego_filename: lib/helpers.rego # External file
policies:
- mrn: "mrn:iam:policy:main"
name: main
dependencies:
- "mrn:iam:library:helpers"
rego_filename: policies/main.rego # External file
- mrn: "mrn:iam:policy:simple"
name: simple
rego: | # Inline is also allowed
package authz
default allow = true
The rego_filename field is supported on:
policiespolicy-librariesmappers
Converting to PolicyDomain
Use mpe build to convert PolicyDomainReference to PolicyDomain:
# Convert for deployment
mpe build -f my-domain-ref.yaml -o my-domain.yaml
The build process:
- Reads each
rego_filenamereference - Loads the external
.regofile content - Replaces
rego_filenamewith inlinerego - Changes
kindfromPolicyDomainReferencetoPolicyDomain
Which Format Should I Use?
Community Users: All tooling (mpe test, mpe serve, Go API) accepts both formats interchangeably. Choose based on your preference:
- Use
PolicyDomainReferenceif you prefer separate.regofiles - Use
PolicyDomainif you prefer everything in one file
Premium Users: The Kubernetes Operator only accepts PolicyDomain format. You can:
- Develop using
PolicyDomainReferencefor better IDE support - Run
mpe buildas part of your CI/CD pipeline before deployment - Or develop directly in
PolicyDomainformat if you prefer
Development Workflow Example
my-policies/
├── domain.yaml # PolicyDomainReference
├── lib/
│ └── helpers.rego # Shared library code
├── policies/
│ ├── identity.rego # Identity phase policy
│ └── resource.rego # Resource phase policy
└── build/
└── domain-built.yaml # Generated PolicyDomain (git-ignored)
Build command in CI/CD:
mpe build -f domain.yaml -o build/domain-built.yaml
Multiple Domains
You can load multiple PolicyDomains together:
mpe test decision \
-b base-policies.yml \
-b service-policies.yml \
-i input.json
Cross-domain library references use the format:
dependencies:
- "other-domain/library-name"
GitOps-Friendly Design
PolicyDomains are fundamentally GitOps-friendly because they are plain files—YAML documents that can be version-controlled, reviewed, tested, and deployed through any standard GitOps workflow.
Why Plain Files Matter
- Human-readable: Easy to review in pull requests
- Diff-friendly: Changes are clearly visible in version control
- Declarative: Describes the desired state, not imperative steps
- Tooling support: Standard YAML linting, formatting, and validation
- Portable: Deploy through any file-based workflow
Deployment Patterns
Because PolicyDomains are just files, they integrate with any GitOps-oriented deployment flow:
| Pattern | Description |
|---|---|
| Push-based | Git → CI pipeline → kubectl apply to Kubernetes |
| Pull-based | GitOps operators (Flux, ArgoCD) continuously sync from Git |
Delivery by Edition
ConfigMap-based delivery
In the Community Edition, PolicyDomains are typically delivered as Kubernetes ConfigMaps. Configure your PDP pods (for HTTP API integration) or application pods (for embedded Go) to trigger a rolling restart when the ConfigMap changes:
apiVersion: v1
kind: ConfigMap
metadata:
name: policy-domain
data:
domain.yaml: |
apiVersion: iamlite.manetu.io/v1alpha4
kind: PolicyDomain
metadata:
name: my-service
spec:
# ... PolicyDomain content
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mpe-pdp
spec:
template:
metadata:
annotations:
# Trigger rollout when ConfigMap changes
checksum/config: "{{ sha256sum .Values.policyDomain }}"
CRD-based delivery with dynamic updates
The Premium Edition provides a Kubernetes Custom Resource Definition (CRD) for PolicyDomain resources. When a PolicyDomain CRD instance is created or updated—whether through CI push or a GitOps operator pull—the Policy Administration Point (PAP) automatically distributes the new policies to all PDPs through the cache-coherency mechanism. No pod restarts required.
apiVersion: iamlite.manetu.io/v1alpha4
kind: PolicyDomain
metadata:
name: my-service
spec:
# ... PolicyDomain content
Example CI Pipeline
# .github/workflows/policy-ci.yml
name: Policy CI
on:
push:
paths:
- 'policies/**'
pull_request:
paths:
- 'policies/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install MPE
run: |
curl -L https://github.com/manetu/policyengine/releases/latest/download/mpe-linux-amd64 -o mpe
chmod +x mpe
sudo mv mpe /usr/local/bin/
- name: Lint policies
run: mpe lint -f policies/domain.yaml
- name: Run policy tests
run: |
for test in policies/tests/*.json; do
echo "Running test: $test"
mpe test decision -b policies/domain.yaml -i "$test" | \
jq 'if .decision == "DENY" then "Test failed: access denied" | halt_error(1) else . end'
done
- name: Build for deployment
run: mpe build -f policies/domain.yaml -o dist/domain.yaml
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: policy-bundle
path: dist/domain.yaml
Pull Request Reviews
Because PolicyDomains are YAML, policy changes follow standard code review practices:
- Author creates a branch with policy changes
- CI automatically validates syntax and runs tests
- Reviewers examine the diff—changes are clear and auditable
- Merge triggers deployment to staging/production
This approach provides:
- Audit trail: Git history shows who changed what and when
- Rollback: Revert to any previous policy version instantly
- Collaboration: Multiple team members can work on policies
- Testing: Automated validation before deployment
Best Practices
- One domain per service: Keep domains focused
- Use libraries: Extract common code into libraries
- Use anchors: Avoid duplicating MRNs
- Use references: Keep Rego in external files for better editing
- Validate early: Run
mpe lintfrequently during development - Version control: Store PolicyDomains in Git with your application code or in a dedicated policy repository
- Automate testing: Include policy tests in your CI/CD pipeline
Related Concepts
- Policies: Authorization policies defined in domains
- Policy Libraries: Reusable Rego code shared across policies
- Operations: Route requests to operation phase policies
- Roles: Connect principals to identity phase policies
- Groups: Bundle roles for easier assignment
- Resource Groups: Connect resources to resource phase policies
- Scopes: Define access-method constraints
- Resources: Define resource routing patterns
- Mappers: Transform non-PORC inputs
See also: Examples for complete, production ready PolicyDomains for a deeper understanding.