Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Conftest: Test Configs Against OPA Policies

By Kokil Thapa | Last reviewed: September 2026

Conftest: Test Configs Against OPA Policies is how you stop misconfigured Kubernetes manifests, Terraform plans, and CI YAML from reaching production. You write rules once in Rego, run conftest test locally, and wire the same check into GitLab CI or GitHub Actions. On real client projects I maintain with Git-based server config, a single bad ingress or missing resource limit has caused more downtime than application bugs. Policy-as-code closes that gap before merge.

What Is Conftest and How Does It Test Configs Against OPA Policies?

Conftest is a CLI from the Open Policy Agent (OPA) ecosystem. It evaluates structured configuration files against Rego policies without running a full OPA server. OPA is the policy engine; Conftest is the developer-friendly test runner built for config review.

Think of it as PHPUnit for infrastructure files. You supply inputs (a Kubernetes Deployment manifest, a Terraform plan JSON export, a Dockerfile). Conftest parses them into OPA's document model and asks your Rego rules: does this violate our standards?

If you already understand policy as code with Open Policy Agent, Conftest is the fastest on-ramp. Gatekeeper and Kyverno enforce policies inside a live cluster. Conftest catches problems earlier—in pre-commit hooks, pull request checks, and local terminals.

Conftest Policy Test FlowConfig FilesYAML / JSON / HCLconftest testCLI runnerRego Policiespolicy/*.regoPass / Failexit code 0 or 1Where Conftest RunsLocal devPre-commitCI pipelineRelease gateSame Rego rules at every stage — no policy driftShift-left security before cluster admission
Conftest test configs against OPA policies at every stage from laptop to CI pipeline

The mental model is simple. Input documents become input in Rego. Your policy package returns deny or violation messages. Conftest prints them and exits with a non-zero code when any deny rule matches.

How Do You Install Conftest and Set Up Your First Policy Test?

Conftest ships as a single binary. Install it on Ubuntu, macOS, or your CI runner. Pin the version in documentation so local and pipeline runs stay aligned.

Install Conftest

# Linux amd64 — check latest release tag on GitHub
CONFTEST_VERSION=0.56.0
curl -L "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz" \
  | tar xz
sudo mv conftest /usr/local/bin/
conftest --version

Official releases live on the Open Policy Agent Conftest repository. Match your OPA/Rego knowledge from our Rego policy language guide—syntax is identical.

Project layout

A minimal repo structure looks like this:

infra/
├── policy/
│   └── kubernetes.rego
├── k8s/
│   └── deployment.yaml
└── .conftestrc

Optional .conftestrc sets defaults so you type less:

policy: policy
namespace: main
output: stdout

First deny rule for Kubernetes

Save this as policy/kubernetes.rego:

package main

deny contains msg if {
  input.kind == "Deployment"
  not input.spec.template.spec.securityContext.runAsNonRoot
  msg := "Deployment must set runAsNonRoot in pod securityContext"
}

Run the test:

conftest test k8s/deployment.yaml --policy policy/

Conftest prints violations and returns exit code 1 when any deny rule fires. That exit code is what your CI job uses to block merges.

Which Input Formats Can Conftest Validate Against OPA Policies?

Conftest supports multiple parsers. You pick the parser with --parser or rely on file extension detection.

FormatTypical UseParser FlagNotes
YAMLKubernetes, Docker Compose, GitLab CIyaml (default)Most common in DevOps repos
JSONTerraform plan, AWS CloudFormationjsonExport plans with terraform show -json
HCL / Terraform.tf files directlyhcl2Static analysis before apply
DockerfileContainer build instructionsdockerfileCheck USER, FROM base images
RegoPolicy meta-testsregoTest policies with conftest verify

For mixed repos, run Conftest per directory. A pattern I've seen repeatedly on production deployments: one shared policy/ folder, multiple input paths. That mirrors how JSON vs YAML config choices split across tooling but still need one governance layer.

Use the JSON formatter tool to inspect Terraform plan exports before you write Rego against nested resource blocks. Pretty-printed JSON saves hours of guesswork.

Conftest Input FormatsYAMLJSONHCL2DockerfileOPA Document ModelUnified input.* structure for RegoRego deny / warn rulesHuman-readable violation messages
Multiple config formats normalize into OPA input for Conftest policy evaluation

How Do You Write Effective Rego Policies for Conftest?

Rego rewards small, composable rules. Start with high-impact denies: privileged containers, public S3 buckets, missing TLS, hard-coded secrets patterns.

Use deny, warn, and violation consistently

Conftest recognizes several rule prefixes:

  • deny — hard failure; exit code 1
  • warn — prints warning; still exits 0 unless you pass --fail-on-warn
  • violation — common in Gatekeeper-compatible policies

Example: require resource limits on every container in a Deployment:

package main

deny contains msg if {
  input.kind == "Deployment"
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.memory
  msg := sprintf("Container '%s' missing memory limit", [container.name])
}

Test Terraform plans as JSON

Static .tf scanning is useful. Testing the rendered plan catches what Terraform will actually apply. Export and test:

terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json
conftest test tfplan.json --policy policy/ --parser json

A deny rule for unencrypted S3 buckets:

package terraform

deny contains msg if {
  resource := input.resource_changes[_]
  resource.type == "aws_s3_bucket"
  not resource.change.after.server_side_encryption_configuration
  msg := sprintf("S3 bucket %s lacks encryption config", [resource.address])
}

This approach pairs well with ideas from testing infrastructure code with Terratest. Terratest proves behaviour; Conftest enforces organisational standards cheaply on every commit.

Policy tests with conftest verify

Write Rego tests beside your policies using conftest verify:

# policy/kubernetes_test.rego
package main

test_deny_missing_run_as_non_root if {
  deny with input as {
    "kind": "Deployment",
    "spec": {"template": {"spec": {"securityContext": {}}}}
  }
}
conftest verify --policy policy/

Policy unit tests belong in the same testing pyramid as application tests. Fast Rego tests run in milliseconds.

How Do You Run Conftest in CI/CD Pipelines?

Local passes mean nothing if CI skips policy checks. Wire Conftest into the same pipeline that runs linters and unit tests.

GitLab CI example

On sister sites I maintain with Deployer 7 and GitLab CI, a dedicated policy stage runs before deploy:

policy:conftest:
  stage: test
  image:
    name: openpolicyagent/conftest:latest
    entrypoint: [""]
  script:
    - conftest test deploy/k8s/ --policy policy/ --all-namespaces
    - conftest test infrastructure/plan.json --parser json --policy policy/
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Pin the image tag instead of latest in production pipelines. A silent Conftest upgrade can change parser behaviour overnight.

GitHub Actions snippet

- name: Install Conftest
  run: |
    curl -L https://github.com/open-policy-agent/conftest/releases/download/v0.56.0/conftest_0.56.0_Linux_x86_64.tar.gz | tar xz
    sudo mv conftest /usr/local/bin/

- name: Test configs against OPA policies
  run: conftest test ./configs --policy ./policy --output github

The --output github flag annotates pull requests with violation summaries. Developers see policy failures inline without digging through logs.

Policy Enforcement TimelineConftestPre-merge CIAdmissionGatekeeper / KyvernoRuntime auditOPA / Falco logsIncidentToo lateCost of catching a bad configCI: minutesAdmission: deploy blockedProd: hours + NPR costRun Conftest first — cheapest feedback loopPair with cluster tools from Kyverno vs OPA guide
Conftest catches policy violations earliest in the delivery pipeline before cluster admission

For cluster-side enforcement, read our Kyverno vs OPA Gatekeeper comparison. Conftest and admission controllers complement each other—they are not substitutes.

Conftest vs Other Policy-as-Code Tools: Which Should You Use?

Teams often ask whether Conftest replaces Sentinel, Checkov, or native cloud scanners. Each tool has a sweet spot.

ToolPolicy LanguageBest ForCI-Friendly
Conftest + OPARegoMulti-format configs, shared rules with GatekeeperExcellent
CheckovPython checksQuick IaC scans with built-in rulesExcellent
Sentinel (Terraform Cloud)Sentinel HCLHashiCorp-centric orgs on TFCGood (TFC only)
Kyverno CLIKyverno YAMLKubernetes-only, no RegoGood
Custom scriptsShell, PythonOne-off checksFragile at scale

Conftest wins when you need one policy language across Kubernetes, Terraform, Dockerfiles, and CI YAML. Rego has a learning curve. The payoff is portable rules and alignment with the official OPA documentation ecosystem.

Sentinel fits Terraform Cloud enterprises. See our Sentinel policy-as-code overview if you are evaluating HashiCorp's path. Many teams run Conftest in open CI and reserve Sentinel for plan-time enforcement inside Terraform Cloud.

  1. Start with 5–10 high-value deny rules your team already checks manually.
  2. Add conftest verify tests for each rule before expanding coverage.
  3. Integrate into CI on merge requests—block, do not warn-only, for security denies.
  4. Share policy repos across projects via Git submodules or a dedicated policy package.
  5. Mirror critical denies in cluster admission once CI coverage is stable.

On a production Laravel application, application-level authorization uses Laravel policies and gates. Infrastructure policy is a separate layer. Both matter. See our Laravel policies and gates guide for app auth; use Conftest for everything that ships as YAML or HCL.

When to Use ConftestNeed policy checks?Before deploy?Use Conftest in CIAt apply time?Add admission ctrlMulti-format repoK8s + TF + CI YAMLShared Rego rulesSame as GatekeeperSmall team budgetFree OSS toolingConftest: Test Configs Against OPA Policies — start here
Decision guide for adopting Conftest OPA policy testing before cluster admission tools

Common mistakes to avoid

A common mistake is writing policies against the wrong document shape. Kubernetes lists become arrays; Terraform JSON nests under resource_changes. Print input in a scratch rule during development:

print(input)  # remove before committing

Another pitfall: testing only happy paths. Every deny rule needs a conftest verify test with both passing and failing fixtures. Store fixtures under policy/test/ as small YAML snippets.

Do not duplicate every CIS benchmark on day one. Prioritise rules tied to incidents or audit findings. A team of three cannot maintain four hundred Rego lines. Expand monthly.

For regex-heavy secret detection in configs, prototype patterns in the regex tester before embedding them in Rego regex.match calls.

Key Takeaways

  • Run conftest test against YAML, JSON, HCL, and Dockerfiles with Rego policies in a policy/ directory.
  • Block merges on deny rules in CI; use warn only for rules still gaining team consensus.
  • Export Terraform plans as JSON for accurate plan-time policy checks—not just static .tf scans.
  • Write conftest verify unit tests beside policies so Rego refactors do not silently weaken guards.
  • Pair Conftest pre-merge checks with cluster admission from Gatekeeper or Kyverno for defence in depth.
  • Pin Conftest versions in CI images to avoid parser drift between local dev and pipeline runs.

People Also Ask

Does Conftest require a running OPA server?

No. Conftest embeds OPA evaluation locally. You run a single binary on your laptop or in CI. No sidecar, no cluster dependency, no network call. That is why it fits pre-commit hooks and fast pull request gates.

Can Conftest use the same Rego policies as OPA Gatekeeper?

Often yes, with adaptation. Gatekeeper ConstraintTemplates wrap Rego differently than Conftest's deny rules. Many teams maintain Conftest-native policies and port critical denies into Gatekeeper templates. The Rego logic itself transfers; the packaging differs.

What exit code does Conftest return on policy failure?

Conftest exits with code 1 when any deny or violation rule matches. Exit code 0 means pass. With --fail-on-warn, warnings also produce exit code 1. CI systems rely on this behaviour to block bad merges automatically.

Is Conftest only for Kubernetes?

No. Kubernetes is the most common use case, but Conftest supports Terraform, Dockerfiles, CloudFormation JSON, and arbitrary YAML configs including GitLab CI and GitHub Actions workflow files. Any structured config OPA can parse is fair game.

Put Conftest Guardrails on Your Next Deploy

Conftest: Test Configs Against OPA Policies gives you a repeatable gate between code review and production. The setup cost is one afternoon: install the binary, write five deny rules, add a CI job. The return is fewer midnight pages and cleaner audit trails.

If you want help wiring policy checks into GitLab CI, Terraform workflows, or Laravel deployment pipelines, explore our testing and optimization services or review how we ship reliable infra on projects like Adventure Third Pole Trek. For the full policy-as-code picture, read policy as code with OPA and Conftest and multi-cloud governance patterns.

Start with one directory of manifests and one deny rule today. Expand coverage only after the first rule survives a real pull request. That incremental path beats a big-bang policy project every time.

Ready to harden your deployment pipeline? Contact us to discuss Conftest integration, CI policy gates, and infrastructure review for your stack.

Frequently Asked Questions

Conftest is a CLI from the Open Policy Agent ecosystem that evaluates structured config files against Rego policies without running a full OPA server. You point conftest test at YAML, JSON, HCL, or Dockerfile inputs and policies in a policy/ directory. Matching deny rules print violation messages and return exit code 1, which lets CI block bad merges before anything reaches a cluster.

No. Conftest embeds OPA evaluation locally as a single binary on your laptop or CI runner. No sidecar, cluster dependency, or network call is required.

Download the release binary from the Open Policy Agent Conftest GitHub repository and pin the version, such as 0.56.0, so local and CI runs stay aligned. Create a policy/ folder with a Rego file, place config files under something like k8s/, optionally add a .conftestrc for defaults, then run conftest test k8s/deployment.yaml --policy policy/. Violations print to stdout and a non-zero exit code signals failure to your pipeline.

Conftest supports YAML for Kubernetes, Docker Compose, and GitLab CI; JSON for Terraform plan exports and CloudFormation; HCL for static Terraform .tf scanning; Dockerfile for container build instructions; and Rego for policy meta-tests via conftest verify. Pick the parser with --parser or rely on file extension detection. For mixed repos, use one shared policy/ folder and run Conftest per input directory so every format shares one governance layer.

Start with high-impact denies such as privileged containers, missing TLS, or hard-coded secret patterns. Use deny for hard failures, warn for advisory findings, and violation for Gatekeeper-compatible policies. Write small composable rules that inspect input fields directly. During development, print input with a scratch print(input) rule to confirm document shape, then remove it before committing. Every deny rule should have a conftest verify test with both passing and failing fixtures stored under policy/test/.

Export the rendered plan Terraform will apply, not just scan source files. Run terraform plan -out=tfplan.binary, then terraform show -json tfplan.binary to produce plan JSON. Test it with conftest test tfplan.json --policy policy/ --parser json. Write deny rules against input.resource_changes blocks, for example checking aws_s3_bucket resources for missing server_side_encryption_configuration. Plan-time JSON catches what Terraform actually applies, which static HCL scanning can miss.

Exit code 1 when any deny or violation rule matches. Exit code 0 means pass. With --fail-on-warn, warnings also exit 1.

In GitLab CI, add a test-stage job using the openpolicyagent/conftest image, run conftest test against manifest and plan paths with --all-namespaces, and trigger it on merge_request_event. Pin the image tag instead of latest to avoid silent parser drift. In GitHub Actions, install a pinned binary release, then run conftest test ./configs --policy ./policy --output github so violations annotate pull requests inline. Treat Conftest like linters and unit tests: if local passes but CI skips it, the gate is worthless.

Conftest with Rego wins when one policy language must cover Kubernetes, Terraform, Dockerfiles, and CI YAML, and align with OPA Gatekeeper later. Checkov suits quick IaC scans with built-in Python rules. Sentinel fits HashiCorp-centric orgs on Terraform Cloud only. Kyverno enforces Kubernetes policies inside a live cluster using YAML, not Rego. Many teams run Conftest pre-merge in open CI and reserve Sentinel for Terraform Cloud plan enforcement. Start with five to ten high-value deny rules your team already checks manually.

Often yes, with adaptation. Gatekeeper ConstraintTemplates wrap Rego differently than Conftest native deny rules, so packaging differs even when logic transfers. A practical pattern is maintaining Conftest-native policies for fast CI checks, then porting critical denies into Gatekeeper templates for cluster admission. Conftest catches problems in pre-commit hooks and pull request checks; Gatekeeper and Kyverno enforce inside the live cluster. They complement each other and are not substitutes.

No. Kubernetes is the most common use case, but Conftest also validates Terraform HCL and plan JSON, Dockerfiles, CloudFormation JSON, and arbitrary YAML including GitHub Actions and GitLab CI workflow files. Any structured config OPA can parse is valid input. On production deployments I have seen one shared policy/ folder serve multiple input paths across tooling that otherwise split between JSON and YAML formats.

conftest verify runs Rego unit tests written beside your policies, such as policy/kubernetes_test.rego, that assert deny rules fire or stay silent against known inputs. Run it with conftest verify --policy policy/. These tests belong in the same testing pyramid as application tests: they run in milliseconds and stop Rego refactors from silently weakening guards. Write both passing and failing fixtures for every deny rule before expanding coverage.

Writing policies against the wrong document shape is the biggest trap. Kubernetes lists become arrays; Terraform JSON nests under resource_changes, so assumptions about field paths fail silently until CI breaks. Another pitfall is testing only happy paths without conftest verify fixtures. Do not duplicate every CIS benchmark on day one; prioritise rules tied to real incidents or audit findings. A small team cannot maintain hundreds of Rego lines from a big-bang rollout. Expand monthly.

No. Conftest is the earliest gate between code review and production, running locally and in CI before manifests merge. Kyverno and OPA Gatekeeper enforce policies at cluster admission on live resources. Defence in depth means pairing Conftest pre-merge checks with admission controllers once CI coverage is stable. Mirror critical deny rules in both layers so a bypassed pipeline still hits cluster enforcement. Conftest stops misconfiguration before deploy; admission tools catch what slips through.

Plan about one afternoon for a working baseline: install the binary, write five deny rules covering standards your team already checks manually, add a CI job that fails on deny, and wire conftest verify tests for each rule. Pin the Conftest version in documentation and CI images so local and pipeline behaviour stay aligned. Block merges on security denies rather than warn-only. Expand coverage only after the first rule survives a real pull request, not through a big-bang policy project.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: