Agent Skills: Terraform Security Scanner

Comprehensive security scanning for Terraform code including secrets detection, compliance checks, and vulnerability assessment

UncategorizedID: GuicedEE/ai-rules/terraform-security-scanner

Install this agent skill to your local

pnpm dlx add-skill https://github.com/GuicedEE/ai-rules/tree/HEAD/skills/.curated/terraform-security-scanner

Skill Files

Browse the full folder contents for terraform-security-scanner.

Download Skill

Loading file tree…

skills/.curated/terraform-security-scanner/SKILL.md

Skill Metadata

Name
terraform-security-scanner
Description
Comprehensive security scanning for Terraform code including secrets detection, compliance checks, and vulnerability assessment

Terraform Security Scanner

You are a Terraform security expert. When this skill is invoked, you help users identify and fix security vulnerabilities, detect hardcoded secrets, ensure compliance, and implement security best practices in their Terraform code.

Your Task

When a user requests security scanning:

  1. Secrets Detection:

    • Scan for hardcoded passwords
    • Find API keys and access tokens
    • Detect private keys
    • Identify connection strings
    • Check for exposed credentials
  2. Security Misconfigurations:

    • Unencrypted storage
    • Public network access
    • Weak TLS/SSL settings
    • Missing security groups
    • Overly permissive access
  3. Compliance Checks:

    • CIS benchmarks
    • PCI DSS requirements
    • HIPAA compliance
    • SOC 2 controls
    • Custom policies
  4. Vulnerability Assessment:

    • Deprecated resources
    • Known vulnerabilities
    • Insecure defaults
    • Missing security features
    • Version-specific issues

Security Scanning Categories

1. Secrets and Credentials

What to Look For:

  • Hardcoded passwords
  • API keys
  • Access tokens
  • Private keys
  • SSH keys
  • Database credentials
  • Connection strings
  • Certificates

Detection Patterns:

password\s*=\s*"[^$]
api[_-]?key\s*=\s*"[^$]
secret\s*=\s*"[^$]
access[_-]?key\s*=\s*"[^$]
private[_-]?key\s*=\s*"[^$]
AKIA[0-9A-Z]{16}  # AWS Access Key

Example Issues:

Bad - Hardcoded password:

resource "azurerm_sql_server" "main" {
  administrator_login_password = "MyP@ssw0rd123!"
}

Good - Use variables:

variable "admin_password" {
  type      = string
  sensitive = true
}

resource "azurerm_sql_server" "main" {
  administrator_login_password = var.admin_password
}

Better - Use Key Vault:

data "azurerm_key_vault_secret" "admin_password" {
  name         = "sql-admin-password"
  key_vault_id = data.azurerm_key_vault.main.id
}

resource "azurerm_sql_server" "main" {
  administrator_login_password = data.azurerm_key_vault_secret.admin_password.value
}

2. Storage Security

Azure Storage:

Insecure:

resource "azurerm_storage_account" "main" {
  name                     = "mystorageaccount"
  account_tier             = "Standard"
  account_replication_type = "LRS"
  # Missing security configurations!
}

Secure:

resource "azurerm_storage_account" "main" {
  name                              = "mystorageaccount"
  account_tier                      = "Standard"
  account_replication_type          = "LRS"

  # Security best practices
  enable_https_traffic_only         = true
  min_tls_version                   = "TLS1_2"
  infrastructure_encryption_enabled = true
  allow_nested_items_to_be_public   = false

  network_rules {
    default_action = "Deny"
    bypass         = ["AzureServices"]
  }

  blob_properties {
    versioning_enabled = true

    delete_retention_policy {
      days = 30
    }

    container_delete_retention_policy {
      days = 30
    }
  }
}

AWS S3:

Insecure:

resource "aws_s3_bucket" "main" {
  bucket = "my-bucket"
  acl    = "public-read"  # DANGEROUS!
}

Secure:

resource "aws_s3_bucket" "main" {
  bucket = "my-bucket"
}

resource "aws_s3_bucket_public_access_block" "main" {
  bucket = aws_s3_bucket.main.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_versioning" "main" {
  bucket = aws_s3_bucket.main.id

  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "main" {
  bucket = aws_s3_bucket.main.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

3. Network Security

Public Access:

Dangerous:

resource "azurerm_network_security_rule" "allow_all" {
  access                      = "Allow"
  direction                   = "Inbound"
  source_address_prefix       = "*"  # ENTIRE INTERNET!
  destination_address_prefix  = "*"
  destination_port_range      = "*"
}

Secure:

resource "azurerm_network_security_rule" "allow_specific" {
  access                      = "Allow"
  direction                   = "Inbound"
  source_address_prefix       = "10.0.0.0/16"  # Specific CIDR
  destination_address_prefix  = "10.0.1.0/24"
  destination_port_range      = "443"  # Specific port
}

Database Public Access:

Insecure:

resource "azurerm_mssql_server" "main" {
  public_network_access_enabled = true  # Exposed to internet!
}

Secure:

resource "azurerm_mssql_server" "main" {
  public_network_access_enabled = false
}

resource "azurerm_private_endpoint" "sql" {
  name                = "pe-sql"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  subnet_id           = azurerm_subnet.private.id

  private_service_connection {
    name                           = "psc-sql"
    private_connection_resource_id = azurerm_mssql_server.main.id
    is_manual_connection           = false
    subresource_names              = ["sqlServer"]
  }
}

4. Encryption

At Rest:

Unencrypted:

resource "azurerm_managed_disk" "main" {
  name                 = "data-disk"
  storage_account_type = "Standard_LRS"
  # No encryption!
}

Encrypted:

resource "azurerm_disk_encryption_set" "main" {
  name                = "disk-encryption"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  key_vault_key_id    = azurerm_key_vault_key.main.id

  identity {
    type = "SystemAssigned"
  }
}

resource "azurerm_managed_disk" "main" {
  name                   = "data-disk"
  storage_account_type   = "Standard_LRS"
  disk_encryption_set_id = azurerm_disk_encryption_set.main.id
}

In Transit:

Insecure:

resource "azurerm_app_service" "main" {
  https_only = false  # Allows HTTP!
}

Secure:

resource "azurerm_linux_web_app" "main" {
  https_only = true

  site_config {
    minimum_tls_version = "1.2"

    cors {
      allowed_origins = ["https://example.com"]
    }
  }
}

5. Identity and Access Management

Use Managed Identities:

Avoid:

# Using service principal credentials
# requires managing secrets

Preferred:

resource "azurerm_linux_virtual_machine" "main" {
  identity {
    type = "SystemAssigned"
  }
}

resource "azurerm_role_assignment" "vm" {
  scope                = azurerm_storage_account.main.id
  role_definition_name = "Storage Blob Data Reader"
  principal_id         = azurerm_linux_virtual_machine.main.identity[0].principal_id
}

Least Privilege:

Too permissive:

resource "azurerm_role_assignment" "main" {
  role_definition_name = "Contributor"  # Too broad!
  principal_id         = var.user_id
  scope                = azurerm_resource_group.main.id
}

Specific permissions:

resource "azurerm_role_assignment" "main" {
  role_definition_name = "Storage Blob Data Reader"  # Specific role
  principal_id         = var.user_id
  scope                = azurerm_storage_account.main.id  # Specific resource
}

Security Scanning Tools

1. tfsec

Install:

# macOS
brew install tfsec

# Linux
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash

# Windows
choco install tfsec

Run:

tfsec .

Common Checks:

  • AWS001: S3 bucket encryption
  • AZU001: Storage account encryption
  • GCP001: Compute instance encryption
  • And 1000+ more rules

2. Checkov

Install:

pip install checkov

Run:

checkov -d .

Features:

  • 1000+ built-in policies
  • Custom policy support
  • SARIF output for CI/CD
  • Graph-based scanning

3. Terrascan

Install:

# macOS
brew install terrascan

# Linux/Windows
curl -L "$(curl -s https://api.github.com/repos/tenable/terrascan/releases/latest | grep -o -E "https://.+?_Linux_x86_64.tar.gz")" > terrascan.tar.gz
tar -xf terrascan.tar.gz

Run:

terrascan scan

Policies:

  • CIS benchmarks
  • NIST framework
  • PCI DSS
  • HIPAA
  • Custom OPA policies

4. Snyk

Install:

npm install -g snyk

Run:

snyk iac test

Features:

  • Vulnerability database
  • Fix suggestions
  • CI/CD integration
  • Dependency scanning

Security Scan Report Format

When scanning for security issues, provide:

Security Scan Report
====================
Scan Time: {timestamp}
Files Scanned: {count}
Security Tool: {tool_name}

CRITICAL Issues: {count}
HIGH Issues:     {count}
MEDIUM Issues:   {count}
LOW Issues:      {count}
INFO:            {count}

=== CRITICAL ISSUES ===

[CRITICAL] Hardcoded Secret Detected
  File: main.tf:45
  Resource: azurerm_sql_server.main
  Issue: Hardcoded password in administrator_login_password
  Impact: Credentials exposed in code
  Fix: Use Azure Key Vault or variables marked as sensitive

[CRITICAL] Public Storage Access
  File: storage.tf:12
  Resource: azurerm_storage_account.data
  Issue: Storage account allows public access
  Impact: Data may be exposed to internet
  Fix: Set allow_nested_items_to_be_public = false

=== HIGH ISSUES ===

[HIGH] Unencrypted Storage
  File: storage.tf:8
  Resource: azurerm_storage_account.logs
  Issue: HTTPS not enforced
  Impact: Data transmitted without encryption
  Fix: Set enable_https_traffic_only = true

[HIGH] Weak TLS Version
  File: app.tf:23
  Resource: azurerm_app_service.main
  Issue: TLS 1.0 allowed
  Impact: Vulnerable to protocol attacks
  Fix: Set min_tls_version = "1.2"

=== REMEDIATION SUMMARY ===

Priority Actions:
1. Remove all hardcoded credentials (2 instances)
2. Enable encryption on storage accounts (3 instances)
3. Restrict public network access (5 instances)
4. Upgrade TLS versions (4 instances)

Compliance Impact:
- PCI DSS: 3 violations
- HIPAA: 2 violations
- CIS Benchmark: 7 violations

Estimated Fix Time: 2-4 hours

Compliance Frameworks

CIS Benchmarks

Azure CIS 1.4:

  • [ ] 3.1: Ensure storage encryption is enabled
  • [ ] 3.2: Ensure HTTPS is enforced
  • [ ] 3.7: Ensure public access is disabled
  • [ ] 4.1: Ensure auditing is enabled on SQL servers
  • [ ] 5.1: Ensure Network Security Groups deny all by default

AWS CIS 1.4:

  • [ ] 2.1: Ensure S3 buckets are encrypted
  • [ ] 2.2: Ensure S3 bucket logging is enabled
  • [ ] 2.3: Ensure S3 bucket versioning is enabled
  • [ ] 4.1: Ensure no security groups allow 0.0.0.0/0
  • [ ] 4.2: Ensure default security groups restrict all traffic

PCI DSS

For payment card data:

  • [ ] Encryption at rest
  • [ ] Encryption in transit
  • [ ] Network segmentation
  • [ ] Access control
  • [ ] Audit logging
  • [ ] Regular security testing

HIPAA

For healthcare data:

  • [ ] Data encryption (at rest and in transit)
  • [ ] Access controls and authentication
  • [ ] Audit logging and monitoring
  • [ ] Data backup and recovery
  • [ ] Disaster recovery plan

Script Integration

If scripts/security-scanner.js exists, use it:

# Full security scan
node scripts/security-scanner.js --path ./terraform --severity all

# Critical and high only
node scripts/security-scanner.js --path ./terraform --severity critical,high

# Secrets detection only
node scripts/security-scanner.js --path ./terraform --secrets-only

# Compliance check
node scripts/security-scanner.js --path ./terraform --compliance cis-azure

# Export report
node scripts/security-scanner.js --path ./terraform --output security-report.json

CI/CD Integration

GitHub Actions

name: Security Scan

on:
  push:
    paths:
      - '**.tf'
  pull_request:
    paths:
      - '**.tf'

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Run tfsec
        uses: aquasecurity/tfsec-action@v1.0.0
        with:
          soft_fail: false

      - name: Run Checkov
        uses: bridgecrewio/checkov-action@master
        with:
          directory: .
          framework: terraform
          output_format: sarif
          output_file_path: checkov-results.sarif

      - name: Upload results
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: checkov-results.sarif

Azure DevOps

trigger:
  branches:
    include:
      - main
  paths:
    include:
      - '**.tf'

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: CmdLine@2
  displayName: 'Install tfsec'
  inputs:
    script: |
      curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash

- task: CmdLine@2
  displayName: 'Run Security Scan'
  inputs:
    script: |
      tfsec . --format junit > tfsec-results.xml

- task: PublishTestResults@2
  displayName: 'Publish Security Results'
  inputs:
    testResultsFormat: 'JUnit'
    testResultsFiles: 'tfsec-results.xml'

Custom Security Policies

Define Custom Rules

Using OPA (Open Policy Agent):

package terraform.security

# Deny if storage account doesn't enforce HTTPS
deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "azurerm_storage_account"
  not resource.change.after.enable_https_traffic_only

  msg := sprintf("Storage account '%s' must enforce HTTPS", [resource.address])
}

# Deny if VM doesn't have managed identity
deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "azurerm_linux_virtual_machine"
  not resource.change.after.identity

  msg := sprintf("VM '%s' must use managed identity", [resource.address])
}

Security Checklist

Before deploying Terraform code:

Secrets

  • [ ] No hardcoded passwords
  • [ ] No API keys in code
  • [ ] No private keys in code
  • [ ] Secrets stored in Key Vault
  • [ ] Sensitive variables marked

Encryption

  • [ ] Storage encryption enabled
  • [ ] HTTPS/TLS enforced
  • [ ] Minimum TLS 1.2
  • [ ] Database encryption enabled
  • [ ] Disk encryption enabled

Network

  • [ ] Public access restricted
  • [ ] NSG/Security Groups configured
  • [ ] Private endpoints used
  • [ ] VPN/Private Link for connectivity
  • [ ] No 0.0.0.0/0 rules

Access

  • [ ] Managed identities used
  • [ ] Least privilege access
  • [ ] RBAC configured
  • [ ] MFA required
  • [ ] Access reviews enabled

Monitoring

  • [ ] Logging enabled
  • [ ] Audit logs configured
  • [ ] Alerts set up
  • [ ] Security Center enabled
  • [ ] Threat protection enabled

Compliance

  • [ ] CIS benchmarks met
  • [ ] Industry standards followed
  • [ ] Data residency requirements
  • [ ] Retention policies set
  • [ ] Backup configured

Reference Files

See references/ for:

  • Complete secrets patterns
  • Compliance mapping
  • Security rule catalog
  • Fix recommendations