terraform-security-scanner
Comprehensive security scanning for Terraform code including secrets detection, compliance checks, and vulnerability assessment
Best use case
terraform-security-scanner is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Comprehensive security scanning for Terraform code including secrets detection, compliance checks, and vulnerability assessment
Teams using terraform-security-scanner should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/terraform-security-scanner/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How terraform-security-scanner Compares
| Feature / Agent | terraform-security-scanner | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Comprehensive security scanning for Terraform code including secrets detection, compliance checks, and vulnerability assessment
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# 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**:
```regex
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:
```hcl
resource "azurerm_sql_server" "main" {
administrator_login_password = "MyP@ssw0rd123!"
}
```
✅ **Good** - Use variables:
```hcl
variable "admin_password" {
type = string
sensitive = true
}
resource "azurerm_sql_server" "main" {
administrator_login_password = var.admin_password
}
```
✅ **Better** - Use Key Vault:
```hcl
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**:
```hcl
resource "azurerm_storage_account" "main" {
name = "mystorageaccount"
account_tier = "Standard"
account_replication_type = "LRS"
# Missing security configurations!
}
```
✅ **Secure**:
```hcl
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**:
```hcl
resource "aws_s3_bucket" "main" {
bucket = "my-bucket"
acl = "public-read" # DANGEROUS!
}
```
✅ **Secure**:
```hcl
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**:
```hcl
resource "azurerm_network_security_rule" "allow_all" {
access = "Allow"
direction = "Inbound"
source_address_prefix = "*" # ENTIRE INTERNET!
destination_address_prefix = "*"
destination_port_range = "*"
}
```
✅ **Secure**:
```hcl
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**:
```hcl
resource "azurerm_mssql_server" "main" {
public_network_access_enabled = true # Exposed to internet!
}
```
✅ **Secure**:
```hcl
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**:
```hcl
resource "azurerm_managed_disk" "main" {
name = "data-disk"
storage_account_type = "Standard_LRS"
# No encryption!
}
```
✅ **Encrypted**:
```hcl
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**:
```hcl
resource "azurerm_app_service" "main" {
https_only = false # Allows HTTP!
}
```
✅ **Secure**:
```hcl
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**:
```hcl
# Using service principal credentials
# requires managing secrets
```
✅ **Preferred**:
```hcl
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**:
```hcl
resource "azurerm_role_assignment" "main" {
role_definition_name = "Contributor" # Too broad!
principal_id = var.user_id
scope = azurerm_resource_group.main.id
}
```
✅ **Specific permissions**:
```hcl
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**:
```bash
# macOS
brew install tfsec
# Linux
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash
# Windows
choco install tfsec
```
**Run**:
```bash
tfsec .
```
**Common Checks**:
- AWS001: S3 bucket encryption
- AZU001: Storage account encryption
- GCP001: Compute instance encryption
- And 1000+ more rules
### 2. Checkov
**Install**:
```bash
pip install checkov
```
**Run**:
```bash
checkov -d .
```
**Features**:
- 1000+ built-in policies
- Custom policy support
- SARIF output for CI/CD
- Graph-based scanning
### 3. Terrascan
**Install**:
```bash
# 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**:
```bash
terrascan scan
```
**Policies**:
- CIS benchmarks
- NIST framework
- PCI DSS
- HIPAA
- Custom OPA policies
### 4. Snyk
**Install**:
```bash
npm install -g snyk
```
**Run**:
```bash
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:
```bash
# 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
```yaml
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
```yaml
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):
```rego
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 recommendationsRelated Skills
terraform-validator
Validate Terraform code for syntax errors, best practices, security issues, and compliance with standards
terraform-state-manager
Analyze, inspect, and safely manipulate Terraform state files with drift detection and resource management
terraform-resource-fetch
Fetch latest Terraform provider resources and documentation from Terraform Registry
terraform-project-generator
Generate complete Terraform project structure with main.tf, variables.tf, outputs.tf, backend.tf, and terraform.tf following best practices
terraform-plan-analyzer
Parse, explain, and analyze terraform plan output for impact assessment, cost estimation, and risk evaluation
terraform-module-scaffold
Create production-ready, reusable Terraform modules with complete documentation, examples, and tests
terraform-doc-generator
Auto-generate comprehensive README.md documentation for Terraform modules with usage examples, inputs, outputs, and requirements
terraform-code-generator
Auto-generate Terraform resource blocks by fetching latest schemas from Terraform Registry in real-time
security-ownership-map
Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions.
security-compliance
Security and compliance workflow for designing defense-in-depth controls, performing threat modeling and risk assessments, and mapping mitigations to frameworks (SOC2/ISO27001/GDPR/HIPAA). Use when reviewing security posture, shipping sensitive features, preparing compliance evidence, or running a lightweight secrets scan.
security-best-practices
Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks.
skill-installer
Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos).