expert 40 min read advanced-topics Updated: 2025-06-27

Advanced Policy Patterns

Explore complex policy design for dynamic, data-driven, and context-aware infrastructure governance using OPA and Sentinel.

📋 Prerequisites

  • Expert-level proficiency in a policy language (Rego or Sentinel).
  • Experience integrating external data sources into CI/CD or policy workflows.
  • Deep understanding of your cloud providers' resource graph and metadata.
  • Familiarity with building and maintaining shared code libraries/modules.

🏷️ Topics Covered

advanced rego policy patterns and examplesdata driven policy design best practicestemporal policy implementation with opameta policy architecture patternscontext aware policy evaluation techniquescomplex policy design patterns tutorial

💡 Moving Beyond Static Rules

Simple policies check for static values ("instance type must be t3.large"). Advanced policies make decisions based on dynamic, external, or time-based context. They answer questions like, "Is this resource owned by a team that is currently on-call?" or "Are we in a designated deployment window?"

Advanced Policy Design Patterns

These patterns elevate your policies from simple configuration validation to truly context-aware governance, enabling a more intelligent and automated approach to infrastructure management.

📊

Data-Driven Policies

Enrich decisions by fetching data from external systems like a CMDB, an identity provider, or a vulnerability scanner.

Temporal Policies

Make decisions based on time, such as enforcing deployment windows, resource TTLs (Time To Live), or checking for staleness.

📜

Meta-Policies

Write policies that govern other policies, ensuring your policy library itself adheres to standards for metadata, severity, and testing.

Pattern 1: Data-Driven Policies with OPA

This pattern involves enriching the policy evaluation with external data. A common use case is to validate that a resource's owner (defined in a Terraform tag) matches a central CMDB or identity service.

Step 1: The External Data Source (cmdb.json)

This file acts as our source of truth. In a real system, this data would be fetched from an API and passed to OPA.

{
  "users": [
    { "email": "alice@example.com", "team": "platform-engineering" },
    { "email": "bob@example.com", "team": "data-science" }
  ],
  "projects": {
    "infra-project": {
      "authorized_teams": ["platform-engineering"]
    },
    "analytics-project": {
      "authorized_teams": ["data-science", "platform-engineering"]
    }
  }
}

Step 2: The Data-Aware Policy (Rego)

This policy checks if the user deploying a resource (from the CI/CD context) is on a team authorized to manage the resource's project (from its tag).

package terraform.validation
import rego.v1

# The input document contains the Terraform plan and the user who triggered the run
plan := input.tfplan
user_email := input.identity.user_email

# Find the user's team from the CMDB data
user_team := [u.team | u := data.cmdb.users[_]; u.email == user_email][0]

# Find the project tag from the resource
project_tag := plan.resource_changes[_].change.after.tags.project

# Find the list of authorized teams for that project
authorized_teams := data.cmdb.projects[project_tag].authorized_teams

# The policy denies if the user's team is NOT in the list of authorized teams
deny[msg] if {
    not user_team in authorized_teams
    msg := sprintf("User from team '%v' is not authorized for project '%v'", [user_team, project_tag])
}

Pattern 2: Temporal Policies with Sentinel

Temporal policies make decisions based on time. A classic example is a "No Deploy Fridays" policy to reduce the risk of weekend incidents.

Sentinel Policy: "No Deploy Fridays"

This policy uses the timestamp import to get the current time and the param keyword to know if the target workspace is production.

import "timestamp"

# A parameter passed in by Terraform Cloud, defining the environment
param "environment"

# Get the current day of the week (Friday == 5)
day_of_week = timestamp.now.weekday

# The 'main' rule passes and allows the deploy ONLY IF:
# - The environment is NOT production
# - OR the day of the week is NOT Friday
main = rule {
    (environment is not "production") or (day_of_week is not 5)
}

Architectural Best Practices

As your policy library grows, how you structure and manage it becomes critical for performance and maintainability.

Modular Policy Libraries

Break down policies into small, reusable, and composable functions. For example, have a tags.rego file for validating tags, and a network.rego for checking CIDR blocks. Your main policies then import and use these library functions.

Centralized Data Caching

For data-driven policies, use a central data-fetching mechanism (like OPA's Bundle API) to provide a consistent, cached snapshot of external data to all policy evaluations. This avoids slow, repeated API calls at evaluation time.

Policy Inheritance

Create a hierarchy of policies. A global policy set applies to everyone. A team-specific set can then import the global rules and add its own specific overrides, ensuring a consistent baseline with team-level flexibility.