DevOps

Terraform Import Existing Resource: Ultimate Guide

Discover Terraform's import feature, understand challenges with earlier releases, and enhancements in the latest 1.5 config-driven feature

One of the commands in the Terraform command set is the terraform import command. It allows the import of existing resources. There are some challenges with the legacy terraform import command. With with the release of Terraform 1.5, Hashicorp has introduced new import functionality. Let’s dive into Terraform import existing resources step-by-step and see how this is done in 1.5 and higher.

What is Terraform?

Terraform is a very popular player in Infrastructure as Code (IaC) solutions developed by HashiCorp. It offers a practical way for DevOps teams to define and manage resources across many cloud providers, including but not limited to AWS, Google Cloud, Azure and VMware vSphere.

Below, we are adding AWS resources using Terraform.

Creating AWS infrastructure with Terraform
Creating AWS infrastructure with Terraform

Using the terraform plan and terraform apply commands, Terraform allows teams to plan and apply infrastructure changes. The terraform plan command enables teams to check their configurations and see exactly what actions Terraform will perform when the configurations are applied. It’s an essential step that prevents potential mishaps.

The terraform apply command allows you to align your environment along with the desired state of the resources defined in the configuration files. You use a provider plugins to “talk” with each cloud provider. The action results are then stored in your Terraform state file, which is used for maintaining and modifying the created resources.

What is Terraform import command?

The terraform import module enables teams to bring existing resource objects under Terraform management, marking a significant advantage for mergers and acquisitions or standardization efforts.

Terraform import command instructions
Terraform import command instructions

However, it had limitations for import operations in legacy versions. This is where Terraform 1.5 has improved things. With a slew of new features like config-driven import, Terraform made the process to import and manage existing infrastructure much easier and less problems with it.

Breaking Down Terraform Import Syntax

The basic syntax of the Terraform import command is quite straightforward:

terraform import [options] ADDRESS ID

Here, ‘ADDRESS’ specifies the Terraform state address of the resource to import, and ‘ID’ identifies the specific resource in the existing infrastructure. The optional ‘options’ argument allows for additional flags to fine-tune the import process.

The first way that the import command worked had limitations, mainly that resources had to be imported one by one, the state was immediately modified without a preview, and the configurations were manually written. This has now changed.

The Challenges with Terraform Import Prior to Version 1.5

The previous import command in Terraform had limitations, making importing existing infrastructure cumbersome. There are three limitations to note:

  1. One-by-one Resource Importation

  2. Risk of Accidental Resource Modifications or Deletions

  3. Manual Writing of Matching Resource Code

1. One-by-one Resource Importation

The earlier versions of Terraform only allowed resources to be imported one at a time. This was manageable for small infrastructures or for occasional use. But, with massive environments, this just wasn’t practical and the process became tedious and time-consuming.

2. Risk of Accidental Resource Modifications or Deletions

Another major challenge was that the state was immediately modified after running the import command, with no opportunity to preview the results. This could lead to accidental resource modifications or deletions if an apply operation was executed on the shared state by another team member before the corresponding configuration was added.

Below, working with Terraform version less than 1.5, you will need to understand the limitations and even concerns of using the terraform import command.

Legacy version of Terraform
Legacy version of Terraform

Manual Writing of Matching Resource Code

The import command was dependent on the corresponding resource code. It required the matching resource code to be manually written, often leading to a multi-step process of running plans, identifying the required attribute values, and achieving a clean run. This was an extra task, adding to the complexity of the import process and increasing the time taken to onboard resources onto Terraform.

Terraform 1.5 changes imports for the better

Terraform 1.5 was a game-changer for importing existing infrastructure, introducing a config-driven import feature. This feature simplifies bringing resources under Terraform management as Terraform resource objects.

You can check the version of Terraform you are running using the terraform version command:

Recent version of Terraform with the new config driven import
Recent version of Terraform with the new config driven import

The config-driven import process introduces an import block in your Terraform code, replacing the previous import commands. The import block takes two parameters: the cloud resource ID and the resource address in the Terraform configuration.

For example, for an Amazon EC2 instance, the import block would look something like this:

import { 
     id = "i-abcd1234"
     to = "aws_instance.example"
}

In this example, the id refers to your Terraform configuration’s EC2 instance ID and the destination resource block. By doing so, the EC2 instance is recognized as an AWS resource and can be managed by Terraform.

Running the terraform plan command with the -generate-config-out parameter creates a Terraform configuration file with all the attributes of the imported resources. This allows automatic code generation, significantly reducing the need to create the corresponding resource code manually.

Once the Terraform configuration file is generated and reviewed, running a normal apply operation successfully imports the resources into the Terraform state. This results in a successful import that is more manageable and less prone to human errors.

Check Blocks for Enhanced Validation

Along with config-driven imports, Terraform 1.5 introduces check blocks. These blocks offer a more comprehensive validation of the provisioned infrastructure, allowing users to confirm that the final product aligns with their expectations. This top-level construct can reference all resources, data sources, and module outputs in the configuration, offering a more holistic perspective than its predecessors.

Here’s an example:

check "health_check" {
  data "http" "example" {
    url = "https://${aws_lb.example.dns_name}"
  }

  assert {
    condition     = data.http.example.status_code == 200
    error_message = "${data.http.example.url} returned an unhealthy status code"
  }
}

Terraform 1.5 import lab

Ok, so I have created just three resources using some Terraform code to build out a simple AWS environment, with a VPC, subnet, and an EC2 instance.

What I’m going to do is create the infrastructure with Terraform and then delete the state data. This will simulate a case where we have infrastructure unmanaged by Terraform. So, below we are deleting the state file.

Deleting the Terraform state file
Deleting the Terraform state file

First, we are going to create an import.tf file that contains the following similar code with the real identifiers in the real code:

import { 

     id = "i-1234123412341234"
     to = aws_instance.testec2
	 
}

import {

     id = "vpc-1234123412341234"
     to = aws_vpc.testvpc

}

import {

     id = "subnet-1234123412341234"
     to = aws_subnet.testsubnet

}

If you don’t have a configuration file that matches the import resources you are defining, you will see something like this:

Error that the import block target does not exist
Error that the import block target does not exist

So I do have the configuration file in the example, so let’s just copy back over the .tf file containing the configuration. After copying over the configuration file, running the terraform plan correctly shows that we have 3 to import and 0 to add, 0 to change, and importantly, 0 to destroy.

Running the plan after having the configuration file in place
Running the plan after having the configuration file in place

However, now let’s test out the new config-driven import capabilities. Let’s say we don’t have a configuration file that already contains the configuration which is a likely scenario if you are bringing in existing infrastructure to manage.

Let’s use the command:

terraform plan -generate-config-out=generated.tf

After running the command, as you can see below, we had several error messages. After all the function at this point is experimental as noted in the output.

Errors after generating the new config using the generate functionality
Errors after generating the new config using the generate functionality

However, after you use the -generate-config-out command, you can now run the terraform plan command to start testing your code after you get to the bottom of the errors in the output above. If you keep running the plan with the -generate parameter, it will keep trying to generate a new file. We want to work with the one we have at this point.

What I was able to do was either comment out missing resource requirements or just delete them out of the generated.tf file. What I would recommend is delete or comment them out one at a time and then run a terraform plan. After getting rid of the errors, the generated.tf code is now good.

Errors resolved and running a plan and apply
Errors resolved and running a plan and apply

After you have no errors, then you can run a terraform apply. This will actually add the resources into the terraform state data. At this point the process is just like creating new infrastructure for the import process. Type Yes to verify the apply.

Verifying the Terraform apply operation
Verifying the Terraform apply operation

As you can see, we have imported 3 resources as expected, our VPC, subnet, and EC2 instance.

Resources successfully imported using the new Terraform import functionality
Resources successfully imported using the new Terraform import functionality

Wrapping up

The new import process with Terraform has really improved the process of bringing in existing infrastructure in your environment. With 1.5, it has config-driven import and checks, have made it even more powerful in managing cloud infrastructure. The next time you need to bring your existing resources under Terraform management, remember that with Terraform 1.5, the process has become a lot easier and safer.

Subscribe to VirtualizationHowto via Email 🔔

Enter your email address to subscribe to this blog and receive notifications of new posts by email.



Brandon Lee

Brandon Lee is the Senior Writer, Engineer and owner at Virtualizationhowto.com, and a 7-time VMware vExpert, with over two decades of experience in Information Technology. Having worked for numerous Fortune 500 companies as well as in various industries, He has extensive experience in various IT segments and is a strong advocate for open source technologies. Brandon holds many industry certifications, loves the outdoors and spending time with family. Also, he goes through the effort of testing and troubleshooting issues, so you don't have to.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.