Use Terraform long enough, and eventually, we’ll need to use an existing resource not managed by Terraform as part of the deployment. A typical example is deploying a network-enabled resource, a virtual machine, for instance, to an existing virtual network. This post and accompanying video demonstrate using an existing Azure resource as part of a Terraform deployment.
If you are just getting started with Terraform, be sure to check out other posts and videos here:
Getting started with Terraform and Azure: Overview and Setup
Terraform Workflow with Azure: Write, Plan and Apply
Input Variables with Terraform and Azure
Modules and Outputs with Terraform and Azure
Also, the code used for this post and video can be found on GitHub here:
There are two options for using existing resources created by some means other than Terraform: Import, and Data Source.
Terraform Import, as the name implies, imports infrastructure into Terraform management. Import adds resources to the deployment state, expecting it will be managed by Terraform going forward.
Import is for transitioning infrastructure into Terraform management. Resources not currently managed by Terraform can be transitioned into and be managed by Terraform with Import.
Data Source allows Terraform to define and use infrastructure created outside of the current deployment. The resources could have been deployed as part of another Terraform deployment or other process such as Azure Resource Manager (ARM) or with the portal.
The key difference is that with Data Sources, the source does not become managed by Terraform or part of the Terraform state. Instead, a Data Source simply references existing infrastructure. The data source can then be used as part of the deployment.
The following example will use a Data block to reference an existing Virtual Network. We will attach a virtual network interface for a new VM to an existing subnet. The example also uses the Sensitive argument to obfuscate a password and set VM specific features in the Provider block.
First, we start with an existing Module that creates a VM. The module name is WinServer. Within the main.tf file for the module, we must supply a Subnet ID for the Network Interface resource. This is supplied by the var.subnetid variable.
Another item to note, in the inputs.tf is a variable for the local admin password. Notice the sensitive argument provided with the variable. The sensitive argument instructs Terraform not to write the password to the console, providing security by obscurity for sensitive variable data.
For some reason, I created this example with variables in a file named inputs.tf instead of variables.tf. I’m too far into this example to change it now.
The Root module calls the WinServer module, passing in all the variables, including the subnet ID. Some resources, such as virtual machines, have deployment-wide features that can be enabled in a feature block within the provider. These features set behaviors for the resources. For example, the provider block below has two Virtual Machine features enabled. One feature sets the OS disk to delete when the VM is removed. The other will not force a graceful shutdown on the VM when deleted.
A full list of features can be found at the Terraform Registry documentation located here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#features
Now for the main attraction. The example creates a virtual machine, and as part of that deployment, we need to supply a subnet ID. The subnet already exists, and there is no intention to import the subnet into this deployment for management. We use a data block to reference the external subnet resource.
We can find examples of data blocks in the Terraform documentation. A search for subnet will return azurerm_subnet under the heading Resources and Data Sources https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Select azurerm_subnet under Data Sources to view an example of a data block for Azure subnets and output. Use the documentation for other resources you may need to reference when creating data blocks in Terraform.
Now that we have an example, we can create the data block. The example below uses variables to provide the name of the subnet, virtual network, and the virtual network’s resource group. An important to note is that the resources group in this context is for the VNet, not the resource group of the deployment.
That exposes the external resource to our deployment. Next, we need to supply the Subnet ID to the module. To do that, we simply reference the data block in the module block as shown below.
Now, when we apply the configuration, the network interface for the new virtual machine will connect to the existing subnet. That is how to reference a data source outside of the deployment in Terraform with Azure.