How to import existing infrastructure resources in Terraform
My name is Teraoka and I am an infrastructure engineer.
Have you ever thought, ``I want to be able to manage my existing infrastructure configuration with Terraform?''
Terraform provides commands to achieve this, so I will introduce them in this article.
I created one VPC without using Terraform in advance.
This time, let's import this into Terraform.
Directory structure
$ tree . ├── README.md ├── provider.tf ├── terraform.tfstate ├── variables.tf └── vpc.tf 0 directories, 5 files
Write provider and variable
Before importing, write provider and variable as they are the minimum required.
provider.tf
provider "aws" { access_key = var.access_key secret_key = var.secret_key region = var.region assume_role { role_arn = var.role_arn } }
variables.tf
#################### # Provider #################### variable "access_key" { description = " AWS Access Key" } variable "secret_key" { description = "AWS Secret Key" } variable "role_arn" { description = "AWS Role Arn" } variable "region" { default = "ap-northeast-1" }
Save your AWS access keys etc. in environment variables.
$ export TF_VAR_access_key=XXXXXXXXXXXXXXXXXX $ export TF_VAR_secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX $ export TF_VAR_role_arn=arn:aws:iam::XXXXXXXXXXXX:role/XXXXXXXXXXXXXXXXXXX
run plan
Try running plan.
Since nothing is imported now, execution ends with "No changes."
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. ------------ -------------------------------------------------- ---------- No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed .
run import
To import existing resources with Terraform, run the "terraform import" command.
The command format is described in the Terraform manual (*1) , so refer to it and execute the command below.
$ terraform import aws_vpc.vpc vpc-09a9f1827bfd851f4 Error: resource address "aws_vpc.vpc" does not exist in the configuration. Before importing this resource, please create its configuration in the root module. For example: resource "aws_vpc" "vpc" { # (resource arguments) }
An error has occurred.
When importing, you will specify the resource type and name such as "aws_vpc.vpc", and the existing resource information will be imported for the resources in the tf file specified here.
Therefore, it is necessary to write the corresponding resources in the tf file in advance.
Describe a vpc resource
I will write it as follows.
vpc.tf
#################### # VPC #################### resource "aws_vpc" "vpc" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "vpc-tfstate-test" } }
Run import again
I'll try running it again.
This time I was able to import without any problems.
$ terraform import aws_vpc.vpc vpc-09a9f1827bfd851f4 aws_vpc.vpc: Importing from ID "vpc-09a9f1827bfd851f4"... aws_vpc.vpc: Import prepared! Prepared aws_vpc for import aws_vpc.vpc: Refreshing state... [id=vpc-09a9f182 7bfd851f4 ] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
What does this terraform import do?
When you run the command, you will see that a file named "terraform.tfstate" has been created.
terraform.tfstate
{ "version": 4, "terraform_version": "0.12.24", "serial": 1, "lineage": "c0359eb1-d905-e252-2d8d-525710adddb1", "outputs": {}, "resources": [ { "mode": "managed", "type": "aws_vpc", "name": "vpc", "provider": "provider.aws", "instances": [ { "schema_version": 1, "attributes ": { "arn": "arn:aws:ec2:ap-northeast-1:485076298277:vpc/vpc-09a9f1827bfd851f4", "assign_generated_ipv6_cidr_block": false, "cidr_block": "10.0.0.0/16", "default_network_acl_id" : "acl-0cd8abfed52e0e951", "default_route_table_id": "rtb-08c13269b1b26c9b8", "default_security_group_id": "sg-007ef29e563b6f9c7", "dhcp_options_id": "dopt-6c0f430b", "enable_classiclink" : false, "enable_classiclink_dns_support": false, " enable_dns_hostnames": true, "enable_dns_support": true, "id": "vpc-09a9f1827bfd851f4", "instance_tenancy": "default", "ipv6_association_id": "", "ipv6_cidr_block": "", "main_route_table_id": "rtb- 08c13269b1b26c9b8", "owner_id": "485076298277", "tags": { "Name": "vpc-tfstate-test" } }, "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ==" } ] } ] }
If you look inside, you will see that the information about the resource you imported earlier has been saved.
When executed, Terraform automatically determines whether to create, change, or delete a resource and creates a resource, but this determination is based on the difference between the tf file read during execution and the content written in tfstate. It is being done.
In other words, in order to manage the specified existing resource on Terraform, it is necessary to change the contents of tfstate, and terraform import is a command that reads the information of the specified existing resource and adds it to tfstate.
run plan again
Now that we've run terraform import, let's run plan again.
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.vpc: Refreshing state... [id= vpc-09a9f1827bfd851f4] ------------------------------------------------- -------------------------- No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
aws_vpc.vpc is loaded as a resource on Terraform.
Let's change enable_dns_hostnames to false.
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_vpc.vpc: Refreshing state... [id= vpc-09a9f1827bfd851f4] ------------------------------------------------- -------------------------- An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: ~ update in- place Terraform will perform the following actions: # aws_vpc.vpc will be updated in-place ~ resource "aws_vpc" "vpc" { arn = "arn:aws:ec2:ap-northeast-1:485076298277:vpc/vpc-09a9f1827bfd851f4" assign_generated_ipv6_cidr_block = false cidr_block = "10.0.0.0/16" default_network_acl_id = "acl-0cd8abfed52e0e951" default_route_table_id = "rtb-08c13269b1b26c9b8" default_security_group_id = "sg-007ef29e563b6f9c7" dhcp_options_id = "dopt-6c0f430b" enable_classiclink = false enable_classiclink_dns_support = false ~ enable_dns_hostnames = true -> false enable_dns_support = true id = "vpc-09a9f1827bfd851f4" instance_tenancy = "default" main_route_table_id = "rtb-08c13269b1b26c9b8" owner_id = "485076298277" tags = { "Name" = "vpc-tfstate-test" } } Plan: 0 to add, 1 to change, 0 to destroy. ---------------------------------------- -------------------------------- Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
The behavior is to try to change only the difference.
summary
As stated in the import command's explanation page (*2)
In other words, you need to write the actual tf file by yourself while checking the difference with tfstate. In the future, it seems that a function will be added to automatically generate tf files, but for now, the more targets there are, the harder it will be. . .
To solve this problem, terraformer (*3) has been released as an OSS.
Next time I will write a blog about how to use this.
Reference URL
*1 : https://www.terraform.io/docs/providers/aws/r/vpc.html
*2 : https://www.terraform.io/docs/import/index.html
*3 : https:/ /github.com/GoogleCloudPlatform/terraformer