Packer and WinRM – mystery resolved
A while ago I started exploring Hashicorp Packer in order to learn more about a new way of creating Windows template VMs. Traditionally, you create a VM, attach the Windows ISO file and of you go… But with Packer, you can define the whole thing in code and store that code in a repository where it’s centrally available.
But for some reason, I couldn’t get WinRM to function properly. Almost every blog I read about this subject uses a script to configure WinRM on the VM that is created.
Some use a self-signed certificate while others change traffic settings and authorization settings… Something like this:
winrm quickconfig -quiet winrm set winrm/config/service '@{AllowUnencrypted="true"}' winrm set winrm/config/service/auth '@{Basic="true"}'
To be sure about the settings I started with a Windows Server 2019 VM and tried to connect using the PowerShell CmdLet Test-WSMan.
Default authentication
Test-WSMan -ComputerName 192.168.199.100 -Authentication Default -Credential Administrator
And it didn’t work… The error I received:
The WinRM client cannot process the request. Default authentication may be used with an IP address under the following conditions: the transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided.
Hmm. For HTTPS I needed to change a lot. Configure a listener, create a certificate, and link it all together. Why not start with the TrustedHosts list? On the connecting computer (the WinRM client) I configured the TrustedHosts to *:
Set-WSManInstance -ResourceURI WinRM/Config/Client -ValueSet @{TrustedHosts="*"}
And did the test again… Now I did not get an error but a connection:
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd ProductVendor : Microsoft Corporation ProductVersion : OS: 10.0.17763 SP: 0.0 Stack: 3.0
Basic authentication
The second test I did was with Basic authentication.
Test-WSMan -ComputerName 192.168.199.100 -Authentication Basic -Credential Administrator
This fails with an error:
The WinRM client cannot process the request. The authentication mechanism requested by the client is not supported by the server or unencrypted traffic is disabled in the service configuration.
If you want to use Basic authentication you do need the change the service settings on the WinRM host.
Set-WSManInstance -ResourceURI WinRM/Config/Service -ValueSet @{AllowUnencrypted = "true"} Set-WSManInstance -ResourceURI WinRM/Config/Service/Auth -ValueSet @{Basic = "true"} Restart-Service WinRM
So a default installed Windows server with Server 2019 has all the bits and pieces to be used as a WinRM host. You only need to change the TrustedHosts setting on the client, and you need to be on the same subnet. This last requirement comes from the public network connection on the host and the firewall on that host. If you change the connection to private you might need to change the firewall on the WinRM host.
HTTPS Authentication
With Basic authentication, your credentials are sent unencrypted. So not the most secure method. You can use SSL to send your credentials encrypted.
Test-WSMan -ComputerName 192.168.199.100 -Authentication Basic -Credential Administrator -UseSSL
This test fails because there is no WinRM listener, and the firewall drops traffic on port 5986 (the secure WinRM port). What do we need to do in order to make this work?
- Create a self-signed certificate.
- Create a WinRM listener on port 5968 (HTTPS).
- Configure Basic authentication.
- Create firewall rule to allow traffic on port 5968.
Create self-signed certificate…
$IP = (Get-NetIPAddress -InterfaceAlias "Ethernet*" -AddressFamily IPv4).IPAddress $CertificateThumbprint = (New-SelfSignedCertificate -DnsName $env:COMPUTERNAME,$IP -CertStoreLocation "Cert:\LocalMachine\My").Thumbprint
Create WinRM listener…
$listener = @{ ResourceURI = "winrm/config/Listener" SelectorSet = @{Address="*";Transport="HTTPS"} ValueSet = @{CertificateThumbprint=$CertificateThumbprint} } New-WSManInstance @listener
Enable Basic authentication
Set-WSManInstance -ResourceURI WinRM/Config/Service/Auth -ValueSet @{Basic = "true"}
And finally create the firewall rule…
$rule = @{
Name = "WINRM-HTTPS-In-TCP"
DisplayName = "Windows Remote Management (HTTPS-In)"
Description = "Inbound rule for Windows Remote Management via WS-Management. [TCP 5986]"
Enabled = "true"
Direction = "Inbound"
Profile = "Any"
Action = "Allow"
Protocol = "TCP"
LocalPort = "5986"
}
New-NetFirewallRule @rule
Now when I test the connection the only “error” I receive is about the certificate. Because it is self-signed my computer doesn’t trust the signer…
But now we can configure Packer to use SSL:
winrm_use_ssl – If true, use HTTPS for WinRM.
winrm_insecure – If true, do not check server certificate chain and host name