Terraform Guardrails
Enforce Terraform-specific best practices including provider version pinning, minimum provider versions, module version pinning, and remote backend configuration.
terraform to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/terraform@v1.0.0
Included Guardrails
This policy includes 4 guardrails that enforce standards for your deployment and infrastructure.
provider-versions-pinned
Requires Terraform providers to specify version constraints in required_providers. Unpinned providers can introduce breaking changes unexpectedly.
module-versions-pinned
Requires Terraform modules to use pinned versions or commit SHAs. Unpinned modules make infrastructure deployments non-reproducible.
remote-backend
Requires Terraform to use a remote backend for state management. Local state files are fragile and cannot be shared across teams.
min-provider-versions
Enforces minimum version requirements for Terraform providers. Ensures providers meet security and compatibility baselines.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
required_backend_types
|
Required | — | Comma-separated list of approved backend types (empty = any remote backend) |
min_provider_versions
|
Optional |
{}
|
JSON object mapping provider names to minimum versions (e.g., {"aws": "5.0", "random": "3.0"}) |
Documentation
View on GitHubTerraform Guardrails
Enforces Terraform-specific configuration best practices.
Overview
This policy enforces Terraform-specific standards that don't transfer to other IaC frameworks: provider version pinning, module version pinning, and remote backend usage. It reads from .iac.native.terraform.files[] and analyzes the parsed HCL to extract required_providers, module, and backend blocks. For generic IaC checks (validity, WAF, datastores), see the iac policy.
Policies
This policy provides the following guardrails (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
provider-versions-pinned |
Providers specify version constraints | Provider in required_providers has no version field |
module-versions-pinned |
Modules use pinned versions | Module missing version or ?ref= in source |
remote-backend |
Remote backend configured | No terraform { backend {} } block found |
min-provider-versions |
Providers meet minimum version requirements | Provider version constraint below required minimum |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.iac.native.terraform.files[] |
array | terraform collector |
Note: Ensure the terraform collector is configured before enabling this policy.
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/terraform@main
on: [infra]
policies:
- uses: github://earthly/lunar-lib/policies/terraform@main
on: [infra]
enforcement: report-pr
# include: [provider-versions-pinned, remote-backend] # Only run specific checks
# with:
# required_backend_types: "s3,gcs,remote" # Restrict allowed backend types
# min_provider_versions: '{"aws": "5.0", "random": "3.0"}' # Enforce minimum versions
Examples
Passing Example
A component with pinned providers, versioned modules, and a remote backend:
{
"iac": {
"native": {
"terraform": {
"files": [
{
"path": "main.tf",
"hcl": {
"terraform": [
{
"required_providers": [
{
"aws": {"source": "hashicorp/aws", "version": "~> 5.0"},
"random": {"source": "hashicorp/random", "version": ">= 3.0"}
}
],
"backend": [
{"s3": {"bucket": "my-state", "key": "state.tfstate"}}
]
}
],
"module": {
"vpc": [{"source": "terraform-aws-modules/vpc/aws", "version": "5.1.0"}]
}
}
}
]
}
}
}
}
Failing Example
A component with unpinned providers, unversioned modules, and no backend:
{
"iac": {
"native": {
"terraform": {
"files": [
{
"path": "main.tf",
"hcl": {
"terraform": [
{
"required_providers": [
{
"aws": {"source": "hashicorp/aws"},
"random": {"source": "hashicorp/random"}
}
]
}
],
"module": {
"vpc": [{"source": "terraform-aws-modules/vpc/aws"}],
"rds": [{"source": "git::https://github.com/org/tf-module.git"}]
}
}
}
]
}
}
}
}
Failure messages:
Providers without version constraints: aws, random. Add version constraints in required_providers to ensure reproducible deployments.Modules without pinned versions: vpc, rds. Add version constraints or use ?ref= to pin module sources.No backend configured. Terraform state is stored locally, which is fragile and cannot be shared across teams.
Remediation
When this policy fails, resolve it by:
- For
provider-versions-pinnedfailures: Addversionconstraints to each provider inrequired_providers:terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } - For
module-versions-pinnedfailures: Addversionto registry modules or?ref=to git sources:module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.1.0" } - For
remote-backendfailures: Configure a remote backend for shared state:terraform { backend "s3" { bucket = "my-terraform-state" key = "state.tfstate" region = "us-east-1" } }
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 100+ built-in guardrails.