Day 25 - Terraform Import for Existing AWS Resources

Today I worked on Terraform import as part of Day 25 of my AWS Terraform learning series.

In real projects, not every AWS resource starts from Terraform. Some resources are created manually from the AWS Console. Some are created by older scripts. Some are created by different teams before Infrastructure as Code is adopted.

Terraform import helps bring those existing resources into Terraform state so they can be managed going forward.

For this project, I created a few AWS resources manually first, then imported them into Terraform.

What I Built

I used three existing AWS resources:

S3 bucket
EC2 instance
Security group

These resources were created outside Terraform first. Then I wrote Terraform configuration blocks for them and used terraform import to connect those real AWS resources to Terraform state.

Architecture

The workflow is simple:

Existing AWS resources already exist in the AWS account.
Terraform configuration defines matching resource blocks.
terraform import maps those resources into Terraform state.
terraform plan checks whether the code and real infrastructure match.
Terraform manages the resources going forward.

Why Terraform Import Matters

Terraform normally manages resources from the time it creates them. But in real environments, we often inherit existing infrastructure.

Terraform import is useful when:

A company is adopting Infrastructure as Code.
Resources were created manually before Terraform was introduced.
A production resource should not be recreated.
A resource was created during troubleshooting and now needs to be managed properly.
Teams want better drift detection and consistent change control.

The important point is this: import does not create infrastructure. It only updates Terraform state so Terraform knows about the existing resource.

Terraform Configuration

I started with a normal Terraform provider and backend configuration.

terraform {
required_version = ">= 1.6.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}

backend "s3" {
bucket = "jay-terraformstate-bucket"
key = "day-25/dev/terraform.tfstate"
region = "us-east-1"
encrypt = true
use_lockfile = true
}
}

provider "aws" {
region = var.aws_region
}

Then I defined the existing resources in Terraform.

resource "aws_s3_bucket" "imported_bucket" {
bucket = var.existing_bucket_name

tags = {
Name = var.existing_bucket_name
Project = "Day25TerraformImport"
ManagedBy = "Terraform"
Environment = "dev"
}
}

I also added resource blocks for the existing security group and EC2 instance.


This screenshot should show the Terraform files before running the import commands.

Import Commands

After initializing Terraform, I ran the import commands.

terraform init
terraform validate

Then I imported the existing S3 bucket.

terraform import aws_s3_bucket.imported_bucket day25-import-demo-xxxx

Next, I imported the security group.

terraform import aws_security_group.imported_sg sg-xxxxxxxxxxxxxxxxx

Then I imported the EC2 instance.

terraform import aws_instance.imported_ec2 i-xxxxxxxxxxxxxxxxx

State Verification

After importing, I checked the Terraform state.

terraform state list

Expected output:

aws_instance.imported_ec2
aws_s3_bucket.imported_bucket
aws_security_group.imported_sg

Before import, terraform state list returned no resources because Terraform had configuration files but no state mapping to existing AWS resources. After running import commands, the resources appeared in Terraform state, confirming that Terraform now tracks and manages them.

I also checked detailed state information.

terraform state show aws_instance.imported_ec2

This helps verify that Terraform has stored the correct resource attributes.

Drift Check

The most important step after import is running:

terraform plan

This step shows whether the Terraform configuration matches the real AWS resources.

If the plan shows changes, it means the Terraform code does not fully match the existing resource. In that case, I need to update the Terraform configuration carefully until the plan becomes clean.

A good final result is:

No changes. Your infrastructure matches the configuration.

One observation was, there's 1 resource that is destroyed as per above.
I noticed that changing the security group description forced replacement.
This showed me why terraform plan is critical after import.
Imported resources should first match the real AWS configuration
before making changes.

Test Scenario

To test that Terraform can now manage the imported resources, I added a new tag:

Owner = "Jay"

Then I ran:

terraform plan
terraform apply

This proves Terraform is not just tracking the resource, but can also manage changes going forward.

Key Learnings

Terraform import is useful for bringing existing AWS resources under Infrastructure as Code.

Import does not create resources. It connects existing resources to Terraform state.

A matching Terraform resource block is required before import.

terraform state list and terraform state show help verify the import.

terraform plan is the most important validation step because it shows drift between code and real infrastructure.

Cleanup

For this project, cleanup should be handled carefully.

If these are demo resources, they can be destroyed using:

terraform destroy


But in real environments, imported resources may already be production resources. In that case, do not destroy them unless the resource owner approves it.

Conclusion

Day 25 helped me understand how Terraform can adopt existing AWS resources. This is an important real world skill because cloud environments often already have resources before Terraform is introduced.

The main lesson is to import carefully, validate state, review the plan, and only then allow Terraform to manage future changes.

Video Reference


Jay

Comments

Popular posts from this blog

ASM Integrity check failed with PRCT-1225 and PRCT-1011 errors while creating database using DBCA on Exadata 3 node RAC

Life is beautiful

Lock Tables in MariaDB