- Random Access Musings
- Posts
- Back in Action: Terraforming Azure
Back in Action: Terraforming Azure
From Setup to Deployment

Hello Muser!
I wanted to apologize for the long delay on this edition of the newsletter. I had some personal events get in the way of the schedule but I’m back to writing!
Last time we did a deep dive into Terraform's vocabulary, getting acquainted with the syntax and components like providers, resources, and how the state is managed. We even took a peek at a simple AWS example to see how these pieces come together in a script. Now, we're all set to roll up our sleeves and get our hands dirty with a real-world Azure scenario.
If you’ve worked in Azure with Terraform before, please add some thoughts in the comments!
Azure Account Setup
First off, let’s get you set up on Azure. Head on over to the Azure Free Account Page and snag yourself a free account.
Azure generously offers a bunch of free services for 12 months plus a $200 credit to explore any Azure service for 30 days. It’s a sweet deal to kickstart your cloud journey!

Terraform, Meet Azure
Before Terraform and Azure can start interacting, you'll need to install Azure CLI (Command-Line Interface) if you haven’t already. Here's a quick summary on getting it installed and setting things up:
Installing Azure CLI
For Windows, grab the installer and run it.
On macOS, a simple
brew install azure-cli
should do the trick.Linux folks, run
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
.
Logging In
Once Azure CLI is installed, open your command line and enter
az login
. Your web browser will open for you to sign in to your Azure account.
Check Subscription
Once logged in, confirm you're on the right subscription with
az account list
. If you have multiple subscriptions, set the right one usingaz account set --subscription="SUBSCRIPTION_ID"
.
Setting Up Terraform
With Azure CLI installed and logged in, Terraform is now ready to interact with Azure. If you run into any trouble, you can refer to the Azure CLI guide. It's a straightforward walkthrough to get Terraform and Azure on speaking terms and recaps some of these steps we just did in more detail.

Create a new GitHub repo for your Terraform configurations
Head over to GitHub and hit the New button.
Name your repo something like terraform-azure-hello-world.
Choose to make it public or private, and initialize it with a README.

Terraform and Your Repo
Clone your repo, and pop in a
main.tf
file.
provider "azurerm" {
features {}
}
provider "tls" {}
# Generate an RSA SSH key
resource "tls_private_key" "myprivatekey" {
algorithm = "RSA"
rsa_bits = 4096
}
# Save the private key locally
resource "local_file" "private_key" {
content = tls_private_key.myprivatekey.private_key_openssh
filename = "${path.module}/private_key.openssh"
}
# Save the public key locally
resource "local_file" "public_key" {
content = tls_private_key.myprivatekey.public_key_openssh
filename = "${path.module}/public_key.pub"
}
# Resource group
resource "azurerm_resource_group" "my_rg" {
name = "MyResourceGroup"
location = "East US"
}
# Virtual network
resource "azurerm_virtual_network" "my_vnet" {
name = "MyVNet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.my_rg.location
resource_group_name = azurerm_resource_group.my_rg.name
}
# Subnet
resource "azurerm_subnet" "my_subnet" {
name = "MySubnet"
resource_group_name = azurerm_resource_group.my_rg.name
virtual_network_name = azurerm_virtual_network.my_vnet.name
address_prefixes = ["10.0.2.0/24"]
}
# Network Security Group to allow SSH
resource "azurerm_network_security_group" "my_nsg" {
name = "MyNSG"
location = azurerm_resource_group.my_rg.location
resource_group_name = azurerm_resource_group.my_rg.name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# Public IP address
resource "azurerm_public_ip" "my_public_ip" {
name = "MyPublicIP"
location = azurerm_resource_group.my_rg.location
resource_group_name = azurerm_resource_group.my_rg.name
allocation_method = "Dynamic"
}
# Network Interface
resource "azurerm_network_interface" "my_nic" {
name = "MyNIC"
location = azurerm_resource_group.my_rg.location
resource_group_name = azurerm_resource_group.my_rg.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.my_subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.my_public_ip.id
}
}
# Associate NSG to NIC
resource "azurerm_network_interface_security_group_association" "myprivatekey" {
network_interface_id = azurerm_network_interface.my_nic.id
network_security_group_id = azurerm_network_security_group.my_nsg.id
}
# Virtual Machine
resource "azurerm_virtual_machine" "my_vm" {
name = "MyVM"
location = azurerm_resource_group.my_rg.location
resource_group_name = azurerm_resource_group.my_rg.name
network_interface_ids = [azurerm_network_interface.my_nic.id]
vm_size = "Standard_DS1_v2"
# Create the VM with an image from the marketplace
storage_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts-gen2"
version = "latest"
}
# Define the OS disk
storage_os_disk {
name = "myosdisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
# Computer name, admin username
os_profile {
computer_name = "myvm"
admin_username = "adminuser"
}
# SSH Key for the VM
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
path = "/home/adminuser/.ssh/authorized_keys"
key_data = tls_private_key.myprivatekey.public_key_openssh
}
}
}
Here's what this does:
Sets Up Azure Provider
Generates an RSA SSH Key
Stores SSH Keys Locally
Creates a Resource Group
Deploys a Virtual Network
Configures a Subnet
Establishes Network Security
Assigns a Public IP
Sets Up a Network Interface
Associates NSG to NIC
Launches a Virtual Machine
Uses an Ubuntu Image
Configures OS and Disk

Planning Our Azure Resources
cd
into your git repo folder (if you haven't already) and kick things off withterraform init
to prep your directory.Run
terraform plan
to peek into Terraform’s playbook. You'll get an output like something below (this is a snippet):
# azurerm_virtual_machine.my_vm will be created
+ resource "azurerm_virtual_machine" "my_vm" {
+ availability_set_id = (known after apply)
+ delete_data_disks_on_termination = false
+ delete_os_disk_on_termination = false
+ id = (known after apply)
+ license_type = (known after apply)
+ location = "eastus"
+ name = "MyVM"
+ network_interface_ids = (known after apply)
+ resource_group_name = "MyResourceGroup"
+ vm_size = "Standard_DS1_v2"
+ os_profile {
# At least one attribute in this block is (or was) sensitive,
# so its contents will not be displayed.
}
+ os_profile_linux_config {
+ disable_password_authentication = true
+ ssh_keys {
+ key_data = (known after apply)
+ path = "/home/adminuser/.ssh/authorized_keys"
}
}
+ storage_image_reference {
+ offer = "0001-com-ubuntu-server-jammy"
+ publisher = "Canonical"
+ sku = "22_04-lts-gen2"
+ version = "latest"
}
+ storage_os_disk {
+ caching = "ReadWrite"
+ create_option = "FromImage"
+ disk_size_gb = (known after apply)
+ managed_disk_id = (known after apply)
+ managed_disk_type = "Standard_LRS"
+ name = "myosdisk"
+ os_type = (known after apply)
+ write_accelerator_enabled = false
}
Since we're running the full plan, you'll have a lot more than this and it'll all be +
(creations) to Terraform. If you got this far, you've successfully written your first functioning Terraform configuration! Congratulations!
I don’t want to take too much longer on this since the code makes this quite long in terms of word count. Next time we’ll apply and actually create the infrastructure in Azure! Don’t miss it! Subscribe now and share with your colleagues who might find this useful!
Keep learning and keep growing,
Reply