checkov -d: IaC Policy Scanning (Overview)
checkov scans infrastructure-as-code for policy and security misconfigurations, exiting non-zero on failed checks unless --soft-fail is set.
Checkov is a widely used policy-as-code scanner spanning Terraform, Kubernetes, Helm, CloudFormation, and more. This page is a brief cross-reference for the command shape; container and IaC security scanners are covered in depth in the security-scanners module.
What it does
checkov evaluates IaC against a large built-in policy set plus optional custom (Python or Rego/YAML) policies. It reports passed, failed, and skipped checks with a check id (like CKV_K8S_...) and location. By default any failed check yields a non-zero exit; --soft-fail reports without failing.
Common usage
# scan a directory (auto-detects frameworks)
checkov -d .
# limit to Kubernetes and output SARIF
checkov -d ./manifests --framework kubernetes -o sarif
# gate on specific checks only, report others softly
checkov -d . --check CKV_K8S_20,CKV_K8S_23 --soft-failOptions
| Flag | What it does |
|---|---|
| -d, --directory <path> | Directory of IaC to scan |
| -f, --file <path> | Scan a single file |
| --framework <name> | Restrict to terraform, kubernetes, helm, etc. |
| --check / --skip-check <ids> | Only run, or skip, specific check ids |
| --soft-fail | Always exit 0 (report only, do not gate) |
| -o, --output <fmt> | Output: cli, json, sarif, junitxml, github_failed_only |
In CI
Use --framework to keep runs fast and scoped, -o sarif for code scanning, and --skip-check with documented ids for deliberate exceptions instead of a blanket --soft-fail. For fuller guidance on IaC and container scanning gates, see the security-scanners module rather than duplicating it here.
Common errors in CI
Failed checks print blocks like "Check: CKV_K8S_20: ... FAILED for resource: ..." with file and line, and the run exits non-zero unless --soft-fail is set. "Error: no checks were run" often means --framework or the path excluded everything. An unexpected exit 0 despite findings usually means --soft-fail (or a soft-fail config) is active.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes