Friday, October 21, 2011

Setting the WinRM HTTPS listener

A recent puzzle of mine has been to configure the HTTPS listener for WinRM.  You might ask; why?  Because it is supported!  And you supposedly can.

This applies to both WinRM and PowerShell remoting.

I say “supposedly” because this has been a messy trip.  And all of the documentation has been of nearly no help, leading me to believe that it is just supposed to work and I must be an idiot for it not working.

Back in 2008 I wrote about securing WinRM using a self signed certificate.  Well, guess what is now blocked.  Using self-signed certificates for WinRM.

So, we move forward, attempting to embrace the security model.

One thing to understand, when using HTTPS with WinRM you must:

  • have a certificate with a CN that matches the hostname of the server
  • use the hostname to connect to the remote machine

In my case I have a private CA that I use, and I simply import the CRL into each server as it is not published to allow CRL lookup.

There has been a litany of errors along the way, far too many for me to attempt to capture.  Lets just say that many have been very obscure and strange failures that have error messages with very little to do with the actual problem.

In the end there are two commands that you want to work on your Server; they are:

winrm create winrm/config/listener?Address=*+Transport=HTTPS @{Hostname=($env:COMPUTERNAME);CertificateThumbprint=($sslCert.Thumbprint)}

or

Set-WSManQuickConfig –useSSL

To get to this point you need to have a certificate authority, and you need to get your certificate on your server.  The CN of your certificate must match the servername (and this is picky too, the case / mixed case must match or you will get an error).  A tip – pay attention to the error message as it has the proper string that it is looking for.

WinRM runs under the NETWORK SERVICE security context.  This is pretty restrictive, so it most likely does not have access to the private key of your certificate.  Because it doesn’t have access it can’t do the encryption and nothing happens.  The setup fails.

Here is the little piece of script that fixes it all up:

$sslCert = Get-ChildItem Cert:\LocalMachine\My | where {$_.Subject -match $env:COMPUTERNAME}

"The installed SSL certificate: " + $sslCert.Subject

###  Give the Network Service read permissions to the private key.

$sslCertPrivKey = $sslCert.PrivateKey

$privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | where {$_.Name -eq $sslCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName}

$privKeyAcl = (Get-Item -Path $privKeyCertFile.FullName).GetAccessControl("Access")

$permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow"

$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission

$privKeyAcl.AddAccessRule($accessRule)

"Modifying the permissions of the certificate's private key.."

Set-Acl $privKeyCertFile.FullName $privKeyAcl

After you run this, then you can configure the HTTPS listener for WinRM using either of the commands I previously mentioned.

2 comments:

Anonymous said...

Great post.
FYI this must be executed at a DOS prompt and not in powershell.

BrianEh said...

winrm as a command can be executed in a PowerShell prompt (it is fully functional). And the PowerShell cmdlets are only available in the PowerShell prompt.
I am not sure of the reason for the statement.