Terraform TFLint Custom Ruleset Authoring Prompt
Author a custom TFLint ruleset — .tflint.hcl config, the terraform + aws bundled rulesets, and Go rules built on the TFLint plugin SDK to enforce naming conventions and required tags, then wire it into pre-commit and CI.
- Target user
- Platform teams enforcing org-specific Terraform standards
- Difficulty
- Advanced
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a Terraform tooling engineer who has shipped a real TFLint plugin in Go and knows the difference between a bundled ruleset and a custom plugin. I will provide: - The conventions I want enforced (naming patterns, mandatory tags, banned resources/regions) - Provider(s) in use and TFLint version - Where linting runs today (local, pre-commit, CI) and how strict gating is Your job: 1. **Baseline config** — write a `.tflint.hcl` that enables the `terraform` bundled ruleset (`preset = "recommended"`) and the `aws` plugin pinned by `version` + `source`, and set `plugin` blocks correctly. Explain `tflint --init` fetching plugins. 2. **Decide: config rule vs custom plugin** — many needs (naming, deep-checking) are covered by the bundled `terraform` ruleset rules like `terraform_naming_convention` configured with a `format`/`custom` regex. Only reach for a Go plugin when no built-in rule fits. Tell me which of MY rules need code vs config. 3. **Custom Go rule** — for a genuinely custom check (e.g. "every taggable resource must carry a `cost-center` tag"), write a rule against the TFLint plugin SDK: a struct implementing `tflint.Rule` (`Name`, `Enabled`, `Severity`, `Check(runner tflint.Runner)`), using `runner.GetResourceContent` / `runner.WalkExpressions` to inspect attributes and `runner.EmitIssue` to report. Include the `main.go` that registers the ruleset via `plugin.Serve`. 4. **Build + distribute** — how to `go build` the plugin, name it `tflint-ruleset-<name>`, and reference it from `.tflint.hcl` with a local or `github.com` source so teammates get it via `tflint --init`. 5. **Wire into pre-commit** — a `.pre-commit-config.yaml` hook running `tflint` per directory, plus the CI job. 6. **Gating strategy** — DESTRUCTIVE-to-velocity warning: a false-positive custom rule set to `error` severity can BLOCK every deploy. Recommend rolling out new rules at `warning` first, promoting to `error` only after a clean baseline, and how to suppress with `tflint-ignore` comments. Output: (a) the `.tflint.hcl`, (b) config-vs-code decision per rule, (c) the Go rule + `main.go`, (d) pre-commit + CI wiring, (e) the severity rollout plan. Bias toward: built-in rules over custom code, warning-before-error rollout, and per-directory linting. --- Input template: ``` Conventions to enforce: Provider(s) + TFLint version: Where linting runs today: Gating strictness (advisory / blocking): Distribution (local build / GitHub release): ```
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
Most teams reach for a custom Go plugin when a two-line config change on the bundled terraform ruleset would do the job. This prompt forces the decision explicitly — config rule vs. compiled plugin — before any Go gets written, which is where most TFLint effort is wasted. It also treats the real hazard honestly: TFLint can’t destroy infrastructure, but a badly scoped custom rule at error severity halts every pipeline, so the prompt bakes in a warning-first rollout.
How to use it
- List the conventions you actually want enforced and paste them into the template.
- Run the prompt; implement the config-only rules first and confirm they lint clean.
- Only build the Go plugin for checks no bundled rule covers.
- Add the pre-commit hook so violations are caught before push, and mirror it in CI.
- Ship new rules as
warning, watch the baseline, then flip toerror.
Useful commands
# Install plugins declared in .tflint.hcl
tflint --init
# Lint the current module; --recursive walks nested modules
tflint --recursive
# Machine-readable output for CI annotations
tflint -f json --recursive > tflint-report.json
# Build and install a custom ruleset plugin locally
go build -o ~/.tflint.d/plugins/tflint-ruleset-org .
# Run only your custom rule to iterate quickly
tflint --enable-rule=org_required_cost_center_tag --recursive
Patterns
.tflint.hcl enabling the bundled terraform preset, the pinned aws ruleset, and a config-driven naming-convention rule (no Go required):
plugin "terraform" {
enabled = true
preset = "recommended"
}
plugin "aws" {
enabled = true
version = "0.32.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
plugin "org" {
enabled = true
version = "0.1.0"
source = "github.com/example-org/tflint-ruleset-org"
}
rule "terraform_naming_convention" {
enabled = true
format = "snake_case"
resource {
format = "snake_case"
}
}
A custom Go rule on the TFLint plugin SDK enforcing a required cost-center tag, with the main.go that serves the ruleset:
package main
import (
hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/plugin"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
)
type RequiredCostCenterTagRule struct {
tflint.DefaultRule
}
func (r *RequiredCostCenterTagRule) Name() string { return "org_required_cost_center_tag" }
func (r *RequiredCostCenterTagRule) Enabled() bool { return true }
func (r *RequiredCostCenterTagRule) Severity() tflint.Severity { return tflint.WARNING }
func (r *RequiredCostCenterTagRule) Link() string { return "" }
func (r *RequiredCostCenterTagRule) Check(runner tflint.Runner) error {
// Inspect the `tags` attribute of every aws_instance in the module.
resources, err := runner.GetResourceContent("aws_instance", &hclext.BodySchema{
Attributes: []hclext.AttributeSchema{{Name: "tags"}},
}, nil)
if err != nil {
return err
}
for _, resource := range resources.Blocks {
attr, ok := resource.Body.Attributes["tags"]
if !ok {
runner.EmitIssue(r, "missing tags block; cost-center is required", resource.DefRange)
continue
}
var tags map[string]string
if err := runner.EvaluateExpr(attr.Expr, &tags, nil); err != nil {
return err
}
if _, found := tags["cost-center"]; !found {
runner.EmitIssue(r, "resource must set the cost-center tag", attr.Expr.Range())
}
}
return nil
}
func main() {
plugin.Serve(&plugin.ServeOpts{
RuleSet: &tflint.BuiltinRuleSet{
Name: "org",
Version: "0.1.0",
Rules: []tflint.Rule{&RequiredCostCenterTagRule{}},
},
})
}
var _ hcl.Diagnostics // keep hcl import explicit for range types
Pre-commit wiring so violations are caught before code ever reaches CI:
repos:
- repo: https://github.com/terraform-linters/tflint
rev: v0.53.0
hooks:
- id: tflint
args: ["--recursive"] Related prompts
-
Terraform Pre-Commit & Linting Toolchain Prompt
Stand up a layered Terraform quality gate — fmt, validate, tflint, tfsec/checkov, terraform-docs, and trivy — wired through pre-commit so the same checks run on laptops and in CI without bikeshedding.
-
Terraform GitHub Org Management Module Prompt
Manage a GitHub organization as code with repos, teams, memberships, and branch protection via for_each, importing existing repos safely.
-
Terraform Policy Bundle Rollout Strategy Prompt
Plan the staged, versioned rollout of a policy-as-code bundle (Sentinel/OPA/conftest) across many Terraform workspaces and teams — moving rules from advisory to soft-mandatory to hard-mandatory without blocking delivery or causing mass plan failures.
-
Terraform Module Version Pinning Audit Prompt
Audit module source version constraints across a Terraform estate to eliminate unpinned, drifting, and risky references.
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.