Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Policy as code and governance in HCP Terraform

By updated

Improve this page

terraform logo

A terraform plan can be syntactically correct yet propose dangerous changes: a forgotten m5.24xlarge instance, a database without encryption, a deployment in an unauthorised region. Policy as code automatically evaluates the plan before the apply to block violations.

What you will learn

  • What policy as code is and why it exists
  • The difference between Sentinel and OPA (Open Policy Agent)
  • The distinction between policy checks and policy evaluations
  • How policy sets and enforcement levels work
  • How to create and apply a first policy
  • The free tier's limits for policy as code

What policy as code is

Policy as code in HCP Terraform fits into a run's lifecycle, between the plan and the apply:

StepWhat happens
PlanTerraform computes the changes
Policy checks / evaluationsThe policies evaluate the plan
ApplyThe changes are applied (if the policies pass)

If a policy fails, the run is blocked and no change is applied.

Sentinel vs OPA

HCP Terraform supports two policy as code frameworks:

CriterionSentinelOPA (Rego)
Developed byHashiCorp (proprietary)CNCF (open source)
LanguageSentinel (dedicated DSL)Rego (declarative language)
EcosystemHashiCorp-specificMulti-purpose (Kubernetes, CI/CD, APIs)
Learning curveLow (simple syntax)Medium (Rego is peculiar)
Data availablePlan, state, run, organisationPlan JSON through input
Examples and librariesterraform-sentinel-policies (HashiCorp)conftest, Rego Playground
Available for freeYes (limited)Yes (limited)

HashiCorp also documents a third framework, Terraform policy, whose rules are written in HCL. It has three levels: advisory, mandatory overridable (blocking, but an authorised user can continue) and mandatory. This lesson sticks to Sentinel and OPA, and the end-of-page lab has you compare the three frameworks.

When to choose Sentinel

Sentinel fits when your organisation already lives in the HashiCorp ecosystem and wants a readable syntax from the first policy:

  • You are in a 100% HashiCorp ecosystem
  • You want a simple, readable syntax without a learning curve
  • You need access to data specific to HCP Terraform (run metadata, organisation info)

When to choose OPA

OPA fits when the same policy language must serve several tools, from the Kubernetes cluster to the CI pipeline:

  • You already use OPA for Kubernetes (Gatekeeper) or your APIs
  • You want portable policies across tools
  • Your team already masters Rego

For learning labs, Sentinel is the simplest choice.

Policy checks vs policy evaluations

This is the most important architectural distinction to understand in HCP Terraform:

TypeSupported frameworksAvailable enforcement
Policy checksSentinel onlyadvisory, soft-mandatory, hard-mandatory
Policy evaluationsSentinel and OPAadvisory, mandatory (the soft-mandatory and hard-mandatory levels are converted to mandatory)

In practice:

  • Sentinel policies can run as policy checks or as policy evaluations, depending on the policy set type chosen.
  • OPA policies run only as policy evaluations.

This distinction affects the available enforcement levels, the execution order within the run and the override possibilities.

Enforcement levels

The available enforcement levels depend on the evaluation type. The two tables below give, for each level, what happens to the run when the policy fails, and when to use it.

Sentinel policy checks

LevelBehaviour on failureUse case
AdvisoryThe run continues, a warning is shownRecommendations, non-blocking good practices
Soft-mandatoryThe run is blocked, but an authorised user can overrideImportant rules with a possible exception
Hard-mandatoryThe run is blocked, with no override unless the policy set allows itUnavoidable compliance rules (security, regulation)

Policy evaluations (Sentinel and OPA)

In policy evaluations mode, the soft-mandatory and hard-mandatory levels are converted to mandatory:

LevelBehaviour on failure
AdvisoryThe run continues, a warning is shown
MandatoryThe run is blocked, users with the Manage Policy Overrides permission can continue

Policy sets

A policy set groups policies and applies them to workspaces or projects.

Structure of a policy set

A policy set groups several policies and decides where they apply and with what severity. Read the table as the four questions to settle before creating one: which rules, on which workspaces, at which enforcement level, and from which source.

ComponentWhat it does
PoliciesThe individual rules (.sentinel or .rego files)
ScopeThe targeted workspaces or projects
EnforcementThe default level for the set's policies
SourcePolicies managed in the UI, VCS repository or API / tfe provider

Creating a policy set

  1. Prepare your policy files

    Sentinel example, requiring tags on every AWS resource:

    enforce-tags.sentinel
    import "tfplan/v2" as tfplan
    mandatory_tags = ["environment", "team", "cost-center"]
    main = rule {
    all tfplan.resource_changes as _, rc {
    rc.type is "aws_instance" implies
    all mandatory_tags as tag {
    rc.change.after.tags contains tag
    }
    }
    }

    OPA (Rego) example, limiting instance size:

    restrict-instance-size.rego
    package terraform.policies
    deny contains msg if {
    some rc in input.resource_changes
    rc.type == "aws_instance"
    rc.change.after.instance_type == "m5.24xlarge"
    msg := "m5.24xlarge instances are not allowed"
    }

    This rule follows the Rego 1.0 syntax, mandatory since OPA 1.0: the contains and if keywords are required in it. Measured with OPA 1.10.1, the old deny[msg] { form fails at parse time with `contains` keyword is required for partial set rules, and the rule above returns [] on a compliant plan and the message on a plan requesting an m5.24xlarge. Examples written before 2025 still carry the old syntax.

    For an OPA policy managed in the UI, HCP Terraform asks for a query pointing to the Rego rule to evaluate, here terraform.policies.deny. The result of this query must be an array: the policy passes when the array is empty (no violation), and fails when it holds messages.

  2. Create the policy set configuration file

    For Sentinel, create a sentinel.hcl:

    policy "enforce-tags" {
    source = "./enforce-tags.sentinel"
    enforcement_level = "soft-mandatory"
    }

    For OPA, create a policies.hcl file or use the web interface.

  3. Create the policy set in HCP Terraform

    In the web interface: Organization, then Settings, Policy Sets, Connect a new policy set.

    FieldValue
    SourcePolicies managed in the UI (for a test) or VCS / API (for production)
    FrameworkSentinel or OPA
    ScopeSpecific workspaces / Specific projects / All workspaces
  4. Test the policy

    Run a terraform plan in a targeted workspace. If the plan violates the policy:

    • In advisory: the run continues with a warning.
    • In soft-mandatory (Sentinel checks): the run is blocked, an authorised user can override.
    • In hard-mandatory (Sentinel checks): the run is blocked, and only the policy set's override option allows going past it.
    • In mandatory (policy evaluations): the run is blocked, a user with the Manage Policy Overrides permission can continue.

Common policies

Here are examples of policies frequently put in place. The last column gives the enforcement level to start from, which you then tighten as confidence in the policy grows:

PolicyWhat it checksRecommended enforcement
Mandatory tagsEvery resource has the required tagsSoft-mandatory
Allowed regionsNo deployment outside eu-west-1, eu-central-1Hard-mandatory
Encryption enabledEBS volumes, S3 buckets and RDS are encryptedHard-mandatory
Limited instance sizeNo *.24xlarge or *.metal instancesSoft-mandatory
No public IP addressesEC2 instances have no public IPHard-mandatory
Limited estimated costThe plan's cost estimate stays below a thresholdAdvisory

Policy libraries

HashiCorp provides ready-to-use policy libraries, and the OPA ecosystem offers an online sandbox to try Rego before deploying:

  • terraform-sentinel-policies (GitHub): a collection of Sentinel policies covering AWS, Azure, GCP and VMware.
  • Rego Playground: test your OPA policies online before deploying them.

Governance workflow in production

In production, a policy's lifecycle follows a structured workflow, which moves from observation to blocking only once false positives are dealt with:

  1. Develop the policy locally or in the Rego Playground.

  2. Test the policy in advisory mode on a staging workspace.

  3. Observe the results for a few days, identify false positives.

  4. Fix the policy and move to soft-mandatory (Sentinel checks) or mandatory (policy evaluations).

  5. Deploy to production in hard-mandatory (Sentinel checks only) once confidence is established.

Troubleshooting

Most blocks come from the enforcement level or the scope of the policy set, rarely from the rule itself. Find the exact message of the policy check in the run first, then follow the matching row of the table.

SymptomLikely causeSolution
Policy check: soft-mandatory failedThe plan violates a Sentinel policy (checks)Fix the configuration or ask an authorised user for an override
Policy check: hard-mandatory failedThe plan violates a blocking policy (Sentinel checks)Fix the configuration; an override only exists if the policy set allows it
Policy evaluation: mandatory failedThe plan violates a policy evaluation (Sentinel or OPA)Fix the configuration or ask for an override (Manage Policy Overrides permission)
The policy check does not appearNo policy set is attached to the workspaceCheck the policy set's scope
Error: invalid policy on uploadSyntax error in the .sentinel or .rego fileValidate the syntax locally before uploading
The VCS policy set does not updateVCS connection not configured (free tier)Upload by hand or move to the Standard plan
False positive on a policyThe policy is too strictRefine the conditions or add an exception

Put it into practice

A hard-mandatory is not unbeatable, contrary to what its name promises: the policy set setting decides, combined with the user's permission. You qualify seven runs, establish the levels of the three frameworks, and write a rule that refuses a non-compliant plan.

Key points

  • Policy as code automatically evaluates the plan between the plan and the apply. It is your last safeguard before a non-compliant change.
  • Sentinel (HashiCorp, simple syntax) and OPA (CNCF, Rego, portable) are the two historical frameworks, joined by Terraform policy (HCL). Sentinel is simpler to start with.
  • Sentinel can run as policy checks (3 levels: advisory, soft-mandatory, hard-mandatory) or as policy evaluations (2 levels: advisory, mandatory). OPA only supports policy evaluations.
  • Overriding a policy depends on the level, the user's permission and the policy set's override option: when ticked, it makes even a hard-mandatory overridable.
  • On the free edition: 1 policy set, 5 policies at most, no VCS. Enough to test and learn.
  • Roll out gradually: advisory, then mandatory / soft-mandatory, then hard-mandatory (Sentinel checks) once confidence is established.

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn