Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 55

Importing Existing Infrastructure with Terraform

Recommended resources

Hello! Welcome to your next lesson in the "Advanced Infrastructure as Code with Terraform" module.

In our last session, we explored how to use data sources to read information from existing infrastructure, making our configurations more dynamic and adaptable. Today, we'll take the next logical step: learning how to take full control of infrastructure that was created outside of Terraform.

This lesson directly addresses the learning outcome: Use terraform import to bring existing, manually-created infrastructure under Terraform management.

This is a critical skill for any DevOps engineer. You will frequently encounter "brownfield" environments where infrastructure was created manually through a cloud console ("ClickOps") or with scripts before a proper IaC practice was adopted. Your job will be to bring this existing landscape under Terraform's control without destroying and recreating it.

We'll cover:

  • The "why" and "when" of importing resources.
  • The classic terraform import command-line workflow.
  • The modern, safer, configuration-driven import block (introduced in Terraform 1.5).
  • The process of generating, reviewing, and applying configurations for imported resources.

1. Why and When to Import Infrastructure

Before diving into the "how," let's establish the "why." Bringing existing resources under Terraform's management is not just about tidiness; it's about establishing a single source of truth for your infrastructure.

A Comprehensive Guide to Importing Existing Infrastructure into ...

The article 'A Comprehensive Guide to Importing Existing Infrastructure into Terraform' provides a great overview of the scenarios and benefits of importing.

Please read the introduction and the section titled 'Why import existing Infrastructure into Terraform and OpenTofu in the first place?'. This will set the context for the practical exercises to follow.

As the article highlights, importing allows you to achieve:

  • Unified Management: Your IaC code becomes the definitive source of truth.
  • Consistency: You can detect and remediate configuration drift.
  • Automation: The imported resources become part of your standard CI/CD workflow for plan and apply.
  • Reproducibility: You can replicate the configuration in other environments.

Now, let's explore the two primary methods for accomplishing this.

Terraform Import Process for an EC2 Instance
This diagram shows the core concept of importing: Terraform reads a manually created resource (like an EC2 instance), reconciles it with your HCL code, and updates its state file to begin managing that resource.

2. The Classic Method: The terraform import Command

For years, the only way to import resources was with the terraform import command. While a newer method now exists, you will still encounter this approach in older projects, documentation, and tutorials, so it's essential to understand it.

The workflow is procedural and requires careful execution:

  1. Identify the Resource ID: Find the unique identifier for the existing resource in your cloud provider (e.g., vpc-0123abcd for an AWS VPC).
  2. Write the HCL Code: Manually write a resource block in your .tf file that you believe matches the configuration of the existing resource.
  3. Run the Import Command: Execute terraform import <RESOURCE_ADDRESS> <ID> in your terminal. This command directly modifies the Terraform state file, linking your HCL block to the existing resource.
  4. Verify with plan: Run terraform plan. If your HCL code perfectly matches the actual resource, Terraform will report "No changes." If not, it will show a plan to modify the resource to match your code.

This video demonstrates this classic workflow by importing a full AWS network stack.

Terraform Import Existing Resources AWS (Import VPC, Route53, EC2, Security Group)

The video 'Terraform Import Existing Resources AWS' by Anton Putra provides a rapid, practical demonstration of the classic terraform import command for several common AWS resources.

Watch the full video (around 4.5 minutes). Notice the repeated pattern: Define the resource block in main.tf. Run terraform import <address> <id>. At the end (04:16), see how terraform plan is used to verify that everything has been imported correctly with no drift.

While effective, this method has significant drawbacks, especially in a collaborative DevOps environment:

  • Direct State Manipulation: It modifies the state file without the safety of a plan and apply cycle. This is risky.
  • Risk of Destruction: If you run import but haven't written the corresponding HCL code yet, a teammate running terraform apply could cause Terraform to see a resource in the state that's not in the code, leading it to destroy the live resource.
  • One-at-a-Time: You must run the command for every single resource, which is tedious for large environments.

These limitations led HashiCorp to develop a more robust, declarative approach.


3. The Modern Method: The Declarative import Block

Introduced in Terraform 1.5, the import block integrates the import process directly into the standard plan and apply workflow, making it significantly safer and more aligned with IaC principles.

Terraform Import: CLI vs. Import Block
This image visually contrasts the classic CLI command with the modern, declarative `import` block written directly in your HCL code.

The modern workflow is:

  1. Identify Resource ID: Same as before.
  2. Define import Block: Add an import block to your configuration. It requires two arguments: the resource id and the to address where it will be managed.
  3. Generate Configuration (Optional but Recommended): Run terraform plan -generate-config-out=generated.tf. Terraform will inspect the live resource and automatically write a corresponding resource block for you in a new file.
  4. Review and Refine: The generated code is a starting point. You must review it, remove unnecessary arguments, and fix any issues.
  5. Plan and Apply: Run terraform plan to see the import action. Then run terraform apply to execute it.
  6. Cleanup: Once the import is complete, remove the import block from your configuration.

This video from Ned in the Cloud provides an excellent deep dive into this modern workflow and its advantages.

Exploring the Import Block in Terraform 1.5

In 'Exploring the Import Block in Terraform 1.5', Ned explains the problems with the old command and provides a fantastic demonstration of the new, safer workflow.

Please watch these key segments: Shortcomings of import command (00:48 - 04:19): This clearly explains the risks I mentioned earlier. Understanding these problems highlights why the new method is superior. The New import Block Workflow (04:19 - 06:14): Pay close attention to the new, safer process: add block -> plan -> apply. Generating Configuration (06:14 - 07:22): This introduces the powerful -generate-config-out flag. Practical Demos (07:22 - 20:45): You can watch the full demo, but the most crucial part is understanding the process shown in the first Azure subnet example (07:22 - 12:37). The second example (12:37 onwards) is a great illustration of how you need to clean up the auto-generated code, which is a key real-world step.

The key advantages of the import block are clear:

  • Declarative: The intent to import is captured in code.
  • Safe: It's part of the standard plan/apply cycle. You can review the import plan before any state is modified.
  • CI/CD Friendly: It can be run in automated pipelines without manual CLI commands.
  • Code Generation: The -generate-config-out flag saves a significant amount of manual effort, though it's still experimental and requires human oversight.

4. Step-by-Step Guide and Best Practices

Let's solidify this with a practical guide. While the videos used Docker and Azure, the process is identical for AWS. The official HashiCorp tutorial provides another excellent walkthrough that also covers important details about refining the generated code.

Import Terraform configuration - HashiCorp Developer

The official HashiCorp tutorial 'Import Terraform configuration' walks through the entire configuration-driven import process, including the crucial step of refining the auto-generated code.

Read through this tutorial from 'Prerequisites' to 'Limitations and other considerations'. The example uses Docker, but the principles are universal. Focus on these key sections: Define import block (Section 2): Note the simple syntax using id and to. Generate configuration (Section 3): This is the core of the workflow. Pay special attention to how the tutorial identifies an issue in the generated plan (forces replacement) and then corrects the generated HCL code to achieve a clean import. Import and update the resource (Section 4): This shows how you can even modify the resource in the same apply that imports it. Limitations and other considerations (Section 6): This is a critical read. It highlights that import doesn't detect relationships or know which default attributes can be ignored. You, the engineer, must provide that context.


Conclusion

You now have the knowledge to confidently bring existing, manually-created infrastructure under Terraform's management. This is a day-one skill for a DevOps engineer joining a team that is in the process of adopting IaC.

Key Takeaways:

  • Two Methods: The classic terraform import command (procedural, risky) and the modern import block (declarative, safe, recommended).
  • The Modern Workflow: Define an import block, use terraform plan -generate-config-out to create a starting configuration, refine the generated code, and then use plan/apply as usual.
  • Refinement is Key: Auto-generated code is not perfect. It's your responsibility to prune it, add necessary resource relationships (like referencing a docker_image from a docker_container), and ensure the plan is non-destructive (unless intended).
  • Always Verify: After any import operation, run terraform plan one last time to ensure your state and configuration are perfectly synchronized with reality, resulting in a "No changes" message.

In our next and final lesson of this module, we will put everything together. We'll learn how to integrate Terraform into a CI/CD pipeline to automate infrastructure validation (plan) and deployment (apply). This will automate the workflows we've been practicing manually, which is the ultimate goal in a modern DevOps environment.