
September 12, 2026
11 min read
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.
conftest test at YAML, JSON, HCL, or Dockerfile inputs and evaluating them with Rego rules under a policy/ directory. Fail the build on deny rules; pass on allow or warn-only findings.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.
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.
| Format | Typical Use | Parser Flag | Notes |
|---|---|---|---|
| YAML | Kubernetes, Docker Compose, GitLab CI | yaml (default) | Most common in DevOps repos |
| JSON | Terraform plan, AWS CloudFormation | json | Export plans with terraform show -json |
| HCL / Terraform | .tf files directly | hcl2 | Static analysis before apply |
| Dockerfile | Container build instructions | dockerfile | Check USER, FROM base images |
| Rego | Policy meta-tests | rego | Test 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.
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 1warn— prints warning; still exits 0 unless you pass--fail-on-warnviolation— 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.
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.
| Tool | Policy Language | Best For | CI-Friendly |
|---|---|---|---|
| Conftest + OPA | Rego | Multi-format configs, shared rules with Gatekeeper | Excellent |
| Checkov | Python checks | Quick IaC scans with built-in rules | Excellent |
| Sentinel (Terraform Cloud) | Sentinel HCL | HashiCorp-centric orgs on TFC | Good (TFC only) |
| Kyverno CLI | Kyverno YAML | Kubernetes-only, no Rego | Good |
| Custom scripts | Shell, Python | One-off checks | Fragile 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.
- Start with 5–10 high-value deny rules your team already checks manually.
- Add
conftest verifytests for each rule before expanding coverage. - Integrate into CI on merge requests—block, do not warn-only, for security denies.
- Share policy repos across projects via Git submodules or a dedicated policy package.
- 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.
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 testagainst YAML, JSON, HCL, and Dockerfiles with Rego policies in apolicy/directory. - Block merges on
denyrules in CI; usewarnonly for rules still gaining team consensus. - Export Terraform plans as JSON for accurate plan-time policy checks—not just static
.tfscans. - Write
conftest verifyunit 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
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.

