wiki.getshifting.com

--- Sjoerd Hooft's InFormation Technology ---

User Tools

Site Tools


terraformazurecloudshell

Terraform in Azure Cloud Shell

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:

  • Setup the main.tf file with the azurerm provider configuration and the resource group
  • We will create terraform files for a vnet and a subnet
  • We will create a vm with a ip address in the subnet
  • We will have terraform create a random password for the vm
    • We will figure out where to find the password
  • At the end we will manually create an additional subnet and have the vm use it

In the end we will use terraform destroy to remove all resources.

A Reminder on Terraform

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 looks automatically for all files with the .tf extension in the directory you run the command from and combines them into one configuration
    • So you only need to define the provider once
    • So you can use separate files for separate resources
  • Hashicorp calls the terraform technical documentation online a “registry”:
    • Make sure you know how to find the documentation for the resources you want to create:
      • Use the 'Documentation' per provider for examples and authentication information
      • If you google for 'terraform registry' + the resource you want to create you'll almost always find the right page
        • For example: 'terraform registry azurerm virtual network'
      • Use the version dropdown to find the version of the provider you are using:
        terraform {
          required_version = ">= 0.14.9"
         
          required_providers {
            azurerm = {
              source  = "hashicorp/azurerm"
              version = "3.112"
            }
          }
        }
  • Resources describe infrastructure objects in Terraform configurations
  • Data sources allow Terraform to use information defined outside of Terraform or defined by another separate Terraform configuration

Start Cloud Shell

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.

Setup the main.tf file

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.

main.tf
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]

Create a VNet and Subnet

Now create a vnet.tf file with the following content:

vnet.tf
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.

Create a VM

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:

vm.tf
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.

Create a Random Password

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:

vm2.tf
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.

Where to Find the 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%

Use an existing subnet

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:

vm3.tf
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.

Destroy All Resources

When you're done, you can run the following command to destroy all resources: terraform destroy

terraformazurecloudshell.txt · Last modified: by 127.0.0.1