Hamburger Cross Icon
Terraform Guardrails - Lunar Policy for Deployment And Infrastructure

Terraform Guardrails

Enforce Terraform best practices such as provider/module version pinning and remote backend configuration, plus AWS resource security checks relevant to SOC 2: encryption at rest, logging, public-access blocking, network ingress limits, WAF, GuardDuty, and VPC flow logs.

Add terraform to your lunar-config.yml:
uses: github://earthly/lunar-lib/policies/terraform@v1.0.5

Included Guardrails

This policy includes 33 guardrails that enforce standards for your deployment and infrastructure.

Guardrail

provider-versions-pinned

Requires Terraform providers to specify version constraints in required_providers. Unpinned providers can introduce breaking changes unexpectedly.

terraform providers version pinning reproducibility required_providers
View Guardrail
Guardrail

module-versions-pinned

Requires Terraform modules to use pinned versions or commit SHAs. Unpinned modules make infrastructure deployments non-reproducible.

terraform modules version pinning reproducibility
View Guardrail
Guardrail

remote-backend

Requires Terraform to use a remote backend for state management. Local state files are fragile and cannot be shared across teams.

terraform backend state management s3 gcs terraform cloud
View Guardrail
Guardrail

min-provider-versions

Enforces minimum version requirements for Terraform providers. Ensures providers meet security and compatibility baselines.

terraform providers minimum version security semver
View Guardrail
Guardrail

aws-alb-waf-enabled

Requires every internet-facing Application Load Balancer to have an AWS WAF web ACL associated. Unprotected public ALBs are exposed to common web exploits such as SQL injection and cross-site scripting.

aws waf alb application load balancer web acl soc2 owasp
View Guardrail
Guardrail

aws-cloudtrail-multi-region

Requires a multi-region CloudTrail trail that delivers events to CloudWatch Logs, so API activity is captured across every region and available for monitoring and alerting.

cloudtrail multi-region cloudwatch audit log aws api soc2
View Guardrail
Guardrail

aws-security-group-no-public-postgres

Requires that no security group allows unrestricted ingress (0.0.0.0/0 or ::/0) to the PostgreSQL port. Databases must never be reachable directly from the public internet.

security group postgresql 5432 ingress public access soc2
View Guardrail
Guardrail

aws-security-group-no-public-ssh

Requires that no security group allows unrestricted ingress (0.0.0.0/0 or ::/0) to the SSH port. SSH must be reached through a bastion or VPN, never open to the entire internet.

security group ssh port 22 ingress public access soc2
View Guardrail
Guardrail

aws-eks-control-plane-logging

Requires EKS clusters to enable control-plane logging to CloudWatch for the required log types (api, audit, authenticator, controllerManager, scheduler), giving auditable visibility into cluster activity.

eks kubernetes control plane logging cloudwatch audit soc2
View Guardrail
Guardrail

aws-elb-access-logging

Requires Elastic Load Balancers to have access logging enabled so request traffic is recorded to S3 for audit, troubleshooting, and security investigations.

elb load balancer access logging s3 logs audit soc2
View Guardrail
Guardrail

aws-ebs-snapshot-encryption

Requires EBS snapshots to be encrypted at rest. Snapshots inherit data from their source volumes and must not leave that data unencrypted when copied or shared.

ebs snapshot encryption at rest kms data protection aws soc2
View Guardrail
Guardrail

aws-ebs-volume-encryption

Requires EBS volumes (standalone and instance block devices) to be encrypted at rest, protecting data on disk with KMS-managed keys.

ebs volume encryption at rest kms ec2 disk data protection soc2
View Guardrail
Guardrail

aws-elb-https-only

Requires load balancers to enforce encrypted transport. HTTP listeners must redirect to HTTPS, and listeners must use HTTPS/TLS so traffic in transit is never sent in cleartext.

elb https tls encryption in transit load balancer listener soc2
View Guardrail
Guardrail

aws-guardduty-enabled

Requires Amazon GuardDuty to be enabled so the account has continuous threat detection across CloudTrail, VPC flow, and DNS telemetry.

guardduty threat detection aws security monitoring detector soc2
View Guardrail
Guardrail

aws-rds-cloudwatch-logging

Requires RDS instances and clusters to export database logs to CloudWatch, so engine, audit, and error logs are retained off-host for monitoring.

rds cloudwatch logs database logging log exports audit soc2
View Guardrail
Guardrail

aws-s3-block-public-access

Requires every S3 bucket to have public access fully blocked through a public access block configuration, preventing accidental public exposure of stored objects.

s3 public access block bucket security data exposure aws soc2
View Guardrail
Guardrail

aws-s3-access-logging

Requires S3 buckets to have server access logging enabled, recording every request to a logging bucket for audit and forensic purposes.

s3 server access logging audit log bucket logging aws soc2
View Guardrail
Guardrail

aws-vpc-flow-logs

Requires every VPC to have flow logs enabled, capturing accepted and rejected network traffic for security monitoring and incident response.

vpc flow logs network monitoring cloudwatch traffic audit soc2
View Guardrail
Guardrail

aws-security-group-no-public-admin-ports

Requires that no security group allows unrestricted ingress (0.0.0.0/0 or ::/0) to sensitive admin or database ports (RDP, MSSQL, Oracle, MySQL, Telnet, SMB, Elasticsearch, and more). SSH and PostgreSQL have their own dedicated checks.

security group ingress rdp mysql mssql public access soc2
View Guardrail
Guardrail

aws-rds-encryption-at-rest

Requires RDS instances and clusters to set storage_encrypted = true so database storage is encrypted at rest with KMS. Replicas and snapshot/PITR restores that inherit encryption are not flagged.

rds encryption at rest storage_encrypted kms database soc2
View Guardrail
Guardrail

aws-rds-not-publicly-accessible

Requires RDS instances to keep publicly_accessible = false so databases are not reachable directly from the public internet.

rds publicly accessible database public access network soc2
View Guardrail
Guardrail

aws-rds-snapshot-encryption

Requires RDS snapshots to be encrypted at rest. Snapshots inherit encryption from their source DB, so this verifies the referenced instance or cluster sets storage_encrypted = true.

rds snapshot encryption at rest storage_encrypted kms backup soc2
View Guardrail
Guardrail

aws-s3-encryption-at-rest

Requires every S3 bucket to declare a server-side encryption configuration, making encryption at rest an explicit and auditable choice rather than relying on the implicit default.

s3 encryption at rest sse kms bucket soc2
View Guardrail
Guardrail

aws-s3-no-static-website

Forbids S3 buckets from hosting a public static website, which would serve bucket contents directly to the internet.

s3 static website public bucket data exposure soc2
View Guardrail
Guardrail

aws-s3-no-public-acl

Forbids S3 buckets from granting public access through canned ACLs (public-read/public-read-write) or grants to the AllUsers/AuthenticatedUsers groups.

s3 acl public access bucket data exposure soc2
View Guardrail
Guardrail

aws-iam-password-min-length

Requires an IAM account password policy that enforces a minimum password length (default 14). The account password policy is a global baseline, so its absence is treated as a violation.

iam password policy minimum length account baseline credentials soc2
View Guardrail
Guardrail

aws-iam-no-direct-user-policies

Forbids attaching IAM policies (inline or managed) directly to users. Policies should be attached to groups or roles so access is granted through reviewable, reusable boundaries.

iam least privilege user policy groups roles soc2
View Guardrail
Guardrail

aws-acm-cert-dns-validation

Requires ACM certificates to use DNS validation so issuance and renewal are automatic and auditable. Imported certificates are not flagged.

acm certificate dns validation tls renewal soc2
View Guardrail
Guardrail

aws-eks-private-endpoint

Requires EKS clusters to enable private API-server endpoint access, so the control plane is reachable from within the VPC rather than only over the public internet.

eks kubernetes private endpoint api server network soc2
View Guardrail
Guardrail

aws-dynamodb-encryption

Requires DynamoDB tables to declare server-side encryption explicitly. DynamoDB is encrypted by default with an AWS-owned key; this makes encryption (optionally customer-managed) a deliberate, auditable choice.

dynamodb encryption at rest sse kms table soc2
View Guardrail
Guardrail

aws-lambda-not-public

Forbids Lambda functions from being publicly invokable through a principal "*" permission without a source scope, or a function URL with authorization_type = NONE.

lambda public access function url permission principal soc2
View Guardrail
Guardrail

aws-cloudtrail-log-file-validation

Requires CloudTrail trails to enable log-file integrity validation so tampering with delivered logs can be detected.

cloudtrail log file validation integrity audit log tamper soc2
View Guardrail
Guardrail

aws-cloudtrail-kms-encryption

Requires CloudTrail trails to encrypt delivered logs with a KMS customer-managed key.

cloudtrail kms encryption at rest audit log sse-kms soc2
View Guardrail

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
1
Integrations Gather Data
Collectors extract metadata from code, CI pipelines, tool outputs, and scans
2
{ } Centralized as JSON
All data merged into each component's unified metadata document
3
Guardrails Enforce Standards This Policy
Real-time feedback in PRs and AI workflows

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"})
ssh_port Optional 22 TCP port treated as SSH for the public-ingress check
postgres_port Optional 5432 TCP port treated as PostgreSQL for the public-ingress check
eks_required_log_types Optional api,audit,authenticator,controllerManager,scheduler Comma-separated EKS control-plane log types that must be enabled
require_cloudtrail_cloudwatch Optional true Whether CloudTrail must also deliver logs to CloudWatch Logs (true/false)
extra_admin_ports Required Additional comma-separated TCP ports to treat as sensitive for the public admin-ports check
min_password_length Optional 14 Minimum IAM account password length required by aws-iam-password-min-length

Documentation

View on GitHub

Terraform 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 also bundles a set of AWS resource security checks relevant to SOC 2 — such as encryption at rest, logging, public-access blocking, and network ingress limits — each individually includable. All checks read from .iac.native.terraform.files[] and analyze the parsed HCL. 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

The checks below are AWS resource security guardrails relevant to SOC 2 (tagged with the soc2 keyword). Each is individually includable — a future SOC 2 starter-pack can bundle them all:

Policy Description Failure Meaning
aws-alb-waf-enabled Public ALBs have a WAF web ACL associated Internet-facing aws_lb with no aws_wafv2_web_acl_association
aws-cloudtrail-multi-region CloudTrail is multi-region and ships to CloudWatch No multi-region aws_cloudtrail, or no CloudWatch Logs group
aws-security-group-no-public-postgres No public ingress to PostgreSQL A security group allows 0.0.0.0/0 to port 5432
aws-security-group-no-public-ssh No public ingress to SSH A security group allows 0.0.0.0/0 to port 22
aws-eks-control-plane-logging EKS control-plane logging enabled aws_eks_cluster missing required enabled_cluster_log_types
aws-elb-access-logging Load balancers log access requests aws_lb / aws_elb without access logging enabled
aws-ebs-snapshot-encryption EBS snapshots encrypted at rest aws_ebs_snapshot without encrypted = true
aws-ebs-volume-encryption EBS volumes encrypted at rest aws_ebs_volume or block device without encrypted = true
aws-elb-https-only Load balancers enforce HTTPS/TLS Plaintext HTTP listener without an HTTPS redirect
aws-guardduty-enabled GuardDuty detector enabled No aws_guardduty_detector with enable = true
aws-rds-cloudwatch-logging RDS exports logs to CloudWatch RDS instance/cluster without enabled_cloudwatch_logs_exports
aws-s3-block-public-access S3 buckets block public access Bucket without a full aws_s3_bucket_public_access_block
aws-s3-access-logging S3 buckets log access requests Bucket without server access logging configured
aws-vpc-flow-logs VPCs have flow logs enabled aws_vpc without a matching aws_flow_log
aws-security-group-no-public-admin-ports No public ingress to sensitive admin/database ports A security group allows 0.0.0.0/0 to a port like RDP, MySQL, MSSQL, or Telnet
aws-rds-encryption-at-rest RDS storage is encrypted at rest aws_db_instance / aws_rds_cluster without storage_encrypted = true
aws-rds-not-publicly-accessible RDS is not publicly accessible An RDS instance sets publicly_accessible = true
aws-rds-snapshot-encryption RDS snapshots encrypted at rest Snapshot whose source DB is not storage_encrypted
aws-s3-encryption-at-rest S3 buckets declare encryption at rest Bucket without a server-side encryption configuration
aws-s3-no-static-website S3 buckets do not host static websites Bucket with a website configuration (public hosting)
aws-s3-no-public-acl S3 buckets do not grant public ACL access Bucket with a public-read/public-read-write ACL or AllUsers grant
aws-iam-password-min-length IAM password policy enforces a minimum length No aws_iam_account_password_policy, or length below the minimum
aws-iam-no-direct-user-policies No IAM policies attached directly to users Inline/managed policy attached to a user instead of a group or role
aws-acm-cert-dns-validation ACM certificates use DNS validation aws_acm_certificate using EMAIL (or unset) validation
aws-eks-private-endpoint EKS clusters enable private endpoint access Cluster without endpoint_private_access / cluster_endpoint_private_access
aws-dynamodb-encryption DynamoDB tables declare encryption at rest Table without a server_side_encryption { enabled = true } block
aws-lambda-not-public Lambda functions are not publicly invokable principal = "*" permission without source scope, or function URL with authorization_type = NONE
aws-cloudtrail-log-file-validation CloudTrail validates log-file integrity Trail without enable_log_file_validation = true
aws-cloudtrail-kms-encryption CloudTrail logs encrypted with KMS Trail without kms_key_id

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:

  1. For provider-versions-pinned failures: Add version constraints to each provider in required_providers:
    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 5.0"
        }
      }
    }
    
  2. For module-versions-pinned failures: Add version to registry modules or ?ref= to git sources:
    module "vpc" {
      source  = "terraform-aws-modules/vpc/aws"
      version = "5.1.0"
    }
    
  3. For remote-backend failures: 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.

View Repository

Common Use Cases

Explore how individual guardrails work with specific integrations.

+
Provider Versions Pinned + Terraform Collector Requires Terraform providers to specify version constraints in...
+
Module Versions Pinned + Terraform Collector Requires Terraform modules to use pinned versions or commit SHAs. Unpinned...
+
Remote Backend + Terraform Collector Requires Terraform to use a remote backend for state management. Local state...
+
Min Provider Versions + Terraform Collector Enforces minimum version requirements for Terraform providers. Ensures providers...
+
Aws Alb Waf Enabled + Terraform Collector Requires every internet-facing Application Load Balancer to have an AWS WAF web...
+
Aws Cloudtrail Multi Region + Terraform Collector Requires a multi-region CloudTrail trail that delivers events to...
+
Aws Security Group No Public Postgres + Terraform Collector Requires that no security group allows unrestricted ingress (0.0.0.0/0 or ::/0)...
+
Aws Security Group No Public Ssh + Terraform Collector Requires that no security group allows unrestricted ingress (0.0.0.0/0 or ::/0)...
+
Aws Eks Control Plane Logging + Terraform Collector Requires EKS clusters to enable control-plane logging to CloudWatch for...
+
Aws Elb Access Logging + Terraform Collector Requires Elastic Load Balancers to have access logging enabled so...
+
Aws Ebs Snapshot Encryption + Terraform Collector Requires EBS snapshots to be encrypted at rest. Snapshots inherit data...
+
Aws Ebs Volume Encryption + Terraform Collector Requires EBS volumes (standalone and instance block devices) to be encrypted at...
+
Aws Elb Https Only + Terraform Collector Requires load balancers to enforce encrypted transport. HTTP listeners...
+
Aws Guardduty Enabled + Terraform Collector Requires Amazon GuardDuty to be enabled so the account has continuous threat...
+
Aws Rds Cloudwatch Logging + Terraform Collector Requires RDS instances and clusters to export database logs to CloudWatch, so...
+
Aws S3 Block Public Access + Terraform Collector Requires every S3 bucket to have public access fully blocked through a public...
+
Aws S3 Access Logging + Terraform Collector Requires S3 buckets to have server access logging enabled, recording...
+
Aws Vpc Flow Logs + Terraform Collector Requires every VPC to have flow logs enabled, capturing accepted and rejected...
+
Aws Security Group No Public Admin Ports + Terraform Collector Requires that no security group allows unrestricted ingress (0.0.0.0/0 or ::/0)...
+
Aws Rds Encryption At Rest + Terraform Collector Requires RDS instances and clusters to set storage_encrypted = true so database...
+
Aws Rds Not Publicly Accessible + Terraform Collector Requires RDS instances to keep publicly_accessible = false so databases are not...
+
Aws Rds Snapshot Encryption + Terraform Collector Requires RDS snapshots to be encrypted at rest. Snapshots inherit encryption...
+
Aws S3 Encryption At Rest + Terraform Collector Requires every S3 bucket to declare a server-side encryption configuration,...
+
Aws S3 No Static Website + Terraform Collector Forbids S3 buckets from hosting a public static website, which would...
+
Aws S3 No Public Acl + Terraform Collector Forbids S3 buckets from granting public access through canned...
+
Aws Iam Password Min Length + Terraform Collector Requires an IAM account password policy that enforces a minimum password length...
+
Aws Iam No Direct User Policies + Terraform Collector Forbids attaching IAM policies (inline or managed) directly to users. Policies...
+
Aws Acm Cert Dns Validation + Terraform Collector Requires ACM certificates to use DNS validation so issuance and renewal are...
+
Aws Eks Private Endpoint + Terraform Collector Requires EKS clusters to enable private API-server endpoint access, so...
+
Aws Dynamodb Encryption + Terraform Collector Requires DynamoDB tables to declare server-side encryption explicitly. DynamoDB...
+
Aws Lambda Not Public + Terraform Collector Forbids Lambda functions from being publicly invokable through a principal "*"...
+
Aws Cloudtrail Log File Validation + Terraform Collector Requires CloudTrail trails to enable log-file integrity validation so tampering...
+
Aws Cloudtrail Kms Encryption + Terraform Collector Requires CloudTrail trails to encrypt delivered logs with a KMS customer-managed...

Ready to Automate Your Standards?

See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Automate Now
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo