Generate a Secure User Password for Azure VM with Terraform

In this blog post, we’ll explore how to generate secure user passwords for Azure VMs using Terraform during the VM creation step and output it.

Ensuring the security of your virtual machines (VMs) is critical in today’s dynamic digital landscape. One way to achieve this is by using strong and unique user passwords. By the end of this guide, you’ll know how to automate the creation of random passwords for your Azure VM, enhancing security and streamlining your workflow.

Generate a random password using Terraform

We’ll start with using the random_password resource to generate a random, secure password for the VM. Add the following block to your main.tf file. This configuration generates a 20-character password containing alphanumeric characters and special characters from the specified set.

resource "random_password" "set_password" {
  length      = 20
  min_lower   = 1
  min_upper   = 1
  min_numeric = 1
  min_special = 1
  special     = true
}

Define the Azure VM resource

Now, we’ll define an azurerm_virtual_machine resource, which represents your Azure VM. Replace the placeholders with the appropriate values for your environment. Notice the password configuration line admin_password = random_password.set_password.result

resource "azurerm_windows_virtual_machine" "winosvm" {
  name                            = "${var.winosprefix}-vm"
  resource_group_name             = azurerm_resource_group.rg.name
  location                        = azurerm_resource_group.rg.location
  size                            = "Standard_F2s_v2" 
  admin_username                  = "vmadmin"
  admin_password                  = random_password.set_password.result
  network_interface_ids = [
    azurerm_network_interface.winosnic.id,
  ]

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2022-datacenter-azure-edition"
    version   = "latest"
  }

  os_disk {
    storage_account_type = "Standard_LRS"
    caching              = "ReadWrite"
  }


}

Variables

If you would like to use our variables.tf copy it to your code.

variable "rg_name" {
  type        = string
  default = "Server2022"
  description = "The prefix used for all resources in this example"

}

variable "location" {
  type        = string
  default = "southeastasia"
  description = "The Azure location where all resources in this example should be created"
}

variable "vm_username" {
  type = string
  default = "vmadmin"

}

variable "winosprefix" {
  type = string
  default = "Win2022"
  description = "The prefix which should be used for all resources in this example"
}

variable "vnet_name" {
  type = string
  default = "win_vnet"

}

variable "subnet_name" {
  type = string
  default = "win_vms"

}

variable "nic_name" {
  type = string
  default = "winnic"
}

variable "vm_nsg" {
  type = string
  default = "win_nsg"
}

Output

To output the VM public IP address and password, we use the following output.tf file. Notice that the password section is set not to output the password to the terminal (sensitive set to true). You can change that to false however, we don’t recommend you do that.

The admin password will be available inside terraform.tfstate

output "public_ip_address" {
  value = azurerm_windows_virtual_machine.winosvm.public_ip_address
}


output "admin_password" {
  sensitive = true
  value     =  azurerm_windows_virtual_machine.winosvm.admin_password
}

The admin_password value inside the terraform.tfstate looks like:

 "outputs": {
    "admin_password": {
      "value": "random_password_value",
      "type": "string",
      "sensitive": true
    },

Full code

The full code to create a Windows Server 2022 VM and generate a random password is below.


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" "winosnic" {
  name                = "${var.winosprefix}-nic"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.winospublicip.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" "winosvm" {
  name                            = "${var.winosprefix}-vm"
  resource_group_name             = azurerm_resource_group.rg.name
  location                        = azurerm_resource_group.rg.location
  size                            = "Standard_F2s_v2" 
  admin_username                  = "vmadmin"
  admin_password                  = random_password.set_password.result
  network_interface_ids = [
    azurerm_network_interface.winosnic.id,
  ]

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2022-datacenter-azure-edition"
    version   = "latest"
  }

  os_disk {
    storage_account_type = "Standard_LRS"
    caching              = "ReadWrite"
  }


}


resource "azurerm_public_ip" "winospublicip" {
  name                = "${var.winosprefix}-pubip"
  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" {
    network_interface_id      = azurerm_network_interface.winosnic.id
    network_security_group_id = azurerm_network_security_group.nsg.id
}

resource "random_password" "set_password" {
  length      = 20
  min_lower   = 1
  min_upper   = 1
  min_numeric = 1
  min_special = 1
  special     = true
}

Processing…
Success! You're on the list.

Posted

in

, ,

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.