Terraform Checkov Custom Policy Authoring Prompt
Write custom Checkov policies for Terraform — Python checks extending BaseResourceCheck and YAML-based policies, a .checkov.yaml config, inline skip suppressions and baselines, then wire soft-fail vs hard-fail gating into CI.
- Target user
- Security/platform engineers extending IaC scanning
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are an application-security engineer who writes custom Checkov policies and knows when Python is warranted over a YAML policy. I will provide: - The control I want to enforce (e.g. "S3 buckets must have a specific tag", "no security group open to 0.0.0.0/0 on 22") - Resource type(s) and provider - Where Checkov runs (local, pre-commit, CI) and how strict gating should be Your job: 1. **Python vs YAML** — decide per control. Simple attribute assertions belong in a YAML custom policy (`definition` with `and`/`or`, `cond_type: attribute`). Anything needing logic, cross-attribute checks, or lists belongs in a Python check extending `BaseResourceCheck`. Tell me which for MY control. 2. **Python custom check** — write a class extending `checkov.terraform.checks.resource.base_resource_check.BaseResourceCheck`, with a unique `id` in a custom namespace (e.g. `CKV_ORG_1`), the `supported_resources` list, `categories`, and a `scan_resource_conf(self, conf)` that returns `CheckResult.PASSED`/`FAILED`. Remember Checkov wraps every attribute value in a list. 3. **YAML custom policy** — write the equivalent simple control as a YAML policy with `metadata.id`, `scope.provider`, and a `definition` block. 4. **`.checkov.yaml` config** — set `directory`, `external-checks-dir` (where custom checks live), `framework: terraform`, `compact`, and `output`. Explain `--external-checks-dir` vs config. 5. **Suppression + baseline** — inline `#checkov:skip=CKV_ORG_1:reason` comments for accepted risk, and `checkov --create-baseline` / `--baseline .checkov.baseline` so existing findings don't block while new ones do. 6. **Soft-fail vs hard-fail** — DESTRUCTIVE-to-velocity warning: `--soft-fail` reports without failing the build; hard-fail (default non-zero exit) BLOCKS merges. An over-strict custom policy at hard-fail can wall off every PR. Recommend soft-fail (or `--soft-fail-on` for the new rule's ID) during rollout, hard-fail after a clean baseline. Use `--hard-fail-on`/`--soft-fail-on` to gate by severity/ID. 7. **CI wiring** — the job that installs Checkov, points at `external-checks-dir`, applies the baseline, and sets the fail mode. Output: (a) Python-vs-YAML decision, (b) the Python check, (c) the YAML policy, (d) `.checkov.yaml`, (e) suppression/baseline plan, (f) CI job with the gating strategy. Bias toward: YAML for simple asserts, unique custom IDs, baseline over blanket skips, and soft-fail during rollout. --- Input template: ``` Control to enforce: Resource type(s) + provider: Where Checkov runs today: Gating (advisory / blocking): Existing findings to baseline? (y/n): ```
Run this prompt with AI
Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.
Why this prompt works
The most common Checkov mistake is writing Python for a control that a five-line YAML policy handles, and the second most common is flipping a brand-new check straight to hard-fail and walling off the entire team. This prompt forces the Python-vs-YAML decision per control and makes the rollout gating explicit — soft-fail with a baseline first, hard-fail once the codebase is clean. It also captures the one Checkov API gotcha that trips everyone: attribute values in conf are always wrapped in a list.
How to use it
- State the control precisely (resource, attribute, condition) in the template.
- Run the prompt and implement the YAML policy if the control is a plain attribute assertion.
- Drop custom checks into an
external-checks-dirand confirm Checkov discovers them. - Create a baseline so existing debt doesn’t block, and add inline skips only for genuinely accepted risk.
- Start at
--soft-fail-onfor the new ID, then promote to hard-fail.
Useful commands
# Scan a directory with custom checks loaded from a dir
checkov -d . --external-checks-dir ./policies
# Run a single custom check while iterating
checkov -d . --external-checks-dir ./policies --check CKV_ORG_1
# Establish a baseline so only NEW findings gate the build
checkov -d . --create-baseline
checkov -d . --baseline .checkov.baseline
# Report everything but never fail the build (rollout mode)
checkov -d . --external-checks-dir ./policies --soft-fail
# Gate hard only on high severity, keep the new custom rule advisory
checkov -d . --hard-fail-on HIGH --soft-fail-on CKV_ORG_1
Patterns
A Python custom check extending BaseResourceCheck — note every attribute value arrives wrapped in a list:
from checkov.common.models.enums import CheckCategories, CheckResult
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
class S3RequiresDataClassificationTag(BaseResourceCheck):
def __init__(self):
super().__init__(
name="Ensure S3 buckets carry a data-classification tag",
id="CKV_ORG_1",
categories=[CheckCategories.CONVENTION],
supported_resources=["aws_s3_bucket"],
)
def scan_resource_conf(self, conf):
# conf["tags"] is [ { ... } ] — Checkov wraps values in a list.
tags = conf.get("tags")
if not tags or not isinstance(tags[0], dict):
return CheckResult.FAILED
if "data-classification" in tags[0]:
return CheckResult.PASSED
return CheckResult.FAILED
check = S3RequiresDataClassificationTag()
The equivalent simple control as a YAML custom policy plus the .checkov.yaml config:
# policies/s3_encryption.yaml
metadata:
id: "CKV_ORG_2"
name: "S3 bucket must set force_destroy = false"
category: "GENERAL_SECURITY"
scope:
provider: "aws"
definition:
cond_type: "attribute"
resource_types:
- "aws_s3_bucket"
attribute: "force_destroy"
operator: "equals"
value: false
# .checkov.yaml
directory:
- .
framework:
- terraform
external-checks-dir:
- ./policies
compact: true
output:
- cli
- junitxml
soft-fail-on:
- CKV_ORG_1 # new check stays advisory during rollout Related prompts
-
Terraform jsonencode Policy Rendering Review Prompt
Review IAM/resource policies built with jsonencode and templatefile in Terraform for correctness, injection risk, and plan-time diff noise.
-
Terraform OIDC CI Authentication Design Prompt
Replace long-lived cloud credentials in Terraform CI pipelines with short-lived OIDC-federated identity.
-
Terraform Ephemeral Preview Environments Prompt
Design per-PR ephemeral preview environments with Terraform — unique naming/tagging, TTL auto-destroy in CI, DNS/subdomain per env, cost caps, and safe teardown on PR close without nuking the wrong workspace.
-
Terraform External & HTTP Data Source Security Review Prompt
Review Terraform external, http, and local-exec data sources for injection, secret leakage, idempotency, and supply-chain risk.
More Terraform prompts & error guides
Browse every Terraform prompt and troubleshooting guide in one place.
Reading prompts? Get all 500 in one free PDF
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.