skip to Main Content

I currently having a working script to build Windows servers in Azure using the for_each expression against a variable map. At the moment I’m using a variable for the keyvault secret but this is then used by all the vm’s being created. How can I pass different keyvault secrets to each VM I’m building.

Inside my module I have the following. I’m passing the value of the keyvault secret via the var.winserver.pw. I’ve created additional keyvault secrets but don’t know how I would reference these when using a variable map. Any suggestions.

resource "azurerm_windows_virtual_machine" "winservertest" {

  for_each = var.vm_map
  name                = each.value.name
  resource_group_name = var.m_resource_group_name
  location            = var.m_location
  size                = each.value.size
  admin_username      = var.m_admin_username
  admin_password      = var.winserver-test-pw
  patch_mode               = "Manual" 
  enable_automatic_updates = false 
  network_interface_ids = [
    azurerm_network_interface.nic-multi-vms-01[each.key].id
  ]

2

Answers


  1. You are already doing it with the network vms-01[each.key] just like that we can change your pw to a map and do the same var.winserver-test-pw[each.key] your variable might have to change slightly to match the same keys as vm_map that is all …

    Here is an example we can test using random pet names

    variable "vm_map" {
      default = {
        "abc" = {}
        "def" = {}
      }
    }
    
    variable "vm_pw" {
      default = {
        "abc" = "aaa"
        "def" = "ddd"
      }
    }
    
    resource "random_pet" "test" {
      for_each = var.vm_map
      prefix   = var.vm_pw[each.key]
    }
    
    
    output "test" {
      value = random_pet.test
    }
    

    that output will be:

    Outputs:
    
    test = {
      "abc" = {
        "id" = "aaa-composed-bug"
        "length" = 2
        "prefix" = "aaa"
      }
      "def" = {
        "id" = "ddd-sure-gar"
        "length" = 2
        "prefix" = "ddd"
      }
    }
    
    Login or Signup to reply.
  2. I tried to pass different keyvault secrets to each VM I build using for_each expression and I was able to provision the requirement successfully.

    To do this, you need to write your Terraform configuration in a way that can automatically get the right secret for each VM.

    To enhance the user experience of your requirement, I generated random passwords and stored them in the vault as secrets. Since secrets are sensitive information, I retrieved them from the vault using data modules and applied them to the VM configuration.

    My demo terraform configuration:

    provider "azurerm" {
      features {}
    }
    
    variable "vm_names" {
      description = "Names of the VMs"
      type        = list(string)
    }
    
    # Data source to fetch current Azure client configuration
    data "azurerm_client_config" "current" {}
    
    # Resource Group
    resource "azurerm_resource_group" "example" {
      name     = "demorg-vk"
      location = "East US"
    }
    
    # Virtual Network
    resource "azurerm_virtual_network" "example" {
      name                = "demovk-vnet"
      address_space       = ["10.0.0.0/16"]
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
    }
    
    # Subnet
    resource "azurerm_subnet" "example" {
      name                 = "demovk-subnet"
      resource_group_name  = azurerm_resource_group.example.name
      virtual_network_name = azurerm_virtual_network.example.name
      address_prefixes     = ["10.0.2.0/24"]
    }
    
    # Network Interfaces for each VM
    resource "azurerm_network_interface" "example" {
      for_each = toset(var.vm_names)
    
      name                = "${each.key}-nic"
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
    
      ip_configuration {
        name                          = "internal"
        subnet_id                     = azurerm_subnet.example.id
        private_ip_address_allocation = "Dynamic"
      }
    }
    
    # Azure KeyVault
    resource "azurerm_key_vault" "example" {
      name                        = "demovkKVaultt"
      location                    = azurerm_resource_group.example.location
      resource_group_name         = azurerm_resource_group.example.name
      tenant_id                   = data.azurerm_client_config.current.tenant_id
      sku_name                    = "standard"
      soft_delete_retention_days  = 7
      purge_protection_enabled    = false
    }
    
    # Azure KeyVault Access Policy
    resource "azurerm_key_vault_access_policy" "example" {
      key_vault_id = azurerm_key_vault.example.id
    
      tenant_id = data.azurerm_client_config.current.tenant_id
      object_id = data.azurerm_client_config.current.object_id
    
      key_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore", "Decrypt", "Encrypt", "UnwrapKey", "WrapKey", "Verify", "Sign", "Purge", "Release", "Rotate", "GetRotationPolicy", "SetRotationPolicy"]
    
      secret_permissions = ["Get", "List", "Set", "Delete", "Recover", "Backup", "Restore", "Purge"]
    
      certificate_permissions = ["Get", "List", "Delete", "Recover", "Backup", "Restore", "Purge"]
    }
    
    # Random Passwords
    resource "random_password" "password" {
      for_each = toset(var.vm_names)
    
      length  = 16
      special = true
      override_special = "_%@"
    }
    
    # Store the Random Passwords in Azure KeyVault
    resource "azurerm_key_vault_secret" "example" {
      for_each    = random_password.password
    
      name         = "${each.key}-password"
      value        = each.value.result
      key_vault_id = azurerm_key_vault.example.id
    }
    
    # Azure Windows Virtual Machines
    resource "azurerm_windows_virtual_machine" "winservertest" {
      for_each = toset(var.vm_names)
    
      name                = each.key
      resource_group_name = azurerm_resource_group.example.name
      location            = azurerm_resource_group.example.location
      size                = "Standard_DS1_v2"
      admin_username      = "adminusername"
      admin_password      = azurerm_key_vault_secret.example[each.key].value
    
      network_interface_ids = [
        azurerm_network_interface.example[each.key].id,
      ]
    
      os_disk {
        caching              = "ReadWrite"
        storage_account_type = "Standard_LRS"
      }
    
      source_image_reference {
        publisher = "MicrosoftWindowsServer"
        offer     = "WindowsServer"
        sku       = "2019-Datacenter"
        version   = "latest"
      }
    }
    
    output "vm_ids" {
      value = { for vm in azurerm_windows_virtual_machine.winservertest : vm.name => vm.id }
    }
    

    Output:

    enter image description here

    enter image description here

    enter image description here

    enter image description here

    Here we can see that we have two unique secret passwords available in the vault, which help in creating two VMs.

    If you have your own predefined passwords stored in Azure KeyVault and to pass them to the VMs as passwords using Terraform

    Remove or comment out the random_password and azurerm_key_vault_secret resources for generating random passwords. Instead, use the data "azurerm_key_vault_secret" data source to fetch the existing secrets

    data "azurerm_key_vault_secret" "vm_passwords" {
      for_each    = toset(var.vm_names)
    
      name         = "${each.key}-password"  
      key_vault_id = azurerm_key_vault.example.id
    }
    

    and update the VM configuration module with

    admin_password = data.azurerm_key_vault_secret.vm_passwords[each.key].value
    

    The rest of the configuration will remain the same.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search