Automating Azure Key Vault and Secrets using Terraform

One area that always need focus is around security and managing credentials. Using Terraform, and the method in this blog post, you can help build Azure Key Vault and create a secure secret to use when creating VMs, automatically.

To keep things secure, my method uses a combination of randomised password values, and Azure Key Vault. This post explains how to automate the creation of both of these, and use the Secret when setting up a Virtual Machine.

This code is also available in my GitHub repo: Terraform-Azure/Azure-KeyVault-with-Secret

The code does 4 main things to set this up:

  • Creates a random string with a prefix using the hashicorp/random provider for the Key Vault name.
  • Creates an Azure Key Vault with the randomised name – so that multiple people can deploy the environment and all get a different, unique, Key Vault Name. Permissions for Secret are set here too.
  • Creates a random string using the hashicorp/random_password provider for the Virtual Machine password.
  • Creates a Secret within the Key Vault called “vmpassword” using the generated password. This means that every deployment also has a different, unique password – just like the Key Vault name.

Creating a random string, and then creating an Azure Key Vault: 

This creates a random string with a prefix, so the output is keyvault##########. It then uses this value to create a Key Vault. Secret Permissions are also set within the Key Vault creation – so if you require any other permissions set here these will need to be added.

#Create KeyVault ID
resource "random_id" "kvname" {
  byte_length = 5
  prefix = "keyvault"
}

#Keyvault Creation
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault" "kv1" {
  depends_on = [ azurerm_resource_group.rg2 ]
  name                        = random_id.kvname.hex
  location                    = var.loc1
  resource_group_name         = var.azure-rg-2
  enabled_for_disk_encryption = true
  tenant_id                   = data.azurerm_client_config.current.tenant_id
  soft_delete_retention_days  = 7
  purge_protection_enabled    = false

  sku_name = "standard"

  access_policy {
    tenant_id = data.azurerm_client_config.current.tenant_id
    object_id = data.azurerm_client_config.current.object_id

    key_permissions = [
      "get",
    ]

    secret_permissions = [
      "get", "backup", "delete", "list", "purge", "recover", "restore", "set",
    ]

    storage_permissions = [
      "get",
    ]
  }
}

Note that if you need to use this Key Vault throughout your code, you can reference the random string result using: random_string.kvname.result

Creating a random password, and then creating a Secret within our Azure Key Vault: 

#Create KeyVault VM password
resource "random_password" "vmpassword" {
  length = 20
  special = true
}

#Create Key Vault Secret
resource "azurerm_key_vault_secret" "vmpassword" {
  name         = "vmpassword"
  value        = random_password.vmpassword.result
  key_vault_id = azurerm_key_vault.kv1.id
  depends_on = [ azurerm_key_vault.kv1 ]
}

Using the Secret when creating a Virtual Machine:

#Create VM
resource "azurerm_windows_virtual_machine" "dc01-vm" {
  name                = "dc01-vm"
  depends_on = [ azurerm_key_vault.kv1 ]
  resource_group_name = azurerm_resource_group.rg2.name
  location            = var.loc1
  size                = var.vmsize-domaincontroller
  admin_username      = var.adminusername
  admin_password      = azurerm_key_vault_secret.vmpassword.value
  network_interface_ids = [
    azurerm_network_interface.dc01-nic.id,
  ]
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "StandardSSD_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2019-Datacenter"
    version   = "latest"
  }
}

We can then access the Secret via the created Key Vault:

We can use the “Show Secret Value” option, or just copy it to the Clipboard:

I hope this has been useful! 😀 Please also check out best practises around storing/working with sensitive data in Terraform state files, as the generated value will be inside the state file.