Infrastructure as Code Security

Infrastructure as Code brings versioning and automation benefits but introduces risks if misconfigurations are propagated automatically. Security must be shift-left for IaC.

Common Vulnerabilities in IaC

  • Hardcoded secrets: Credentials in versioned code
  • Overly permissive rules: Security groups 0.0.0.0/0
  • Unencrypted resources: S3 buckets, RDS without encryption
  • Public access: Resources exposed unnecessarily
  • Missing logging: CloudTrail, flow logs disabled
  • Weak authentication: MFA not enforced

Scanning Tools

Terraform - tfsec, Checkov, Terrascan

      # Vulnerability example - public S3 bucket
      resource "aws_s3_bucket" "bad_bucket" {
      bucket = "my-public-bucket"
      acl    = "public-read"  # [ERROR] VULNERABLE
      }
      # Fix
      resource "aws_s3_bucket" "good_bucket" {
      bucket = "my-private-bucket"
      acl    = "private"  # [OK] Secure
      server_side_encryption_configuration {
      rule {
      apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
      }
      }
      }
      versioning {
      enabled = true
      }
      }
      resource "aws_s3_bucket_public_access_block" "good_bucket" {
      bucket = aws_s3_bucket.good_bucket.id
      block_public_acls       = true
      block_public_policy     = true
      ignore_public_acls      = true
      restrict_public_buckets = true
      }
      

tfsec - Terraform Scanning

      # Install
      brew install tfsec
      # Scan Terraform files
      tfsec .
      # Specific output
      tfsec --format json --out results.json .
      # CI/CD integration
      tfsec --soft-fail . || exit 1
      

Checkov - Multi-Cloud IaC Scanner

      # Install
      pip install checkov
      # Scan Terraform
      checkov -d ./terraform
      # Scan CloudFormation
      checkov -f template.yaml
      # Scan Kubernetes manifests
      checkov -d ./k8s
      # Skip specific checks
      checkov -d . --skip-check CKV_AWS_20
      # Custom policies
      checkov -d . --external-checks-dir ./custom-policies
      

Policy as Code

Open Policy Agent (OPA)

OPA lets you write policies in the Rego language to enforce compliance:

      # deny_public_s3.rego
      package terraform.aws.s3
      deny[msg] {
      resource := input.resource_changes[_]
      resource.type == "aws_s3_bucket"
      resource.change.after.acl == "public-read"
      msg := sprintf("S3 bucket %s cannot be public", [resource.address])
      }
      deny[msg] {
      resource := input.resource_changes[_]
      resource.type == "aws_s3_bucket"
      not resource.change.after.server_side_encryption_configuration
      msg := sprintf("S3 bucket %s must have encryption enabled", [resource.address])
      }
      

Sentinel (HashiCorp)

Policy framework integrated with Terraform Cloud/Enterprise:

      # enforce-mandatory-tags.sentinel
      import "tfplan/v2" as tfplan
      mandatory_tags = ["Environment", "Owner", "Project"]
      all_resources = filter tfplan.resource_changes as _, rc {
      rc.mode is "managed"
      }
      deny_resources_without_tags = rule {
      all all_resources as _, resource {
      all mandatory_tags as tag {
      resource.change.after.tags contains tag
      }
      }
      }
      

Secrets Management in IaC

Terraform - Using AWS Secrets Manager

      # Create secret in Secrets Manager
      resource "aws_secretsmanager_secret" "db_password" {
      name = "production/db/password"
      recovery_window_in_days = 30
      }
      resource "aws_secretsmanager_secret_version" "db_password" {
      secret_id     = aws_secretsmanager_secret.db_password.id
      secret_string = random_password.db_password.result
      }
      # Reference secret (does not expose the value)
      data "aws_secretsmanager_secret_version" "db_password" {
      secret_id = aws_secretsmanager_secret.db_password.id
      }
      # Use in RDS (reference, not hardcoded value)
      resource "aws_db_instance" "main" {
      # ... other configs
      password = data.aws_secretsmanager_secret_version.db_password.secret_string
      }
      

git-secrets - Prevent Committing Secrets

      # Install git-secrets
      brew install git-secrets
      # Setup hooks for repository
      git secrets --install
      git secrets --register-aws
      # Scan commit history
      git secrets --scan-history
      # Prevent commits with secrets
      # Automatic via pre-commit hook
      

State File Security

  • Remote state: S3 + DynamoDB lock, never commit local state
  • Encryption: Server-side encryption on S3
  • Access control: Restrictive IAM policies for the state bucket
  • Versioning: Enable versioning for recovery
  • State locking: DynamoDB to prevent concurrent modifications

Secure Terraform Remote Backend

      terraform {
      backend "s3" {
      bucket         = "terraform-state-prod"
      key            = "global/s3/terraform.tfstate"
      region         = "us-east-1"
      encrypt        = true
      dynamodb_table = "terraform-state-lock"
      # MFA delete protection
      versioning {
      enabled = true
      mfa_delete = true
      }
      }
      }
      

CI/CD Integration

GitHub Actions - Secure Terraform Workflow

      name: 'Terraform Security Scan'
      on:
      pull_request:
      branches: [ main ]
      jobs:
      terraform-security:
      runs-on: ubuntu-latest
      steps:
      - uses: actions/checkout@v3
      - name: Run tfsec
      uses: aquasecurity/[email protected]
      with:
      soft_fail: false
      - name: Run Checkov
      uses: bridgecrewio/checkov-action@master
      with:
      directory: .
      framework: terraform
      output_format: sarif
      output_file_path: checkov.sarif
      - name: Upload results to GitHub Security
      uses: github/codeql-action/upload-sarif@v2
      with:
      sarif_file: checkov.sarif
      

Drift Detection

Detect manual changes outside of IaC that create security gaps:

  • Terraform Cloud: Automatic health checks
  • driftctl: Open-source drift detection
  • CloudFormation Drift Detection: Native AWS service
  • Scheduled scans: Periodic CI/CD jobs

Compliance Frameworks

  • CIS Benchmarks: Terraform modules for compliance
  • NIST 800-53: Policy packs for controls
  • PCI-DSS: Policies for payment card processing
  • HIPAA: Healthcare compliance policies
  • SOC 2: Security organization policies

Secure Terraform Modules

  • Use verified Terraform Registry modules
  • Pin module versions (do not use latest)
  • Code review of internal modules
  • Private registry for custom modules
  • Document security considerations

Best Practices

  • Peer review: Mandatory PRs for production changes
  • Plan before apply: Review proposed changes
  • Separate environments: Isolated Dev/Staging/Prod
  • Tagging strategy: Tags for governance and cost allocation
  • Least privilege: Specific IAM roles for CI/CD
  • Automated testing: Terratest for validation

Final Recommendations

IaC security must be automated and integrated into CI/CD from the start. Use multiple scanning tools (tfsec, Checkov) for complete coverage. Implement policy as code with OPA or Sentinel. Never commit secrets, use secret managers. Continuously monitor drift. IaC misconfiguration is one of the most common causes of cloud breaches.