I explained in a previous post how to get the basics up and running.
There appear to be a few ways to do this in Terraform but I've only found one that works. I attempted to use the built in WinRM configuration option, but this requires creating a certificate locally and then uploading it to an Azure Key Vault. This sounds like a good option, but it can't yet be done purely in Terraform (I think!)
I've also tried creating a self signed certificate on the fresh build VM using the Windows FirstLogonCommands. This proved difficult due to all sorts of timing and character interpolation issues.
The working option is to create a PowerShell script, add in some variables from Terraform and then inject that script into the VM at creation time using the custom_data field as part of the os_profile section.
First, I created the Deploy.ps1 with no parameters which will create the local self-signed certificate and setup WinRM and a firewall rule.
Second, I created the FirstLogonCommands.xml which gets inserted into the Windows unattend.xml and runs the commands at first logon.
Third, in the Virtual Machine configuration of the .tf file, the vm is configured to inject the Deploy.ps1 data into the VM with parameters from Terraform. The VM is configured to automatically log on once which runs the FirstLogonCommands. This should then rename the custom_data blob back to Deploy.ps1, run it and configure WinRM!
The full example can be downloaded from my GitHub.
Part 3, Configuring an Azure RM load balancer is here.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Start-Transcript -Path C:\Deploy.Log | |
Write-Host "Setup WinRM for $RemoteHostName" | |
$Cert = New-SelfSignedCertificate -DnsName $RemoteHostName, $ComputerName ` | |
-CertStoreLocation "cert:\LocalMachine\My" ` | |
-FriendlyName "Test WinRM Cert" | |
$Cert | Out-String | |
$Thumbprint = $Cert.Thumbprint | |
Write-Host "Enable HTTPS in WinRM" | |
$WinRmHttps = "@{Hostname=`"$RemoteHostName`"; CertificateThumbprint=`"$Thumbprint`"}" | |
winrm create winrm/config/Listener?Address=*+Transport=HTTPS $WinRmHttps | |
Write-Host "Set Basic Auth in WinRM" | |
$WinRmBasic = "@{Basic=`"true`"}" | |
winrm set winrm/config/service/Auth $WinRmBasic | |
Write-Host "Open Firewall Port" | |
netsh advfirewall firewall add rule name="Windows Remote Management (HTTPS-In)" dir=in action=allow protocol=TCP localport=$WinRmPort | |
Stop-Transcript |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<FirstLogonCommands> | |
<SynchronousCommand> | |
<CommandLine>cmd /c "copy C:\AzureData\CustomData.bin C:\Deploy.PS1"</CommandLine | |
><Description>CopyScript</Description> | |
<Order>11</Order> | |
</SynchronousCommand> | |
<SynchronousCommand> | |
<CommandLine>powershell.exe -sta -ExecutionPolicy Unrestricted -file C:\Deploy.PS1</CommandLine | |
><Description>RunScript</Description> | |
<Order>12</Order> | |
</SynchronousCommand> | |
</FirstLogonCommands> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
os_profile { | |
computer_name = "${var.vm_name}" | |
admin_username = "${var.admin_username}" | |
admin_password = "${var.admin_password}" | |
#Include Deploy.PS1 with variables injected as custom_data | |
custom_data = "${base64encode("Param($RemoteHostName = \"${null_resource.intermediates.triggers.full_vm_dns_name}\", $ComputerName = \"${var.vm_name}\", $WinRmPort = ${var.vm_winrm_port}) ${file("Deploy.PS1")}")}" | |
} | |
os_profile_windows_config { | |
provision_vm_agent = true | |
enable_automatic_upgrades = true | |
additional_unattend_config { | |
pass = "oobeSystem" | |
component = "Microsoft-Windows-Shell-Setup" | |
setting_name = "AutoLogon" | |
content = "<AutoLogon><Password><Value>${var.admin_password}</Value></Password><Enabled>true</Enabled><LogonCount>1</LogonCount><Username>${var.admin_username}</Username></AutoLogon>" | |
} | |
#Unattend config is to enable basic auth in WinRM, required for the provisioner stage. | |
additional_unattend_config { | |
pass = "oobeSystem" | |
component = "Microsoft-Windows-Shell-Setup" | |
setting_name = "FirstLogonCommands" | |
content = "${file("FirstLogonCommands.xml")}" | |
} | |
} |
I was really looking for something like for a whole day and it works! Just some terraform syntax that has changed since your wrote this like "azurerm_virtual_machine" is now "azurerm_windows_virtual_machine" and the unattended config now looks like this (one of the two blocks)
ReplyDeleteadditional_unattend_content {
setting = "FirstLogonCommands"
content = file("FirstLogonCommands.xml")
}
Thank you!