Step-by-Step Guide: Importing Existing AWS Infrastructure (VPC, EC2, and S3) into Terraform Modules

Introduction
Terraform's import
feature is a powerful tool for bringing existing cloud infrastructure under the management of Infrastructure as Code (IaC). This guide will walk you through the process of importing manually provisioned AWS resources – specifically a Virtual Private Cloud (VPC) with its associated networking components (Subnet, Internet Gateway, and Route Table), an EC2 instance, and an S3 bucket – into a modular Terraform configuration.
Our goal is to achieve a state where your terraform plan
shows "No changes," signifying perfect alignment between your code and the cloud resources, and enabling a clean terraform destroy
. A key aspect of this lab involves managing two distinct security groups: the default security group automatically created with the VPC, and a custom security group specifically for the EC2 instance.
Prerequisites
Phase 1: Manual Creation in AWS Console (Precise Steps)
Create VPC and Networking Components
Create a Custom VPC
Go to VPC Dashboard > Your VPCs > Create VPC.
Choose "VPC only".
Name tag:
My-VPC
IPv4 CIDR block:
10.0.0.0/16
Click "Create VPC".
You can see the VPC has created.
Create a Public Subnet
Go to VPC Dashboard > Subnets > Create subnet.
VPC ID: Select My-VPC.
Subnet name:
Public-subnet-a
Availability Zone: ap-south-1a (or your preferred AZ in ap-south-1).
IPv4 CIDR block:
10.0.1.0/24
Click "Create subnet".
Crucial Step: Enable Auto-assign Public IP:
Select your Public-subnet-a subnet.
Go to "Actions" > "Modify auto-assign IP settings".
CHECK "Enable auto-assign public IPv4 address". Click "Save".
You can see the subnet has created.
Edit subnet settings:
Create an Internet Gateway (IGW)
Go to VPC Dashboard > Internet Gateways > Create internet gateway.
Name tag:
My-internet-gateway
Click "Create internet gateway".
Attach to VPC: Select your new IGW, go to "Actions" > "Attach to VPC". Select My-VPC.
Attach to VPC
Create a Public Route Table
Go to VPC Dashboard > Route Tables > Create route table.
Name tag:
Public-route-table-a
VPC: Select My-VPC.
Click "Create route table".
Associate with Subnet: Go to "Subnet associations" tab > "Edit subnet associations". Select your Public-subnet-a. Click "Save associations".
Associate with Subnet: Go to "Subnet associations" tab > "Edit subnet associations". Select your Public-subnet-a. Click "Save associations".
Add Internet Route: Select your Public-route-table-a. Go to "Routes" tab > "Edit routes" > "Add route".
Destination: 0.0.0.0/0
Target: Select "Internet Gateway" and choose your My-internet-gateway.
Click "Save changes".
Edit subnet associations
Edit routes
Create EC2 Instance and Security Group
Launch an EC2 Instance
Go to EC2 Dashboard > Instances > Launch instances.
Name:
My-EC2
AMI: Search for "Amazon Linux 2023 AMI" and select a valid one for ap-south-1 (e.g., ami-0d03cb826412c6b0f).
Instance type: t2.micro
Key pair (login): Choose an existing key pair or create a new one or proceed without a key pair.
Network settings:
VPC: Select My-VPC.
Subnet: Select Public-subnet-a.
Auto-assign public IP: This should show "Enable" (inherited from subnet).
Firewall (security groups): Select "Create security group".
Security group name:
My-EC2-SG
(Use this exact name).Description: Security group for My-EC2 instance (Use this exact description).
Add inbound rule: Type SSH, Source Anywhere (0.0.0.0/0).
Click "Launch instance".
You can se the EC2 has created.
Create S3 Bucket
Create an S3 Bucket
Go to S3 Dashboard > Buckets > Create bucket.
Bucket name:
my-existing-s3-bucket-name-08-july-2025
(MUST be globally unique).AWS Region: Select AP-South-1.
Block Public Access settings: Keep the default (all public access blocked).
Tags: Do NOT add any tags here. Leave this section empty.
Click "Create bucket".
You can see the S3 Bucket has created.
Phase 2: Terraform Project Setup
Project Structure
.
├── main.tf
├── variables.tf
├── terraform.tfvars
└── modules/
├── ec2/
│ ├── ec2.tf
│ └── variables.tf
├── s3/
│ ├── s3.tf
│ └── variables.tf
└── vpc/
├── vpc.tf
├── variables.tf
└── outputs.tf
Clone the Repository
https://github.com/bilal-amjad-dev/terraform-aws-module-import-vpc-ec2-s3/tree/main
Configure Terraform Variables
You can configure ami-id
for your EC2 in terraform.tfvars. I am in ap-south-1
. So, I don’t need to change.
Phase 3: Initialize and Import with Terraform
1. Initialize Terraform
terraform init
2. Import Existing AWS Resources (One by One)
Please copy the IDs of resources like this:
# 1. Import the VPC
terraform import 'module.vpc.aws_vpc.imported_vpc' 'YOUR_ACTUAL_VPC_ID_HERE'
# 2. Import the Internet Gateway
terraform import 'module.vpc.aws_internet_gateway.imported_igw' 'YOUR_ACTUAL_IGW_ID_HERE'
# 3. Import the Subnet
terraform import 'module.vpc.aws_subnet.imported_subnet' 'YOUR_ACTUAL_SUBNET_ID_HERE'
# 4. Import the Route Table
terraform import 'module.vpc.aws_route_table.imported_rt' 'YOUR_ACTUAL_RT_ID_HERE'
# 5. Import the Route Table Association (ID format: subnet-id/route-table-id)
terraform import 'module.vpc.aws_route_table_association.imported_rta' 'YOUR_ACTUAL_SUBNET_ID_HERE/YOUR_ACTUAL_RT_ID_HERE'
# 6. Import the Custom Security Group (e.g., 'My-EC2-SG')
# Find its ID in the AWS console under VPC -> Security Groups
terraform import 'module.ec2.aws_security_group.custom_sg' 'YOUR_ACTUAL_CUSTOM_SECURITY_GROUP_ID_HERE'
# 7. Import the EC2 Instance
# Use the ACTUAL EC2 INSTANCE ID here (it starts with 'i-')
terraform import 'module.ec2.aws_instance.imported_ec2' 'YOUR_ACTUAL_EC2_INSTANCE_ID_HERE'
# 8. Import the S3 Bucket
terraform import 'module.s3.aws_s3_bucket.imported_bucket' 'YOUR_ACTUAL_S3_BUCKET_NAME_HERE'
# 9. Import the Default Security Group
# Find its ID in the AWS console under VPC -> Security Groups (name "default")
terraform import 'module.vpc.aws_default_security_group.default' 'YOUR_ACTUAL_DEFAULT_SECURITY_GROUP_ID_HERE'
Phase 4: Verification and Destruction
1. Verify the Terraform Plan
terraform plan
🥳 Congratulations!. You can see the message “No changes. Your infrastructure matches the configuration.“
2. Destroy the Infrastructure
terraform destroy
Enter a value: yes
Always remember to terraform destroy
your resources to avoid unnecessary cloud costs.
Conclusion:
This guide has illuminated the essential steps of importing existing AWS infrastructure into a modular Terraform setup. By meticulously aligning your Terraform code with manually provisioned resources like the VPC, EC2 instance, S3 bucket, and their associated security groups, you've successfully brought your cloud environment under the robust, version-controlled power of Infrastructure as Code.
Achieving a "No changes" terraform plan
after import, followed by a clean terraform destroy
, demonstrates the true power of Terraform in managing the full lifecycle of your cloud assets. This practice not only provides clarity and version control for your infrastructure but also streamlines operations and ensures efficient resource decommissioning, directly contributing to significant cost savings by preventing unnecessary cloud expenditure.
Subscribe to my newsletter
Read articles from Bilal Amjad directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Bilal Amjad
Bilal Amjad
Hi, I'm Bilal Amjad, a passionate DevOps enthusiast specializing in AWS, Terraform, and Kubernetes. I create beginner-friendly tutorials on my blog (bilalamjad.hashnode.dev) and YouTube channel (@bilal-amjad-dev) to share my learning journey and help others master cloud technologies. Explore my projects on GitHub (bilal-amjad-dev) and connect with me on LinkedIn for DevOps collaboration! 🚀