A PolicyDomain is a self-contained bundle that defines all policy-related artifacts for a specific domain or service.
PolicyDomains provide:
apiVersion: iamlite.manetu.io/v1beta1
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
scopes: [] # Access-method constraint policies
operations: [] # Operation routing
mappers: [] # Input transformation
Every PolicyDomain document must specify an API version and kind:
apiVersion: iamlite.manetu.io/v1beta1
kind: PolicyDomain # or PolicyDomainReference
Supported API versions: v1alpha3, v1alpha4, v1beta1
:::tip[Use v1beta1 for New Projects]
v1beta1 supports native YAML annotation values, eliminating the need for JSON-encoded strings. This makes PolicyDomains easier to read and write.
:::
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:
name: my-service-policies
The name uniquely identifies the domain. It's used for:
Reusable Rego code shared across policies:
spec:
policy-libraries:
- mrn: "mrn:iam:library:helpers"
name: helpers
rego: |
package helpers
# Shared functions...
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...
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"
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...
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
The PolicyEngine supports two document formats that serve different purposes in the development and deployment workflow.
| 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 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:
.rego files get proper syntax highlightingapiVersion: iamlite.manetu.io/v1beta1
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-librariesmappersUse mpe build to convert PolicyDomainReference to PolicyDomain:
# Convert for deployment
mpe build -f my-domain-ref.yaml -o my-domain.yaml
The build process:
rego_filename reference.rego file contentrego_filename with inline regokind from PolicyDomainReference to PolicyDomainCommunity Users: All tooling (mpe test, mpe serve, Go API) accepts both formats interchangeably. Choose based on your preference:
PolicyDomainReference if you prefer separate .rego filesPolicyDomain if you prefer everything in one filePremium Users: The Kubernetes Operator only accepts PolicyDomain format. You can:
PolicyDomainReference for better IDE supportmpe build as part of your CI/CD pipeline before deploymentPolicyDomain format if you prefermy-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
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"
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.
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 |
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/v1beta1
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/v1beta1
kind: PolicyDomain
metadata:
name: my-service
spec:
# ... PolicyDomain content
# .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
Because PolicyDomains are YAML, policy changes follow standard code review practices:
This approach provides:
mpe lint frequently during developmentSee also: Examples for complete, production ready PolicyDomains for a deeper understanding.
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 |