Liking cljdoc? Tell your friends :D

sidebar_position: 9

PolicyDomains

A PolicyDomain is a self-contained bundle that defines all policy-related artifacts for a specific domain or service.

![PolicyDomain Model](./assets/policydomain.svg)

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/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

API Version and Kind

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:

KindDescription
PolicyDomainDeployment format with inline Rego code
PolicyDomainReferenceDevelopment 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

AspectPolicyDomainPolicyDomainReference
Rego codeInline rego field onlyEither rego (inline) or rego_filename (external file)
Primary useDeployment, runtime evaluationDevelopment, source control
Kubernetes OperatorSupported (Premium)Must convert with mpe build first
Community toolingFully supportedFully 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 .rego files 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/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:

  • policies
  • policy-libraries
  • mappers

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:

  1. Reads each rego_filename reference
  2. Loads the external .rego file content
  3. Replaces rego_filename with inline rego
  4. Changes kind from PolicyDomainReference to PolicyDomain

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 PolicyDomainReference if you prefer separate .rego files
  • Use PolicyDomain if you prefer everything in one file

Premium Users: The Kubernetes Operator only accepts PolicyDomain format. You can:

  • Develop using PolicyDomainReference for better IDE support
  • Run mpe build as part of your CI/CD pipeline before deployment
  • Or develop directly in PolicyDomain format 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:

![GitOps](./assets/gitops.svg)
PatternDescription
Push-basedGit → CI pipeline → kubectl apply to Kubernetes
Pull-basedGitOps 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/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

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:

  1. Author creates a branch with policy changes
  2. CI automatically validates syntax and runs tests
  3. Reviewers examine the diff—changes are clear and auditable
  4. 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

  1. One domain per service: Keep domains focused
  2. Use libraries: Extract common code into libraries
  3. Use anchors: Avoid duplicating MRNs
  4. Use references: Keep Rego in external files for better editing
  5. Validate early: Run mpe lint frequently during development
  6. Version control: Store PolicyDomains in Git with your application code or in a dedicated policy repository
  7. 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.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close