Day 22: Terraform Import & Moving Resources

I'm a cloud-native enthusiast and tech blogger, sharing insights on Kubernetes, AWS, CI/CD, and Linux across my blog and Facebook page. Passionate about modern infrastructure and microservices, I aim to help others understand and leverage cloud-native technologies for scalable, efficient solutions.
Welcome to Day 22! Today you’ll learn how to bring existing infrastructure under Terraform management and how to refactor your Terraform code without destroying resources.
🎯 Today’s Goals
Import existing resources into Terraform
Move resources within the state.
Refactor configurations safely
Handle resource migrations
📥 Terraform Import
Import adds existing infrastructure to Terraform state without recreating it.
Basic Import Syntax
terraform import <resource_address> <resource_id>
Import Process
Write resource block
Import into state
Run plan to verify
Adjust configuration if needed
Example: Import EC2 Instance
# Step 1: Write resource block
resource "aws_instance" "imported" {
# Required arguments only initially
ami = "ami-12345"
instance_type = "t2.micro"
}
# Step 2: Import
terraform import aws_instance.imported i-1234567890abcdef0
# Step 3: Plan to see differences
terraform plan
# Step 4: Update configuration to match
# Add missing arguments from plan output
Common Resource Imports
# EC2 Instance
terraform import aws_instance.web i-1234567890abcdef0
# VPC
terraform import aws_vpc.main vpc-12345678
# S3 Bucket
terraform import aws_s3_bucket.data my-bucket-name
# Security Group
terraform import aws_security_group.web sg-12345678
# IAM Role
terraform import aws_iam_role.app my-app-role
# RDS Instance
terraform import aws_db_instance.database my-database
🔄 Moving Resources
Within Same State
Use terraform state mv:
# Rename resource
terraform state mv aws_instance.old aws_instance.new
# Move to module
terraform state mv aws_instance.web module.web.aws_instance.server
# Move from module
terraform state mv module.old.aws_instance.web aws_instance.web
# Move with count/index
terraform state mv 'aws_instance.web[0]' 'aws_instance.primary'
Between Different States
# Pull source statet
erraform state pull > source.tfstate
# Pull destination state
terraform state pull > dest.tfstate
🧪 Hands-On Lab
Lab 1: Import Existing Resources
main.tf:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# We'll import this later
resource "aws_s3_bucket" "imported" {
bucket = "BUCKET_NAME" # Replace after import
tags = {
Imported = "true"
}
}
# Create bucket manually first
BUCKET_NAME="import-lab-$(date +%s)"
aws s3 mb s3://$BUCKET_NAME
# Add bucket name to terraform
sed -i "s/BUCKET_NAME/$BUCKET_NAME/" main.tf
# Import the bucket
terraform import aws_s3_bucket.imported $BUCKET_NAME
# Verify
terraform plan
# Update tags
terraform apply
# Clean up
terraform destroy
Lab 2: Move Resources
main.tf:
resource "aws_instance" "old_name" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
tags = {
Name = "test-instance"
}
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
# Apply
terraform apply -auto-approve
# Rename in code
mv old_name to new_name in main.tf
# Move in state
terraform state mv aws_instance.old_name aws_instance.new_name
# Verify
terraform plan
# Should show no changes
# Clean up
terraform destroy
🔧 Import with For_Each
resource "aws_s3_bucket" "imported" {
for_each = toset([
"bucket-1",
"bucket-2",
"bucket-3"
])
bucket = each.value
}
# Import each
terraform import 'aws_s3_bucket.imported["bucket-1"]' bucket-1
terraform import 'aws_s3_bucket.imported["bucket-2"]' bucket-2
terraform import 'aws_s3_bucket.imported["bucket-3"]' bucket-3
📋 Best Practices
✅ DO:
Always back up the state before importing
terraform state pull > backup.tfstateImport in stages
Import critical resources first
Test thoroughly
Document what was imported
Use
terraform planto verifyterraform import <resource> <id>terraform plan # Should show minimal changesKeep import scripts
# import.sh #!/bin/bash terraform import aws_vpc.main vpc-12345 terraform import aws_subnet.public[0] subnet-12345 terraform import aws_subnet.public[1] subnet-67890
❌ DON’T:
Don’t import without backing up
Don’t modify state files manually
Don’t import into production without testing
Don’t forget to update configuration after import
🔍 Troubleshooting
Import Fails
# Error: resource already in state
terraform state rm aws_instance.web
terraform import aws_instance.web i-12345
# Error: resource not found
# Check resource ID is correct
aws ec2 describe-instances --instance-ids i-12345
Plan Shows Changes After Import
# Get actual resource configuration
terraform show
# Update your .tf file to match
📝 Summary
Today you learned:
✅ Importing existing resources
✅ Moving resources in state
✅ Refactoring without destruction
✅ Import blocks (Terraform 1.5+)
✅ Import best practices


