Terraform Policy Pack¶
This page describes how Terraform policies are organised for the HybridOps.Studio platform and how they are expected to be consumed by CI/CD. The goal is to provide clear, reviewable guardrails around Terraform plans, without baking policy logic into individual modules or stacks.
The definitive source for policy code lives in the platform repository:
Policy structure¶
Policies are grouped by engine under a single root:
infra/terraform/policies/
├── opa/
│ └── terraform.rego
└── sentinel/
├── deny_public_ip_in_prod.sentinel
├── no_broad_role_assignments_in_prod.sentinel
└── require_kv_purge_protection.sentinel
opa/– Open Policy Agent (Rego) policies, intended for use in generic pipelines or CLI validation.sentinel/– HashiCorp Sentinel policies, for use with Terraform Cloud/Enterprise or a compatible runner.
The CI/CD layer chooses which engine is active for a given pipeline. The Terraform code under infra/terraform/live-v1/** remains policy-agnostic.
Policy intent¶
The initial policy pack focuses on three recurring risks:
- Uncontrolled public exposure in production
- Deny plans that create public IPs, public load balancers, or open inbound rules in the
prodenvironment. -
Encourage explicit, audited exceptions rather than ad-hoc overrides.
-
Overly broad role assignments
- Guard against subscription- or project-wide role assignments that are not narrowly scoped.
-
Push teams towards least-privilege, resource- or RG-scoped roles.
-
Weak key and secret management
- Enforce purge protection and soft-delete on Key Vaults and equivalent services.
- Block plans that attempt to disable those features in live environments.
Additional checks (for example, tagging standards, naming conventions, or storage encryption) can be added incrementally without changing the entry points into Terraform.
OPA policies (opa/)¶
The OPA entry point is:
Expected usage pattern (conceptual):
- Generate a Terraform plan in JSON form:
terraform show -json plan.out > plan.json- Run the plan JSON through an OPA evaluation step in CI.
- Fail the pipeline if the policy decision is
deny.
OPA is engine-only in this context: the policy file is maintained in Git, but how it is invoked (GitHub Actions, Jenkins, or a local wrapper) is left to the pipeline definition.
Sentinel policies (sentinel/)¶
Sentinel policies live under:
They are designed for use with:
- Terraform Cloud / Enterprise policy sets, or
- A standalone Sentinel runner wired into a bespoke pipeline.
The current examples are:
deny_public_ip_in_prod.sentinel– blocks public IPs and similar public ingress in production.no_broad_role_assignments_in_prod.sentinel– rejects broad role assignments at subscription or project scope.require_kv_purge_protection.sentinel– enforces purge protection on Key Vaults or similar secret stores.
In Terraform Cloud, these policies are attached as policy sets to the workspaces for the infra/terraform/live-v1/** stacks, using the same workspace naming convention as the Terragrunt root.hcl files.
Relationship to live Terraform stacks¶
Policies are not embedded inside the Terraform configuration:
- Modules under
infra/terraform/modules/**are written without any direct dependency on OPA or Sentinel. - Live stacks under
infra/terraform/live-v1/**do not import policy files.
Instead:
- CI pipelines map a given stack (for example,
live-v1/cloud/azure/environments/prod/10-platform/aks) to an appropriate policy set. - Policies can evolve independently from the module and stack lifecycle, provided they remain backward compatible with existing inputs.
This separation keeps the infrastructure code portable while still allowing strong governance when run through approved pipelines.
Local development vs CI¶
For local development:
- Running
terraform planorterraform applydirectly underinfra/terraform/live-v1/**is supported but not the primary interface. - Policy evaluation may be skipped locally to keep developer feedback loops short, or run via an optional wrapper script.
For CI and promotion paths (for example dev → staging → prod):
- Plans should be evaluated against OPA and/or Sentinel before apply.
- Promotion workflows should treat “policy pass” as a prerequisite, not an afterthought.
Extending the policy pack¶
When adding a new policy:
- Choose the engine
- If you are standardising on OPA in your own fork, prefer Rego.
-
If you are using Terraform Cloud/Enterprise, prefer Sentinel.
-
Keep scope narrow and explicit
- Start with a single concern (for example, “no unmanaged public IPs in prod”).
-
Avoid bundling multiple unrelated checks into one file.
-
Document the behaviour
-
Add a short header comment inside the policy file describing:
- Purpose.
- Environments affected.
- Expected failure message.
-
Update documentation
- Add a one-line entry for the new policy to this page.
- If relevant, cross-link from any ADRs or runbooks that depend on the policy.
Related documentation¶
-
Terraform platform overview – high-level view of stacks, modules, and state strategy.
See: Terraform platform overview -
Architecture Decision Records – rationale for network, secrets, and environment layout.
See: Architecture Decision Records (ADRs) -
Runbooks and HOWTOs – operational and step-by-step guidance for Terraform use.
See: Runbooks and HOWTOs