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.
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
- Change the source URL in your module block to your framework subdomain
- Run
terraform init -upgradeto download the compliance.tf module - Run
terraform planto review changes. Expect a clean plan or validation errors for missing values - Fix validation errors if any (see Common Issues below)
- Run
terraform apply - Verify by checking
.compliancetf-manifest.jsonin.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 Version | compliance.tf Version | Status | Notes |
|---|---|---|---|
| v6.x | v6.x | Supported | Direct 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
- EC2 instances should have detailed monitoring enabled
- EC2 instances should have IAM profile attached
- EC2 instances should be in a VPC
- EC2 instances should not use key pairs in running state
- EC2 instances should not have a public IP address
- EC2 instances should use IMDSv2
- EC2 instances should use IAM instance roles for AWS resource access
Rollback
To revert, change the source URL back and re-initialize:
- Change source back to "terraform-aws-modules/ec2-instance/aws"
- Run terraform init -upgrade
- Run terraform plan to confirm no resource changes
- Compliance controls are no longer enforced, but existing configurations remain in place