INFRASTRUCTURE AS CODE

IaC Security

Securing Infrastructure as Code - automated security scanning, policy as code, and GitOps principles for safe and auditable infrastructure.

What is IaC Security?

Infrastructure as Code (IaC) Security encompasses the processes and tools for securing your infrastructure defined in code. When you write infrastructure as code (e.g., Terraform, CloudFormation), you automatically create documentation of your infrastructure and can use tools to validate security configurations before they are ever deployed.

Why is IaC Important for Security?

Imagine your infrastructure was larger - you had development, staging, and production environments, multiple GitLab runners, database servers, and more. If everything were configured manually, problems would arise:

  • Slow configuration: Manually creating resources is time-consuming and difficult to scale
  • Inconsistency: Difficult to ensure the same configuration across environments
  • Missing documentation: Without IaC you have no record of how infrastructure was created
  • Misconfiguration risk: People make mistakes - they forget to close a port, remove an unnecessary user
  • No audit trail: Without version control you don't know who changed what and why
  • Difficult recovery: After an attack you don't know how to restore the original state

Benefits of Infrastructure as Code

  • The code itself serves as documentation of your infrastructure
  • You can use tools to validate security issues
  • Peer reviews and security audits of the code
  • Version control and audit trail of all changes
  • Fast recovery after an incident - just apply the code

GitOps Principles for IaC

GitOps is an approach where a Git repository serves as the single source of truth for your infrastructure. All changes go through pull requests, code reviews, and automated tests.

GitOps Workflow for IaC

1. Code & Version Control

All infrastructure lives in a Git repository

  • Terraform/CloudFormation/Pulumi code
  • Branch protection rules
  • Required reviews before merge

2. Automated Validation

CI pipeline automatically validates changes

  • terraform validate - syntax and structure
  • tfsec/Checkov - security scanning
  • terraform plan - preview of changes

3. Review & Approval

Human review before deployment

  • Code review from colleagues
  • Security review for critical changes
  • Approval gates in the pipeline

4. Automated Deployment

Centralized deployment through the pipeline

  • terraform apply only from the pipeline
  • Remote state management
  • Audit log of all deployments

IaC Security Scanning Tools

Open Source

tfsec

Security scanner specifically designed for Terraform code. Detects security misconfigurations.

  • 300+ built-in rules
  • Custom rules support
  • CI/CD integration
  • SARIF output format
Open Source

Checkov

Policy-as-code tool for IaC scanning - Terraform, CloudFormation, Kubernetes, and more.

  • Multi-framework support
  • 1000+ built-in policies
  • Custom policies in Python
  • Graph-based analysis
Open Source

Terrascan

Static code analyzer for Infrastructure as Code with OPA policy support.

  • 500+ policies
  • OPA Rego policies
  • Kubernetes, Docker, Terraform
  • Webhook integration
Terraform Native

terraform validate

Built-in Terraform command for syntax and structure validation.

  • Syntax validation
  • Variable references
  • Module validation
  • Provider requirements

Practical Example: CI/CD Pipeline for Terraform

# .gitlab-ci.yml - DevSecOps Pipeline for Terraform stages: - init - test - plan - deploy variables: TF_ROOT: ${CI_PROJECT_DIR}/terraform # Terraform initialization init: stage: init image: hashicorp/terraform:1.6 script: - cd $TF_ROOT - terraform init -backend-config="bucket=$TF_STATE_BUCKET" artifacts: paths: - $TF_ROOT/.terraform # Syntax validation validate: stage: test image: hashicorp/terraform:1.6 script: - cd $TF_ROOT - terraform validate allow_failure: false # Security scanning with tfsec tfsec: stage: test image: aquasec/tfsec:latest script: - tfsec $TF_ROOT --format json --out tfsec-results.json artifacts: paths: - tfsec-results.json when: always allow_failure: true # Does not block pipeline, but reports issues # Security scanning with Checkov checkov: stage: test image: bridgecrew/checkov:latest script: - checkov -d $TF_ROOT --output-file checkov-results.json --output json artifacts: paths: - checkov-results.json when: always allow_failure: true # Terraform plan plan: stage: plan image: hashicorp/terraform:1.6 script: - cd $TF_ROOT - terraform plan -out=tfplan artifacts: paths: - $TF_ROOT/tfplan dependencies: - init # Terraform apply - only on main branch with manual approval deploy: stage: deploy image: hashicorp/terraform:1.6 script: - cd $TF_ROOT - terraform apply -auto-approve tfplan dependencies: - plan when: manual only: - main environment: name: production

Example tfsec Output

# tfsec results Result #1 CRITICAL Security group rule allows ingress from public internet Location: main.tf:173 Description: Opening a security group to the public internet allows any IP address to potentially access resources behind the security group. Impact: Resources could be exposed to the public internet Resolution: Limit the CIDR blocks to known IP ranges See https://aquasecurity.github.io/tfsec/latest/checks/aws/vpc/... --- Result #2 HIGH VPC Flow Logs is not enabled Location: main.tf:45 Description: VPC Flow Logs capture information about IP traffic going to and from network interfaces in a VPC. Resolution: Enable VPC Flow Logs for audit and troubleshooting --- 8 potential problems detected (17 passed)

Secure Terraform Code - Examples

Security Group - Right vs Wrong

# WRONG - overly open security group resource "aws_security_group" "bad_example" { name = "allow-all" ingress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] # All ports open to the world! } } # RIGHT - minimum required permissions resource "aws_security_group" "good_example" { name = "app-security-group" description = "Security group for web application" vpc_id = aws_vpc.main.id # HTTPS only ingress { description = "HTTPS from internet" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } # Only necessary egress egress { description = "HTTPS outbound" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "app-sg" Environment = var.environment } }

S3 Bucket - Encryption and Access Control

# Secure S3 bucket resource "aws_s3_bucket" "secure_bucket" { bucket = "my-secure-bucket-${var.environment}" tags = { Name = "secure-bucket" Environment = var.environment } } # Block public access resource "aws_s3_bucket_public_access_block" "secure_bucket" { bucket = aws_s3_bucket.secure_bucket.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } # Enable encryption resource "aws_s3_bucket_server_side_encryption_configuration" "secure_bucket" { bucket = aws_s3_bucket.secure_bucket.id rule { apply_server_side_encryption_by_default { sse_algorithm = "aws:kms" kms_master_key_id = aws_kms_key.s3_key.arn } bucket_key_enabled = true } } # Enable versioning resource "aws_s3_bucket_versioning" "secure_bucket" { bucket = aws_s3_bucket.secure_bucket.id versioning_configuration { status = "Enabled" } } # Access logging resource "aws_s3_bucket_logging" "secure_bucket" { bucket = aws_s3_bucket.secure_bucket.id target_bucket = aws_s3_bucket.log_bucket.id target_prefix = "s3-access-logs/" }

IaC Security Best Practices - Summary

GitOps & Version Control

  • All infrastructure in a Git repository
  • Branch protection - no direct pushes to main
  • Required code reviews before merge
  • Signed commits for audit trail
  • Semantic versioning for releases

Automated Security Scanning

  • tfsec or Checkov in every PR
  • Block merge on critical findings
  • Generate reports for audit
  • Regularly update rules
  • Custom policies for your requirements

Secure Terraform Practices

  • Remote state with encryption (S3 + DynamoDB lock)
  • Sensitive values in variables, not in code
  • Use data sources instead of hardcoded values
  • Modules for reusable infrastructure
  • terraform plan review before apply

What NOT to Do

  • Hardcoded secrets in Terraform code
  • terraform apply from a local machine
  • Ignoring security scan results
  • Wildcard permissions (0.0.0.0/0 on all ports)
  • Disabled encryption for storage
  • Missing tags for audit and cost tracking