Skip to main content

Implementing Security Best Practices

1. Using Least Privilege IAM

Resource Permission Description Notes
aws_iam_role iam:CreateRole Create an IAM role Required for creating roles with specific policies
aws_iam_policy iam:CreatePolicy Create an IAM policy Used to define permissions for roles and users
aws_iam_role_policy_attachment iam:AttachRolePolicy Attach a policy to an IAM role Assigns policies to roles for specific permissions

Example: Define a minimal IAM role with least privilege

resource "aws_iam_role" "minimal_role" {
  name = "minimal-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "minimal_role_policy" {
  role = aws_iam_role.minimal_role.name
  policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}
Note: The PowerUserAccess policy is used here as an example. In production, you should define custom policies with only the necessary permissions.
Warning: Never use AdministratorAccess policy in production environments. It grants full access to all AWS services and resources.

2. Encrypting State Files

Option Values Notes
backend "s3" Use S3 backend for state storage with encryption
encrypt true Enable server-side encryption for state files
kms_key_id "arn:aws:kms:us-east-1:123456789012:key/abcd1234-a1b2-c3d4-e5f6-7890ghij1234" KMS key ARN for encryption (optional)

Example: S3 Backend with Encryption

terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "us-east-1"
    encrypt = true
    kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/abcd1234-a1b2-c3d4-e5f6-7890ghij1234"
  }
}
Note: Ensure the IAM role or user has permissions to access the KMS key and S3 bucket.

3. Enabling State Locking

State locking in Terraform prevents concurrent operations that could lead to data corruption or inconsistent state. It ensures only one person or process can modify the state at a time.

Option Values Description
backend "s3" Specifies the backend to use for state storage, which supports state locking via DynamoDB.
dynamodb_table "terraform-locks" Name of the DynamoDB table used for state locking.
lock_table "terraform-locks" Alias for dynamodb_table, used in some backends.

Example: Enabling State Locking with S3 Backend

terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "us-west-2"

    dynamodb_table = "terraform-locks"
  }
}
Note: State locking is not enabled by default in all backends. Ensure that the backend supports state locking and configure it explicitly.

4. Validating Input Variables

Property Description Validation Rule Example
variable "instance_type" Instance type for EC2 Must be one of allowed types
validation {
  condition = contains(["t2.micro", "t3.small", "m5.large"], var.instance_type)
  error_message = "Only t2.micro, t3.small, and m5.large are allowed."
}
variable "vpc_cidr" IP range for VPC Must be valid CIDR block
validation {
  condition = can(cidrsubnet(var.vpc_cidr, 8, 0))
  error_message = "vpc_cidr must be a valid CIDR block."
}
variable "environment" Environment name Must match pattern
validation {
  condition = regex("^(dev|staging|prod)$", var.environment)
  error_message = "Environment must be dev, staging, or prod."
}

Example: Validating Input with Condition

variable "allowed_regions" {
  type = list(string)
  default = ["us-east-1", "us-west-2"]
}

variable "region" {
  type = string
  validation {
    condition = contains(var.allowed_regions, var.region)
    error_message = "Region must be one of: us-east-1, us-west-2"
  }
}
Note: Validation rules are enforced at plan time and prevent invalid configurations from being applied.

5. Using Sentinel Policies

Policy Type Description Usage Notes
Sentinel Policy as Code framework for governance Enforce compliance rules in Terraform Can be applied at plan or apply time
Policy Enforcement Level Enforcement levels (hard-mandatory, soft-advisory, or disabled) Configured in policy configuration Hard-mandatory stops execution if violated

Example: Basic Sentinel Policy

import "tfplan"

# Enforce that all resources have a specific tag
main = rule {
    all tfplan.resources where .type == "aws_instance" {
        # Check if the resource has a specific tag
        all .tags where .key == "Environment" {
            # Ensure the value is not empty
            .value != ""
        }
    }
}
Note: Sentinel policies are evaluated during the Terraform plan and apply phases, ensuring that infrastructure changes adhere to organizational standards.
Warning: Policies must be carefully designed to avoid blocking legitimate infrastructure changes. Always test policies in a non-production environment.

6. Scanning for Security Issues

Tool Description Features Integration
Terraform Cloud/Enterprise Platform for managing Terraform configurations with built-in security scanning NEW Policy as Code, automated drift detection Native integration with Terraform CLI and HCL
Checkov Static analysis tool for identifying misconfigurations in infrastructure as code Supports Terraform, CloudFormation, Kubernetes, Dockerfile CLI, GitHub Actions, GitLab CI, Jenkins
tfsec Static analysis tool focused on security best practices in Terraform configurations Open-source, checks for common security issues like exposed secrets or public S3 buckets CLI, GitHub Actions, GitLab CI, CircleCI
Snyk Security platform that includes infrastructure as code scanning capabilities Scans for vulnerabilities in IaC files and integrates with CI/CD pipelines CLI, GitHub Actions, Bitbucket Pipelines, Jenkins

Example: Using tfsec to scan a Terraform configuration

tfsec . --format json

Example: Using Checkov to scan a directory

checkov --directory ./terraform --framework terraform
Note: Ensure that your scanning tools are updated regularly to detect new security vulnerabilities and misconfigurations.

7. Implementing Network Restrictions

Resource Properties Description
aws_security_group name, vpc_id, description Defines a security group for EC2 instances or other AWS resources.
aws_security_group_rule security_group_id, type, from_port, to_port, protocol, cidr_blocks Defines rules for allowing or denying traffic to a security group.

Example: Allow HTTPS traffic only from a specific IP

resource "aws_security_group" "allow_https" {
  name        = "allow-https"
  description = "Allow HTTPS traffic from specific IP"
  vpc_id      = "vpc-12345678"
}

resource "aws_security_group_rule" "allow_https_from_ip" {
  security_group_id = aws_security_group.allow_https.id
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["203.0.113.0/24"]
}

Example: Deny all outbound traffic

resource "aws_security_group" "deny_outbound" {
  name        = "deny-outbound"
  description = "Deny all outbound traffic"
  vpc_id      = "vpc-12345678"
}

resource "aws_security_group_rule" "deny_all_outbound" {
  security_group_id = aws_security_group.deny_outbound.id
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  description       = "Deny all outbound traffic"
}
Note: By default, AWS security groups allow all outbound traffic. It's recommended to explicitly deny outbound traffic unless needed.

Key Concepts

  • Security Groups act as virtual firewalls for EC2 instances and other AWS resources.
  • Ingress Rules control incoming traffic to a resource.
  • Egress Rules control outgoing traffic from a resource.
  • Use cidr_blocks to define IP ranges that are allowed or denied access.

8. Using Private Module Registry

Feature Description Notes
module.source registry.terraform.io/organization/module-name Path to private module in the registry
module.version v1.2.3 Version constraint for module
terraform.required_providers { "aws" = { source = "hashicorp/aws", version = "~> 5.0" } } Required provider configuration

Example: Using Private Module

module "vpc" {
  source  = "registry.terraform.io/myorg/vpc"
  version = "1.2.3"

  cidr_block = "10.0.0.0/16"
  region     = "us-west-2"
}
Note: Private modules must be published to a registry that supports Terraform modules, such as registry.terraform.io or a self-hosted solution like Terraform Registry Module.
Warning: Ensure that the registry is properly secured and access is restricted to authorized users only.

9. Auditing Changes

Aspect Description Tools/Methods
Change Logs Track all changes made to infrastructure configurations terraform plan -out=tfplan followed by terraform show tfplan
Version Control Integration Ensure all changes are tracked via Git or other VCS Use git log, git diff to review changes
State File Monitoring Monitor changes to state files for unauthorized modifications Enable remote state with versioning and encryption

Example: Reviewing Terraform Plan Output

terraform plan -out=tfplan
terraform show tfplan
Note: Regularly review terraform plan outputs to understand the impact of proposed changes before applying them.
Warning: Ensure that state files are stored securely and access is restricted to authorized personnel only.

Key Points for Auditing Changes

  • Always use terraform plan before applying changes
  • Store state files in a secure, remote backend with version control
  • Integrate with CI/CD pipelines to automate change review processes

10. Implementing Drift Detection

Example: Using Terraform Cloud for Drift Detection

terraform plan -out=tfplan
terraform apply tfplan
Feature Description Status
drift_detection Enables drift detection in Terraform Cloud NEW
drift_detection_enabled Flag to enable or disable drift detection NEW
Note: Drift detection helps identify configuration inconsistencies between actual and expected infrastructure states.
Warning: Drift detection requires Terraform Cloud or Enterprise for full functionality.

Drift Detection Summary

  • Monitors infrastructure state changes
  • Reports drifts via Terraform Cloud UI or API
  • Supports automated remediation in Enterprise

Was this article helpful?