In this blog post, we will show you how to use Terraform to deploy multiple Windows 11 virtual machines (VMs) in Azure.
The following code will also join the VM to Azure AD however we have included instructions on how to not join the VMs to Azure AD.
Terraform is an open-source infrastructure as code tool that enables you to create, change, and improve your infrastructure on various cloud providers such as AWS, Azure, and Google Cloud. It provides a simple and efficient way to manage infrastructure as code, making it easier to manage and maintain your infrastructure.
Code
The following configuration will create a number of machines that are set in a variable called var.num_vms
.
The following code will also join the VMs to Azure AD. If you don’t need the VMs to be joined to Azure AD, remove the following sections:
- identity { type = “SystemAssigned” }
- resource “azurerm_role_assignment” “assign-vm-role”
- resource “azurerm_virtual_machine_extension” “aadlogin”
resource "azurerm_resource_group" "rg" {
name = var.rg_name
location = var.location
}
resource "azurerm_virtual_network" "vnet" {
name = var.vnet_name
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_subnet" "subnet" {
name = var.subnet_name
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_network_interface" "win11nic" {
count = var.num_vms
name = "${var.win11prefix}-nic-${count.index}"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
ip_configuration {
name = "internal-nic-${count.index}"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.win11publicip[count.index].id
}
}
resource "azurerm_network_security_group" "nsg" {
name = var.vm_nsg
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
security_rule {
name = "RDP"
priority = 101
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
resource "azurerm_windows_virtual_machine" "win11vm" {
count = var.num_vms
name = "${var.win11prefix}-vm-${count.index}"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = "Standard_F2s_v2"
admin_username = "vmadmin"
admin_password = var.vm_password
network_interface_ids = [
azurerm_network_interface.win11nic.*.id[count.index],
]
source_image_reference {
publisher = "microsoftwindowsdesktop"
offer = "windows-11"
sku = "win11-22h2-pro"
version = "latest"
}
os_disk {
name = "${var.win11prefix}-disk-${count.index}"
storage_account_type = "Standard_LRS"
caching = "ReadWrite"
}
identity {
type = "SystemAssigned"
}
}
resource "azurerm_public_ip" "win11publicip" {
count = var.num_vms
name = "${var.win11prefix}-${count.index}"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
allocation_method = "Dynamic"
}
resource "azurerm_network_interface_security_group_association" "securitygroup" {
count = var.num_vms
network_interface_id = azurerm_network_interface.win11nic[count.index].id
network_security_group_id = azurerm_network_security_group.nsg.id
}
resource "azurerm_virtual_machine_extension" "aadlogin" {
count = var.num_vms
name = "AADLoginForWindows"
virtual_machine_id = azurerm_windows_virtual_machine.win11vm[count.index].id
publisher = "Microsoft.Azure.ActiveDirectory"
type = "AADLoginForWindows"
type_handler_version = "2.0"
}
resource "azurerm_role_assignment" "assign-vm-role" {
scope = azurerm_resource_group.rg.id
role_definition_name = "Virtual Machine Administrator Login"
principal_id = var.principal_id
}
For more Azure and Terraform posts, visit the main category page.