Skip to main content

Importing Resources Into Terraform

Sometimes terraform apply fails with the following error message:

Error: A resource with the ID "/subscriptions/****/resourceGroups/my-awesome-rg/providers/Microsoft.Something/exampleResource/my-resource" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_example_resource" for more information.

with azurerm_example_resource.my_resource,
on .components/foo/myfile.tf line 25, in resource "azurerm_example_resource" "my_resource":
25: resource "azurerm_example_resource"

This message can pop up for several reasons - most often it is because the resource identified by the error has been either created, re-created or modified outside of terraform. This means the object needs to be “imported” before terraform can perform certain operations on it. Thankfully there is an easy, self-serviceable way to do this that this document will detail.

The import Block

Terraform 1.5.0 introduces the import block. This is a line of code that can be inserted into your terraform code to specify an externally managed resource that is to be brought into the terraform state. This is not to be confused with terraform import, the command-line argument that performs the same operation. Compared to terraform import, an import block is easier and safer to execute, as it integrates seamlessly into existing terraform apply stages in your pipeline and does not require manual tinkering with the state file.

After applying the import, the import block can be safely removed from your code. Attempting to import a resource into the same address again is a harmless no-op and should not affect your configuration.

Implementation

An import block can be inserted anywhere into your terraform code. You will need to know two variables for the block: the resource ID and the resource address. Both are output directly by the error message.

Resource ID

The resource ID is the unique identifier of the resource in Azure. It’s also part of the URL used to visit the ID in the azure portal. Some pipelines censor the subscription ID of the resource in the error message. You will need to know the full resource ID in order to import the resource. The subscription ID of the resource can more often than not be interpolated using terraform variables as will be shown in the example configuration later on.

Resource IDs will always take the following form:

 /subscriptions/01234567-89ab-cdef-0123-456789abcdef/resourceGroups/my-awesome-rg/providers/Microsoft.Something/exampleResource/my-resource

#### Resource Address

The resource address is the internal identifier terraform uses to reference the resource in code. What this will look like will depend entirely on your configuration and where the error is occurring. If the error is occurring in a module (as it often does) the resource address may be significantly longer than the example below.

 azurerm_example_resource.my_resource

#### Environment Filtering

Your error will be occurring in a specific subscription in a specific environment. As most pipelines throughout HMCTS are multi-environment, it will be necessary to restrict the import block to the specific environment where the error is occurring. Failure to do this will mean that the pipeline will import the wrong resources when running in other environments.

#### Import Multiple Resources

Import blocks import a single resource. If there are multiple resources that require importing, you will need multiple import blocks. This can also be accomplished by clever use of a for_each but the example provided here will not be covering that.

## Example configuration

The following is an example import block that can be placed into your code. Take care to ensure that the resource ID and resource address are correct before running. A terraform plan can be run to verify that the import block will function as expected before running apply.

# Obtain the subscription ID of the problematic resource
data "azurerm_subscription" "current" {}

import {
  # Run this import only in prod
  for_each = var.env == "prod" ? toset(["import"]) : toset([])
  # Specify the resource address to import to
  to       =  azurerm_example_resource.my_resource
  # Specify the resource ID to import from
  id       = "/subscriptions/${data.azurerm_subscription.current.subscription_id}/resourceGroups/my-awesome-rg/providers/Microsoft.Something/exampleResource/my-resource"
}
This page was last reviewed on 26 July 2024. It needs to be reviewed again on 26 July 2025 by the page owner platops-build-notices .
This page was set to be reviewed before 26 July 2025 by the page owner platops-build-notices. This might mean the content is out of date.