Skip to content

Terraform Import: Existing Resources

  • 12 min read

Integrating existing infrastructure into Terraform can feel like trying to fit a square peg in a round hole. You’ve spent time crafting resources, and now you need to manage them with code. But there’s a way to bring your current setup into the fold without starting over: the terraform import command. This article walks you through how to use terraform import to manage your existing infrastructure, step by step. We’ll cover everything from the basic syntax to complex scenarios, giving you the knowledge to bring your legacy resources into the Terraform world.

Understanding Terraform Import

The core of integrating your existing infrastructure into Terraform is using the terraform import command. This command lets you take a resource that you’ve created manually (or with other tools) and bring it under Terraform management. It doesn’t magically create all the code for you, but it does connect your real-world resource to a corresponding resource block in your Terraform configuration. In this way, Terraform becomes aware of the existence of your resource, and it can then apply plans and changes as needed.

How it Works

Here’s a simple overview of the terraform import process:

  1. Identify Resource: First, you need to know the type of resource you want to import (e.g., an AWS EC2 instance, an Azure virtual machine) and the unique identifier that the cloud provider uses to manage it (e.g., its ID or name).
  2. Write Terraform Configuration: Next, craft the resource block in your Terraform file to mirror the properties of the resource you wish to import.
  3. Run terraform import: Use the command to link the real-world resource and the resource block in your configuration.
  4. Plan and Apply: After the import, use terraform plan to check for any discrepancies. And then use terraform apply to bring the state of your Terraform config in sync with your real-world resource.

Why Use terraform import?

Why use terraform import when you could try to recreate all of your resources from scratch? Here are a few good reasons:

  • Avoid Downtime: Recreating resources from scratch might cause service disruptions. Import lets you avoid that, because it integrates current resources.
  • Save Time: Writing Terraform code for every resource you already have can be time consuming. Import provides a good way to speed this up.
  • Reduce Errors: If you try to create the resources by hand in your Terraform config, you might end up misconfigured or with resources that are not quite the same as the real ones. Import does not create any new resources, instead it ties in your real resources to the code, avoiding this mistake.
  • Centralized Management: Once your infrastructure is under Terraform management, you can handle all changes, version control, and collaboration with the rest of your team in one place.

Preparing for Import

Before diving into the command, you need to lay some groundwork. Proper setup before importing your resources will smooth the process, and reduce mistakes.

Setting Up Your Terraform Environment

First, make sure your Terraform setup is in good working order. This means:

  1. Install Terraform: Ensure you have Terraform installed on your machine. If not, download it from the official website.
  2. Choose a Backend: Select a suitable backend to store your Terraform state. Cloud options like AWS S3, Azure Storage Account, or Google Cloud Storage are good choices for team setups. Or, you can stick to local state for practice.
  3. Configure Your Provider: Configure your chosen cloud provider to work with Terraform. For instance, for AWS, set up your credentials using environment variables or an AWS profile.

Understanding the Resource Identifier

The most critical piece of info for terraform import is the resource identifier. This is a unique ID or name that the cloud provider gives to each resource. It is different for each provider, here are some examples:

  • AWS: Resource IDs (e.g., i-0abcdef1234567890, subnet-0abcdef1234567890) or resource names, depending on the provider.
  • Azure: Resource IDs (e.g., /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/example-vm)
  • Google Cloud: Fully qualified resource names (e.g., projects/example-project/zones/us-central1-a/instances/example-instance).

You’ll find these identifiers in your cloud provider’s console, CLI, or API. Always double-check you have the correct ID before importing.

Writing the Terraform Configuration

Before importing, you need the resource code ready in Terraform. Here’s a simple example for an AWS EC2 instance:

resource "aws_instance" "example" {
  ami           = "ami-0c55b23422d01c15a"
  instance_type = "t2.micro"
  tags = {
    Name = "example-instance"
  }
}

This resource block defines the characteristics of the resource. Notice that this block doesn’t create a new instance, it only describes it. You’ll have to replace placeholders such as ami with real values, if they are different.

Your configuration doesn’t have to match your real-world resource exactly. The import process will update the Terraform state and allow Terraform to track it. But, starting with a correct config helps avoid extra changes later.

Using the terraform import Command

With prep done, it’s time to use the terraform import command. Let’s look at the basic syntax and how it applies in common scenarios.

Basic Syntax

The terraform import command structure is straightforward:

terraform import <ADDRESS> <ID>
  • ADDRESS: This points to the Terraform resource you want to import. It matches the name you’ve set in the configuration file (e.g., aws_instance.example).
  • ID: This is the unique identifier of the real-world resource that you got from your cloud provider.

Let’s look at a real-world example of importing an AWS EC2 instance, with these identifiers:

  • ADDRESS: aws_instance.example
  • ID: i-0abcdef1234567890

The command would be:

terraform import aws_instance.example i-0abcdef1234567890

When executed, this will bring the real AWS EC2 instance under the umbrella of your Terraform configuration.

Common Import Scenarios

Let’s explore some common use cases for terraform import:

Importing an AWS EC2 Instance

Using the example config above, you would run this command to import an EC2 instance that has an identifier as i-0abcdef1234567890:

terraform import aws_instance.example i-0abcdef1234567890

After running, you can use terraform plan to check if everything matches, and then use terraform apply.

Importing an Azure Virtual Machine

Here is an example configuration for an Azure Virtual Machine:

resource "azurerm_virtual_machine" "example" {
  name                = "example-vm"
  resource_group_name = "example-resource-group"
  location            = "eastus"
  vm_size             = "Standard_DS1_v2"
  storage_image_reference {
      publisher = "Canonical"
      offer     = "UbuntuServer"
      sku       = "16.04-LTS"
      version   = "latest"
  }
  os_profile {
    computer_name = "example-vm"
    admin_username  = "adminuser"
  }
  os_profile_linux_config {
      disable_password_authentication = true
  }
  network_interface_ids = [
    azurerm_network_interface.example.id,
  ]
}

And assuming the resource ID is /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/example-vm, your import command would be:

terraform import azurerm_virtual_machine.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-resource-group/providers/Microsoft.Compute/virtualMachines/example-vm

Importing a Google Cloud Instance

And here’s a configuration for a Google Cloud instance:

resource "google_compute_instance" "example" {
  project      = "example-project"
  zone         = "us-central1-a"
  name         = "example-instance"
  machine_type = "e2-medium"
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }
 network_interface {
    network = "default"
 }
}

With the identifier projects/example-project/zones/us-central1-a/instances/example-instance, the import command would be:

terraform import google_compute_instance.example projects/example-project/zones/us-central1-a/instances/example-instance

Handling Errors and Troubleshooting

Importing resources doesn’t always go off without a hitch. Here are some common issues you might encounter and how to handle them:

  • Incorrect Address: If the address doesn’t match the resource in your Terraform configuration, you’ll get an error. Check that the ADDRESS parameter in the import command corresponds with your resource name in the code.
  • Incorrect ID: An incorrect ID will lead to an error. Double-check the identifier you copy and paste.
  • Resource Already Managed: If Terraform already manages the resource, you can’t import it again. In this case, make sure you are importing the correct resource, or try terraform refresh to see if you already have the resource in your state.
  • Missing Configuration: If you’re missing a key attribute in your config, you may get errors when running terraform plan. Make sure to define all the necessary configurations in your code.
  • Drift Detection: If your configuration does not exactly match the real-world resource, you might detect a drift. In this case, you have two options: adjust your configuration code, or accept the change the plan is trying to make.

After the Import

Importing is only the first step in the journey of moving your resources into Terraform. Let’s discuss what comes next.

Planning and Applying

After the import, it is important to always use terraform plan. The plan command will show you all the differences between the real-world resource and your Terraform configuration. This helps you to find any mistakes. Once you review the plan, if there are no errors, you can then use terraform apply to apply the configuration in the plan, bringing the Terraform state file in sync with the resources you just imported.

Managing State

Terraform state keeps track of the resources managed by your config. After the import, your state file now has information about your resources, so it can track changes. You may need to store this file in a secure, shared backend for teams.

Updating and Modifying Resources

Once imported, you can modify your resources by changing the corresponding attributes in your Terraform code. For instance, change instance types, update tags, or adjust other parameters. After making these changes, run terraform plan to confirm the changes you’re about to apply, and use terraform apply to update your resources.

Deleting Imported Resources

To delete a resource that you imported, you will first need to use the terraform destroy command. This command removes resources from your provider, not from your state. This operation destroys the real-world resource, and removes it from the state file.

Advanced Import Techniques

Now that you know the basics, let’s look at some more advanced techniques to handle complex situations.

Importing Multiple Resources

You can import multiple resources at once, one after another. It is a good idea to do them in the correct order, for example, import a VPC first, and then the subnets and instances in that VPC. Use terraform plan after every import to catch potential errors early on.

Using For Loops for Multiple Imports

If you need to import many of the same kind of resource, you can use a for loop with the terraform import command. Create a list of identifiers and use a for_each loop:

resource "aws_instance" "example" {
  for_each = toset(["i-0abcdef1234567890", "i-0fedcba9876543210"])
  ami           = "ami-0c55b23422d01c15a"
  instance_type = "t2.micro"
  tags = {
    Name = "example-instance-${each.key}"
  }
}

And in your import command, you need to use the correct addresses:

terraform import aws_instance.example["i-0abcdef1234567890"] i-0abcdef1234567890
terraform import aws_instance.example["i-0fedcba9876543210"] i-0fedcba9876543210

This method automates the import process, saving time and effort.

Importing Resources with Dependencies

When importing resources with dependencies, such as a virtual machine that depends on a network interface, be sure to import them in the correct order. Start with the lowest-level resources and move up.

Dealing with Complex Resource Configurations

Complex resource configurations might require breaking down your import process. Sometimes you might need to import the resources one by one, and test after each import. After you import all resources, always run terraform plan to detect and fix errors.

Best Practices for Terraform Import

To avoid problems, here are some best practices for using terraform import:

  • Always Plan: After each import, run terraform plan to check for discrepancies. This is a key step for a successful import.
  • Test in a Non-Prod Environment: Try import on test resources before applying them to production. This helps you become familiar with the process.
  • Version Control Your Configuration: Put your Terraform files under version control so you can track changes and rollback if needed.
  • Use a Remote Backend: Store state files remotely to ensure that multiple team members can collaborate without problems.
  • Document Your Process: Document your import process and the challenges you faced. This serves as a guide for future imports.
  • Clean up Old Configurations: Once your real resources are tied to Terraform, it is a good idea to delete or archive any old resource files or configs that are no longer being used.
  • Use descriptive names: Use names that will help you find your resources quickly. A good name can make the import process easier.
  • Stay Updated: Keep up with updates to Terraform and its providers. That will help you avoid surprises.
  • Read the provider documentation: Each provider has unique characteristics and specifics for its import command. Read the documentation to avoid common errors.
  • Start small: Don’t try to import everything at once. Start with a few simple resources, and then move to more complex ones.
  • Double-check IDs: Always double-check the ID before running the import command. A mistake in the ID will result in problems and errors.
  • Use proper formatting: Follow the correct formatting for the configuration file. This helps prevent syntax errors and makes your config easier to read.

The Benefits of Terraform Import

Using terraform import is more than a way to move your old resources to Terraform. Here are a few benefits that make it important for the modern infrastructure engineer:

  • Improved Resource Management: By bringing your entire infrastructure under Terraform, you have more control, better auditing, and a more unified way to handle changes.
  • Increased Efficiency: The import feature speeds up the process of managing your infrastructure, reducing the time it takes to set up.
  • Better Collaboration: The import option lets you bring legacy infrastructure into a shared system that works well with teams.
  • Less Risk of Human Error: By using the import process, you avoid manually making changes to the infrastructure. And all changes are logged and easy to track.
  • Faster Adoption of IaC: If you work on an environment that already exists, using terraform import is the best way to adopt Infrastructure as Code.

A Well-Managed Infrastructure

terraform import helps you keep pace with infrastructure changes without starting from scratch. By using this command with the correct planning, your real-world resources can be tracked by your Terraform configurations. This makes it easier to keep a well-managed infrastructure. This tool enables you to bridge the gap between what you already have and the world of infrastructure as code.