IaC Guardrails
Enforce Infrastructure as Code best practices including configuration validity, WAF protection, and destroy protection for stateful and stateless resources. Works with any IaC collector that writes to the .iac schema.
iac to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/iac@v1.0.0
Included Guardrails
This policy includes 4 guardrails that enforce standards for your deployment and infrastructure.
valid
Validates that all IaC configuration files are syntactically correct. Invalid configurations will fail deployment.
waf-protection
Requires WAF protection for internet-facing services. Checks each IaC module for public resources and verifies WAF is configured.
datastore-destroy-protection
Ensures stateful resources (databases, storage buckets, caches) have lifecycle { prevent_destroy = true } to prevent accidental data loss.
resource-destroy-protection
Ensures stateless infrastructure resources (EC2 instances, load balancers, networking) have lifecycle { prevent_destroy = true } to prevent accidental destruction of critical infrastructure.
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.
Documentation
View on GitHubIaC Guardrails
Enforces Infrastructure as Code configuration best practices.
Overview
This policy validates IaC configurations against best practices including file validity, WAF protection for internet-facing services, and destroy protection for both stateful (datastores) and stateless (compute, networking) resources. It reads normalized data from .iac.modules[] and works across IaC frameworks (Terraform, Pulumi, CloudFormation).
Policies
This policy provides the following guardrails (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
valid |
All IaC files parse successfully | File has syntax errors |
waf-protection |
Internet-facing services have WAF | Public service without WAF protection |
datastore-destroy-protection |
Stateful resources have destroy protection | Datastore missing lifecycle { prevent_destroy = true } |
resource-destroy-protection |
Stateless resources have destroy protection | Infrastructure resource missing lifecycle { prevent_destroy = true } |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.iac.files[] |
array | terraform collector |
.iac.modules[] |
array | terraform collector |
.iac.modules[].resources[] |
array | terraform collector |
.iac.modules[].analysis |
object | 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/iac@main
on: [infra]
enforcement: report-pr
# include: [valid, waf-protection, datastore-destroy-protection] # Only run specific checks
Examples
Passing Example
A component with valid Terraform, WAF-protected internet services, and protected datastores:
{
"iac": {
"files": [{"path": "main.tf", "valid": true}],
"modules": [
{
"path": "deploy/terraform",
"resources": [
{"type": "aws_db_instance", "name": "main", "category": "datastore", "has_prevent_destroy": true},
{"type": "aws_lb", "name": "api", "category": "network", "has_prevent_destroy": true, "internet_facing": true},
{"type": "aws_wafv2_web_acl", "name": "main", "category": "security"},
{"type": "aws_wafv2_web_acl_association", "name": "api", "category": "security"}
],
"analysis": {"internet_accessible": true, "has_waf": true}
}
]
}
}
Failing Example
A component with an internet-facing load balancer but no WAF, and unprotected datastores:
{
"iac": {
"files": [{"path": "main.tf", "valid": true}],
"modules": [
{
"path": "deploy/terraform",
"resources": [
{"type": "aws_db_instance", "name": "payments_db", "category": "datastore", "has_prevent_destroy": false},
{"type": "aws_instance", "name": "web", "category": "compute", "has_prevent_destroy": false},
{"type": "aws_lb", "name": "api", "category": "network", "has_prevent_destroy": false, "internet_facing": true}
],
"analysis": {"internet_accessible": true, "has_waf": false}
}
]
}
}
Failure messages:
Module 'deploy/terraform': internet-facing resources without WAF protectionModule 'deploy/terraform': stateful resources without destroy protection: aws_db_instance.payments_dbModule 'deploy/terraform': stateless resources without destroy protection: aws_instance.web, aws_lb.api
Remediation
When this policy fails, resolve it by:
- For
validfailures: Fix HCL syntax errors in the flagged.tffiles - For
waf-protectionfailures: Addaws_wafv2_web_aclandaws_wafv2_web_acl_associationresources to protect internet-facing load balancers and API gateways - For
datastore-destroy-protectionfailures: Addlifecycle { prevent_destroy = true }to database, storage, and cache resources - For
resource-destroy-protectionfailures: Addlifecycle { prevent_destroy = true }to critical infrastructure resources like EC2 instances, load balancers, and networking components
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.