Skip to main content

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:

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

bash
pip install checkov

Basic Usage

bash
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

bash
brew install tfsec  # For macOS

Or using Docker:

bash
docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /src

Basic Usage

bash
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

bash
brew install terrascan  # For macOS

Basic Usage

bash
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:

yaml
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:

yaml
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:

bash
#!/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:

python
# 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:

yaml
- 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:

bash
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:

terraform
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:

  1. The S3 bucket is publicly readable
  2. SSH port 22 is open to the entire internet

After running Checkov:

bash
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:

terraform
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:

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:

bash
checkov -d . --framework terraform --skip-framework cloudformation --fix

Common Security Issues in Terraform

  1. Exposed Secrets

    • Hard-coded API keys, passwords
    • Solution: Use Terraform variables, AWS Secrets Manager, or HashiCorp Vault
  2. Overly Permissive Access

    • Security groups allowing traffic from 0.0.0.0/0
    • Public S3 buckets
    • Solution: Restrict to specific IP ranges or VPCs
  3. Unencrypted Data

    • Lack of encryption for databases, volumes, or S3 buckets
    • Solution: Enable encryption by default for all resources
  4. Missing Logging & Monitoring

    • CloudTrail, VPC Flow Logs not enabled
    • Solution: Add these resources to your Terraform configuration
  5. 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

  1. Basic Setup

    • Install Checkov and scan an existing Terraform project
    • Identify and fix at least three security issues
  2. CI/CD Integration

    • Set up a GitHub Actions workflow with TFSec for a Terraform project
    • Configure it to fail on high-severity issues
  3. 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! :)