Import existed AWS resources into Terraform

Chaiwat Tungtongsoontorn
Tri Petch Digital
Published in
6 min readMar 20, 2024

When you heard about upgrading or maintain your existed aws resources to terraform for code versioning, your head might spin around and get cumbersome of incoming tasks to do. Before we jump right into walkthrough, I would like to explain the benefits of code versioning and why we should do it.

Benefits of code versioning for your infra as a code

  • Resources are creditable. When you write down your codes to construct your services before launching to your cloud provider, this makes your cloud construction easy at your fingertips. You ensure that no hidden resources might be created along the way.
  • Log control. You do not worry about what did you do yesterday or someone in your team did yesterday because logging history your might familiar with your repository source code to conduct your application. This does the same way. We know what is going on before and later of your infrastructure before making any mistake.

Two main reasons are enough for you to get your infrastructure transform into code versioning. Next We are going to get your existed infrastructure and write it down into your codes. Let’s get started it.

Step to import your existed AWS resources

  1. First thing first, create your empty folder for your codes base with this linux command and go into that directory.
$ mkdir <WHAT_EVER_YOUR_DIRECTORY_NAME> && cd <WHAT_EVER_YOUR_DIRECTORY_NAME>

2. Create your main terraform file to config your AWS profile for access your AWS’s resources by creating main.tf file.
For looking up to your AWS profile, you might cat your file with this command $ cat ./aws/credentials

Then insert and replace your aws_profile into your main.tf file

terraform {
required_version = "~> 1.5"

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

provider "aws" {
region = "<YOUR_REGION>"
profile = "<YOUR_AWS_PROFILE>"
}

Example

terraform {
required_version = "~> 1.5"

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

provider "aws" {
region = "ap-southeast-1"
profile = "my_aws_profile"
}

3. Before you import your resources, I recommended that you need to write down what are your mandatory resources to support your services first. Then write it down into your commented code first for example. Let start with create file name import.tf

# vpc
# gateway
# public route table
# aws network acl
# aws security group
# aws public subnet
# ec2

3. Then when you defined your mandatory resources then use this terraform directive to import your existed resources with

import {
id = "<YOUR_RESOURCE_ID"
to = <HCL_ARG>.<YOUR_ARG_NAME>
}

# Example

import {
id = "vpc-05e03b9f67146a929"
to = aws_vpc.vpc.my_vpc
}

4. Fill your HCL with entire your file with your AWS’s resource IDs. It looks like

# vpc
import {
id = "vpc-05e03b9f67146a929"
to = aws_vpc.vpc
}

# gateway
import {
id = "igw-063977e33d896ce8c"
to = aws_internet_gateway.gw
}

# public route table
import {
id = "rtb-05f13f5d6baa5bd5b"
to = aws_route_table.pb_rtb
}

# aws network acl
import {
id = "acl-0a2601737a1e300bd"
to = aws_network_acl.ntw_acl
}

# aws security group
import {
id = "sg-0cd80e91b45512dc4"
to = aws_security_group.ntw_sg
}

# aws public subnet
import {
id = "subnet-03bb7402cdbdc5ff4"
to = aws_subnet.pb_subnet
}

# ec2
import {
id = "i-0ceae60691de1cbe7"
to = aws_instance.ec2
}

5. Run terraform command to import with these command orderly.

$ terraform init
$ terraform plan -generate-config-out=<WHATEVER_YOUR_SCRIPT_NAME>.tf

🌈🌈🌈🌈 Tadaaaa 🌈🌈🌈🌈

Now we got the new file which has HCL codes inside that file as figure below. Furthermore you must adjust your codes for your implementation.

# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform
resource "aws_vpc" "vpc" {
assign_generated_ipv6_cidr_block = false
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
enable_network_address_usage_metrics = false
instance_tenancy = "default"
ipv4_ipam_pool_id = null
ipv4_netmask_length = null
ipv6_cidr_block = null
ipv6_cidr_block_network_border_group = null
ipv6_ipam_pool_id = null
tags = {
Name = "tmp-vpc-terraform-vpc"
}
tags_all = {
Name = "tmp-vpc-terraform-vpc"
}
}

# __generated__ by Terraform from "igw-063977e33d896ce8c"
resource "aws_internet_gateway" "gw" {
tags = {
Name = "tmp-vpc-terraform-igw"
}
tags_all = {
Name = "tmp-vpc-terraform-igw"
}
vpc_id = vpc.id
}

# __generated__ by Terraform
resource "aws_route_table" "pb_rtb" {
propagating_vgws = []
route = [{
carrier_gateway_id = ""
cidr_block = "0.0.0.0/0"
core_network_arn = ""
destination_prefix_list_id = ""
egress_only_gateway_id = ""
gateway_id = gw.id
ipv6_cidr_block = ""
local_gateway_id = ""
nat_gateway_id = ""
network_interface_id = ""
transit_gateway_id = ""
vpc_endpoint_id = ""
vpc_peering_connection_id = ""
}]
tags = {
Name = "tmp-vpc-terraform-rtb-public"
}
tags_all = {
Name = "tmp-vpc-terraform-rtb-public"
}
vpc_id = vpc.id
}

# __generated__ by Terraform from "sg-0cd80e91b45512dc4"
resource "aws_security_group" "ntw_sg" {
description = "SG Group for EC2"
egress = [{
cidr_blocks = ["0.0.0.0/0"]
description = ""
from_port = 0
ipv6_cidr_blocks = []
prefix_list_ids = []
protocol = "-1"
security_groups = []
self = false
to_port = 0
}]
ingress = [{
cidr_blocks = ["0.0.0.0/0"]
description = ""
from_port = 22
ipv6_cidr_blocks = []
prefix_list_ids = []
protocol = "tcp"
security_groups = []
self = false
to_port = 22
}, {
cidr_blocks = ["0.0.0.0/0"]
description = ""
from_port = 80
ipv6_cidr_blocks = []
prefix_list_ids = []
protocol = "tcp"
security_groups = []
self = false
to_port = 80
}]
name = "launch-wizard"
name_prefix = null
revoke_rules_on_delete = null
tags = {}
tags_all = {}
vpc_id = vpc.id
}

# __generated__ by Terraform
resource "aws_subnet" "pb_subnet" {
assign_ipv6_address_on_creation = false
availability_zone = "ap-southeast-1a"
cidr_block = "10.0.0.0/20"
customer_owned_ipv4_pool = null
enable_dns64 = false
enable_resource_name_dns_a_record_on_launch = false
enable_resource_name_dns_aaaa_record_on_launch = false
ipv6_cidr_block = null
ipv6_native = false
map_public_ip_on_launch = false
outpost_arn = null
tags = {
Name = "tmp-vpc-terraform-subnet-public1-ap-southeast-1a"
}
tags_all = {
Name = "tmp-vpc-terraform-subnet-public1-ap-southeast-1a"
}
vpc_id = vpc.id
}

# __generated__ by Terraform
resource "aws_instance" "ec2" {
ami = "ami-015f72d56355ebc27"
associate_public_ip_address = true
availability_zone = "ap-southeast-1a"
disable_api_stop = false
disable_api_termination = false
ebs_optimized = false
get_password_data = false
hibernation = false
host_id = null
host_resource_group_arn = null
iam_instance_profile = null
instance_initiated_shutdown_behavior = "stop"
instance_type = "t2.micro"
ipv6_addresses = []
key_name = "my-second-try"
monitoring = false
placement_group = null
placement_partition_number = 0
secondary_private_ips = []
security_groups = []
source_dest_check = true
subnet_id = pb_subnet.id
tags = {
Name = "tmp-easy-ec2"
}
tags_all = {
Name = "tmp-easy-ec2"
}
tenancy = "default"
user_data = "2d120e5bb0aa192cda0cefe1a284f844d34fddd9"
user_data_base64 = null
user_data_replace_on_change = null
volume_tags = null
vpc_security_group_ids = [ntw_sg.id]
capacity_reservation_specification {
capacity_reservation_preference = "open"
}
cpu_options {
amd_sev_snp = null
core_count = 1
threads_per_core = 1
}
credit_specification {
cpu_credits = "standard"
}
enclave_options {
enabled = false
}
maintenance_options {
auto_recovery = "default"
}
metadata_options {
http_endpoint = "enabled"
http_protocol_ipv6 = "disabled"
http_put_response_hop_limit = 2
http_tokens = "required"
instance_metadata_tags = "disabled"
}
private_dns_name_options {
enable_resource_name_dns_a_record = false
enable_resource_name_dns_aaaa_record = false
hostname_type = "ip-name"
}
root_block_device {
delete_on_termination = true
encrypted = false
iops = 3000
kms_key_id = null
tags = {}
throughput = 125
volume_size = 8
volume_type = "gp3"
}
}

To summary

After we import existed AWS’s resources. You can now have HCL. In this scenario might help you for these benefits

  • Catch up new HCL configuration for init your resources cause you might have no idea how to write syntax for init resource but here we do backward engineer to write down your codes.
  • Reduce your human error when write your syntax.

This Terraform import feature require Terraform version 1.5 or above.

Example codes — https://github.com/NickUseGitHub/terraform-ec2

For those who interest joining us team in Tri Petch IT Solutions
Link — https://career.tripetchgroup.com/job-opening?bu_id=4

Contact us or find more Blogs here.
- https://medium.com/tri-petch-digital

--

--