Skip to content

Migrate EC2 Instance

EC2 instance module with compliance controls for IMDSv2, detailed monitoring, EBS optimization, VPC placement, public IP restrictions, IAM instance profiles, and security group ingress rules. PCI DSS additionally requires an IAM instance role and prohibits EC2 key pairs in favor of Systems Manager Session Manager.

Minor Fixes15-30 minutes per instance

Before and After

The migration is a source URL change. Your arguments, outputs, and Terraform state remain the same.

Before (terraform-aws-modules):

module "ec2" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "~> 6.0"

  name          = "my-app-server"
  instance_type = "t3.micro"
  ami           = "ami-0123456789abcdef0"

  subnet_id = "subnet-0123456789abcdef0"

  tags = {
    Environment = "production"
  }
}

After (compliance.tf / PCI DSS v4.0):

module "ec2" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/ec2-instance/aws"
  version = "~> 6.0"

  name          = "my-app-server"
  instance_type = "t3.micro"
  ami           = "ami-0123456789abcdef0"

  subnet_id = "subnet-0123456789abcdef0"

  tags = {
    Environment = "production"
  }
}

Before (terraform-aws-modules):

module "ec2" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "~> 6.0"

  name          = "my-app-server"
  instance_type = "t3.micro"
  ami           = "ami-0123456789abcdef0"

  subnet_id = "subnet-0123456789abcdef0"

  tags = {
    Environment = "production"
  }
}

After (compliance.tf / SOC 2):

module "ec2" {
  source  = "soc2.compliance.tf/terraform-aws-modules/ec2-instance/aws"
  version = "~> 6.0"

  name          = "my-app-server"
  instance_type = "t3.micro"
  ami           = "ami-0123456789abcdef0"

  subnet_id = "subnet-0123456789abcdef0"

  tags = {
    Environment = "production"
  }
}

What Changes

  • Source URL points to compliance.tf registry
  • Compliance controls are enforced via validation rules
  • terraform plan will fail if required controls are not satisfied

What Stays the Same

  • All input variables (same interface as upstream terraform-aws-modules)
  • All output values
  • Resource addresses in Terraform state
  • Provider configuration
  • Version constraints

Step-by-Step Migration

  1. Change the source URL in your module block to your framework subdomain
  2. Run terraform init -upgrade to download the compliance.tf module
  3. Run terraform plan to review changes. Expect a clean plan or validation errors for missing values
  4. Fix validation errors if any (see Common Issues below)
  5. Run terraform apply
  6. Verify by checking .compliancetf-manifest.json in .terraform/modules/

Common Issues and Fixes

Missing IMDSv2 configuration

Cause: The ec2_instance_uses_imdsv2 control requires metadata_options.http_tokens = "required". Most existing configurations use the default (optional), which allows IMDSv1.

Fix: Add metadata_options = { http_tokens = "required" } to the module configuration.

Missing detailed monitoring

Cause: The ec2_instance_detailed_monitoring_enabled control requires monitoring = true. Default is false (basic monitoring only).

Fix: Set monitoring = true. This enables 1-minute CloudWatch metrics (additional cost applies).

Public IP associated with instance

Cause: The ec2_instance_not_publicly_accessible control requires associate_public_ip_address = false.

Fix: Set associate_public_ip_address = false. Use a load balancer or NAT gateway for outbound traffic.

Missing IAM instance role (PCI DSS only)

Cause: The ec2_instance_using_iam_instance_role control (PCI DSS v4.0) requires an IAM instance profile to be attached. This enforces least-privilege access management.

Fix: Create an IAM role and instance profile, then set iam_instance_profile = aws_iam_instance_profile.this.name.

EC2 key pair configured (PCI DSS only)

Cause: The ec2_instance_no_amazon_key_pair control (PCI DSS v4.0) flags EC2 key pairs. PCI DSS v4.0 requirements for MFA on all access and unique user identification make managing SSH key pairs impractical for compliance. AWS Systems Manager Session Manager satisfies these requirements natively.

Fix: Remove the key_name argument and use AWS Systems Manager Session Manager for instance access.

Missing EBS optimization (SOC 2 only)

Cause: The ec2_instance_ebs_optimized control (SOC 2) requires ebs_optimized = true. Most modern instance types support EBS optimization at no additional cost.

Fix: Set ebs_optimized = true. Current-generation instance types (t3, m5, c5, r5 and newer) are EBS-optimized by default at no extra cost. Older types may incur charges.

Version Compatibility

Upstream Versioncompliance.tf VersionStatusNotes
v6.xv6.xSupportedDirect swap. Adapter version constraint: >=6.0.0

State Impact

No terraform state mv needed in typical cases. Resource addresses are unchanged because compliance.tf modules use the same internal resource structure as upstream. If a compliance control adds a new resource (rare), terraform plan will show the addition.

Controls Enforced

Rollback

To revert, change the source URL back and re-initialize:

  1. Change source back to "terraform-aws-modules/ec2-instance/aws"
  2. Run terraform init -upgrade
  3. Run terraform plan to confirm no resource changes
  4. Compliance controls are no longer enforced, but existing configurations remain in place

Migration Guide | Compatibility | EC2 Instance Module