Summary: In this post I'll show you a few basic terraform commands and configuration files. If you're trying to learn terraform on azure this is an easy and fast tutorial to get started.
Date: 11 January 2025
We'll cover the following topics:
In the end we will use terraform destroy
to remove all resources.
Here is a list of terraform terminology and knowledge you need to know to follow this tutorial. Most of it was already covered here, but I'll repeat it here for your convenience:
terraform { required_version = ">= 0.14.9" required_providers { azurerm = { source = "hashicorp/azurerm" version = "3.112" } } }
See here for how to start cloud shell. For direct access, use: https://shell.azure.com/
Once started, you can check if you're ready to go using the following commands:
terraform --version cd clouddrive code rg.tf
This willl check if terraform is available, and will start the integrated editor in the clouddrive directory.
Use the code below to create a main.tf file in your cloud shell. Don't forget to change the subscription_id and tenant_id to your own values.
variable "resource_group_core" { type = string default = "rg_tf" } provider "azurerm" { subscription_id = "30b3c71d-a123-a123-a123-abcd12345678" tenant_id = "7e4an71d-a123-a123-a123-abcd12345678" features {} } resource "azurerm_resource_group" "rg" { name = var.resource_group_core location = "West Europe" }
Now, you can test the configuration by running the following commands:
terraform init # output: Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/azurerm... - Installing hashicorp/azurerm v4.15.0... - Installed hashicorp/azurerm v4.15.0 (signed by HashiCorp) Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. Terraform has been successfully initialized! # Now run the plan command terraform plan # output: Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "westeurope" + name = "rg_tf" } Plan: 1 to add, 0 to change, 0 to destroy. # Now run the apply command terraform apply # output: Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "westeurope" + name = "rg_tf" } Plan: 1 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes azurerm_resource_group.rg: Creating... azurerm_resource_group.rg: Creation complete after 9s [id=/subscriptions/30b3c71d-a123-a123-a123-abcd12345678/resourceGroups/rg_tf]
Now create a vnet.tf file with the following content:
resource "azurerm_virtual_network" "vnet" { name = "vnet-sjoerd" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name address_space = ["10.0.0.0/16"] } resource "azurerm_subnet" "subnet" { name = "snet-sjoerd" virtual_network_name = azurerm_virtual_network.vnet.name resource_group_name = azurerm_resource_group.rg.name address_prefixes = ["10.0.1.0/24"] }
You can now run terraform apply
to create the vnet and subnet.
Now create a vm.tf file with the following content. Note that the network interface is using the subnet we defined earlier. Because terraform is looking at all of the terraform files in the directory, it knows about the subnet:
resource "azurerm_network_interface" "nic" { name = "nic-vm-sjoerd" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name ip_configuration { name = "Configuration" subnet_id = azurerm_subnet.subnet.id private_ip_address_allocation = "Dynamic" } } resource "azurerm_windows_virtual_machine" "vm" { name = "vm-sjoerd" admin_username = "azureuser" admin_password = "password1234!" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name network_interface_ids = [azurerm_network_interface.nic.id] size = "Standard_DS1_v2" os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "MicrosoftWindowsServer" offer = "WindowsServer" sku = "2022-datacenter-azure-edition" version = "latest" } }
You can now run terraform apply
to create the vm and the network interface.
As you can see above we have created a set password for the VM. You can't really use this in production environments as it exposes your password in plain text and possibly in a repository. So let's change the code to use a random password generated by terraform:
resource "random_password" "admin_password" { length = 10 special = true override_special = "!#$%&*()-_=+[]{}<>:?" } resource "azurerm_network_interface" "nic2" { name = "nic-vm-sjoerd2" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name ip_configuration { name = "Configuration" subnet_id = azurerm_subnet.subnet.id private_ip_address_allocation = "Dynamic" } } resource "azurerm_windows_virtual_machine" "vm2" { name = "vm-sjoerd2" admin_username = "azureuser" admin_password = random_password.admin_password.result location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name network_interface_ids = [azurerm_network_interface.nic2.id] size = "Standard_DS1_v2" os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "MicrosoftWindowsServer" offer = "WindowsServer" sku = "2022-datacenter-azure-edition" version = "latest" } }
You can now run terraform apply
to create the vm and the network interface. The new VM will have a random password.
You can find the password in the terraform state file. You can find the state file in the .terraform directory in the directory you are running terraform from. The password is stored in plain text in the state file. You can run the following command to find the password: code bash.tfstate
Note that some characters in the password might be shown as a unicode character:
"password": "Oy\u003cQUJpwd%"
The above part \u003c
is actually the <
character. So be aware of \uXXXX
characters in the password. The password above is actually: Oy<QUJpwd%
Now in the azure portal, in the vnet we created, create a new subnet. You can use the following code to create a new network interface and vm that uses the new subnet:
data "azurerm_subnet" "subnet_manual" { name = "snet-manual" virtual_network_name = azurerm_virtual_network.vnet.name resource_group_name = azurerm_resource_group.rg.name } resource "random_password" "admin_password3" { length = 10 special = true override_special = "!#$%*()-_=+[]{}:?" } resource "azurerm_network_interface" "nic3" { name = "nic-vm-sjoerd3" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name ip_configuration { name = "Configuration" subnet_id = data.azurerm_subnet.subnet_manual.id private_ip_address_allocation = "Dynamic" } } resource "azurerm_windows_virtual_machine" "vm3" { name = "vm-sjoerd3" admin_username = "azureuser" admin_password = random_password.admin_password3.result location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name network_interface_ids = [azurerm_network_interface.nic3.id] size = "Standard_DS1_v2" os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "MicrosoftWindowsServer" offer = "WindowsServer" sku = "2022-datacenter-azure-edition" version = "latest" } }
Now the subnet is defined as a data source, indicating it was created outside of terraform. You can now run terraform apply
to create the vm and the network interface.
When you're done, you can run the following command to destroy all resources: terraform destroy