Terraform Security Scanning
Introduction
Security scanning is a critical component of any Infrastructure as Code (IaC) workflow. When working with Terraform, ensuring your configuration files don't contain vulnerabilities or misconfigurations is essential before deploying to production environments. This guide introduces you to Terraform security scanning techniques and tools that integrate seamlessly into your CI/CD pipeline.
Terraform security scanning helps identify:
- Exposed secrets and credentials
- Insecure configurations
- Compliance violations
- Potential vulnerabilities
- Resource misconfigurations
By implementing security scanning in your Terraform CI/CD workflow, you can catch security issues early in the development lifecycle, reducing the risk and cost of remediating issues in production.
Understanding IaC Security Scanning
Infrastructure as Code security scanning analyzes your Terraform configuration files to identify potential security issues before they're deployed to your cloud environment.
Let's visualize where security scanning fits in a typical Terraform CI/CD pipeline:
Popular Terraform Security Scanning Tools
1. Checkov
Checkov is an open-source static code analysis tool for infrastructure as code. It scans Terraform, CloudFormation, Kubernetes, and other IaC frameworks for misconfigurations.
Installing Checkov
pip install checkov
Basic Usage
checkov -d /path/to/terraform/files
Example Output
Check: CKV_AWS_41: "Ensure no hard coded AWS access key and secret key in provider"
FAILED for resource: aws.default
File: /main.tf:1-5
1 | provider "aws" {
2 | region = "us-west-2"
3 | access_key = "AKIAIOSFODNN7EXAMPLE"
4 | secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
5 | }
2. TFSec
TFSec is specifically designed for Terraform and can detect security issues across multiple cloud providers.
Installing TFSec
brew install tfsec # For macOS
Or using Docker:
docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /src
Basic Usage
tfsec /path/to/terraform/files
Example Output
Result
│
│ AWS018
│ ────────────────────────────────────────────
│ [ERROR] Resource 'aws_security_group.allow_all' defines a security group that allows ingress from public internet
│
│ main.tf:8-17
│
│ Impact: Your port is exposed to the internet
│ Resolution: Set a more restrictive CIDR range
│
│ More Information:
│ https://tfsec.dev/docs/aws/AWS018/
3. Terrascan
Terrascan is a static code analyzer for Infrastructure as Code that supports multiple cloud providers.
Installing Terrascan
brew install terrascan # For macOS
Basic Usage
terrascan scan -d /path/to/terraform/files
Example Output
results:
violations:
- rule_name: openSSHPort
description: SSH port 22 is open to public
rule_id: AWS.SecurityGroup.NetworkSecurity.High.0094
severity: HIGH
category: Network Security
resource_name: example_security_group
resource_type: aws_security_group
file: main.tf
line: 15
Implementing Security Scanning in CI/CD
Let's look at how to integrate Terraform security scanning into different CI/CD platforms.
GitHub Actions Example
Create a file .github/workflows/terraform.yml
:
name: 'Terraform CI/CD'
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Format
id: fmt
run: terraform fmt -check
- name: Terraform Init
id: init
run: terraform init
# Security scanning with TFSec
- name: TFSec
uses: aquasecurity/tfsec-[email protected]
# Security scanning with Checkov
- name: Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: .
framework: terraform
GitLab CI/CD Example
Create a file .gitlab-ci.yml
:
stages:
- validate
- security
- plan
- apply
terraform:fmt:
stage: validate
script:
- terraform fmt -check
terraform:security:
stage: security
image:
name: bridgecrew/checkov:latest
entrypoint: ['']
script:
- checkov -d .
allow_failure: true
artifacts:
reports:
terraform: report.json
terraform:plan:
stage: plan
script:
- terraform init
- terraform plan -out=tfplan
Best Practices for Terraform Security Scanning
1. Scan Early and Often
Integrate security scanning as early as possible in your development workflow. Use pre-commit hooks to scan code before it's committed:
#!/bin/bash
# Pre-commit hook script
for file in $(git diff --cached --name-only | grep -E '\.tf$'); do
tfsec "$file"
if [ $? -ne 0 ]; then
echo "tfsec found issues in $file"
exit 1
fi
done
2. Define Custom Policies
Most security scanning tools allow you to define custom policies. For example, with Checkov you can create a custom policy file:
# custom_policy.py
from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
class NoPublicS3Buckets(BaseResourceCheck):
def __init__(self):
name = "Ensure S3 buckets are not publicly accessible"
id = "CKV_CUSTOM_1"
supported_resources = ['aws_s3_bucket']
categories = [CheckCategories.SECURITY]
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
def scan_resource_conf(self, conf):
if conf.get('acl', [''])[0] == 'public-read' or conf.get('acl', [''])[0] == 'public-read-write':
return CheckResult.FAILED
return CheckResult.PASSED
check = NoPublicS3Buckets()
3. Fail the Pipeline on Critical Issues
Configure your CI/CD pipeline to fail when critical security issues are detected. For example, in GitHub Actions:
- name: TFSec
uses: aquasecurity/tfsec-[email protected]
with:
soft_fail: false # This will make the build fail on high severity issues
4. Generate Comprehensive Reports
Most security scanning tools can generate reports in various formats. Use them to track your security posture over time:
checkov -d . --output json > security-report.json
Real-World Example: Securing AWS Infrastructure
Let's walk through a practical example of securing AWS infrastructure using Terraform security scanning.
Consider this Terraform configuration:
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "data" {
bucket = "my-important-data-bucket"
acl = "public-read" # Problematic setting!
}
resource "aws_security_group" "web" {
name = "web-sg"
description = "Allow web traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Problematic setting!
}
}
Running a security scan on this code would identify two critical issues:
- The S3 bucket is publicly readable
- SSH port 22 is open to the entire internet
After running Checkov:
checkov -f main.tf
You might see output like:
Check: CKV_AWS_20: "S3 Bucket should have all PUBLIC access blocks enabled"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:5-8
Check: CKV_AWS_24: "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22"
FAILED for resource: aws_security_group.web
File: /main.tf:10-19
To fix these issues, you would update your Terraform code:
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "data" {
bucket = "my-important-data-bucket"
}
resource "aws_s3_bucket_acl" "data_acl" {
bucket = aws_s3_bucket.data.id
acl = "private"
}
resource "aws_s3_bucket_public_access_block" "data_public_access" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_security_group" "web" {
name = "web-sg"
description = "Allow web traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"] # Restricted to internal network
}
}
Advanced Techniques
Setting Up Policy as Code
For more advanced security management, consider implementing Policy as Code using tools like Open Policy Agent (OPA) with Terraform:
provider "aws" {
region = "us-east-1"
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
module "s3_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-secure-bucket"
acl = "private"
versioning = {
enabled = true
}
server_side_encryption_configuration = {
rule = {
apply_server_side_encryption_by_default = {
sse_algorithm = "AES256"
}
}
}
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
Automated Remediation
Some scanning tools can automatically fix issues they find. For example, with Checkov:
checkov -d . --framework terraform --skip-framework cloudformation --fix
Common Security Issues in Terraform
-
Exposed Secrets
- Hard-coded API keys, passwords
- Solution: Use Terraform variables, AWS Secrets Manager, or HashiCorp Vault
-
Overly Permissive Access
- Security groups allowing traffic from 0.0.0.0/0
- Public S3 buckets
- Solution: Restrict to specific IP ranges or VPCs
-
Unencrypted Data
- Lack of encryption for databases, volumes, or S3 buckets
- Solution: Enable encryption by default for all resources
-
Missing Logging & Monitoring
- CloudTrail, VPC Flow Logs not enabled
- Solution: Add these resources to your Terraform configuration
-
Resource Misconfigurations
- Inappropriate instance sizes
- Missing tags
- Solution: Enforce consistent configuration through modules
Summary
Terraform security scanning is essential for building secure cloud infrastructure. By integrating security scanning tools into your CI/CD pipeline, you can identify and remediate security issues before they reach production.
Key takeaways:
- Security scanning should be an integral part of your Terraform workflow
- Multiple specialized tools exist for scanning Terraform code
- Integrate scanning into CI/CD pipelines to automate security checks
- Fix common issues like exposed secrets, overly permissive access, and encryption gaps
- Generate reports to track security posture over time
Exercises
-
Basic Setup
- Install Checkov and scan an existing Terraform project
- Identify and fix at least three security issues
-
CI/CD Integration
- Set up a GitHub Actions workflow with TFSec for a Terraform project
- Configure it to fail on high-severity issues
-
Custom Policy
- Create a custom policy that checks if all EC2 instances have specific required tags
- Test it against sample Terraform code
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)