WinRM with non-domain joined machine using Certs

Morning all,

Background:
Hyper-V server running in a Workgroup (as it hosts the DC)
Client workstation domain joined

Requirement
Use WinRM from workstation to Hyper-V server so that the VMs can be suspended and the server shutdown. Password should not be stored and process needs to be scheduled

Solution
WinRM and therefore PowerShell have the ability to use client certificate mapping for mutual trust allowing a remote session to run under the context of a local user on the non-domain joined server.

Problem
I’m struggling to configure the pre-reqs as it doesn’t seem a topic that is particularly well covered, the best information I have found is from http://blogs.msdn.com/b/wmi/archive/2009/03/23/how-to-use-wsman-config-provider-for-certificate-authentication.aspx

Does anyone know the certificate store that needs to contain the user certificate for mapping? I envisaged I would need the user certificate on the domain joined workstation to be exported and placed in the certificate store of the non-domain joined server. That cert would then be mapped to a local user account on the server. When establishing a remote session from the workstation I’d reference the thumbprint of the cert (local to the workstation for the user) and provide it to the server which would see that it was mapped to a local user and therefore the remote session would run under this context? However, analysing the blog instructions (referenced above) this doesn’t seem to be the case.

Paul

Anything on the remote machine would need to be in the computer store, I’d imagine. But this is one scenario I’ve never set up - it might actually be worth you opening a support ticket with MS, and then doing a writeup.

I got this working in a test environment, but it took a lot of fiddling. Here are the two “gotchas” that I remember from my setup:

  • The basic "User" certificate template didn't work; WSMan was complaining about the contents of the Subject Alternative Name field. I had to create a new certificate template that only contained the User Principal Name in the SAN field.
  • The user's certificate does have to be imported on the computer you're connecting to. I got it working by importing the certificate into "Trusted People" in the Local Machine store. (I didn't find documentation for this anywhere, but it seemed like a reasonable guess, and it worked).

Other than that, the steps in the blog post you linked are reasonably accurate. I wouldn’t recommend setting a “Subject” value with wildcards, as the blog showed in the example (unless you want basically anyone with the right type of certificate to be able to administer your machine with WinRM). The command I used to create the mapping (minus the actual certificate thumbprint, because I don’t feel like typing that all out), was:

New-Item -Path WSMan:\localhost\ClientCertificate -Subject 'dlwyatt@testdomain.local' -URI * -Issuer '<CA Certificate thumbprint>' -Credential (Get-Credential) -Force

Once that was done (along with all the usual steps to set up WinRM with an HTTPS listener and open up Windows Firewall on port 5986), I was able to issue these commands from my client computer:

$session = New-PSSession -ComputerName Win2008VM -UseSSL -CertificateThumbprint <Client certificate thumbprint>
Enter-PSSession $session

Oddly, I was not able to run “Enter-PSSession -ComputerName Win2008VM -UseSSL -CertificateThumbprint <thumbprint>”; I got back a Kerberos error. I’m not sure why New-PSSession worked and Enter-PSSession didn’t.

I went through the process again on different VMs, to see if I missed anything in the last post. The only other tricky point was that I had to import the certificate for the CA that signed the HTTPS certificate of the target computer into the user’s “Trusted Root Certification Authorities” store. If it was imported in any other place (either in the local machine store, or in the “Intermediate Certification Authorities” user store), I’d still get errors to the effect of “the SSL certificate is signed by an untrusted authority.”

Also, (though this won’t affect you in your workgroup scenario), I couldn’t create a certificate mapping with the credentials of a domain account (I tried this when testing a “PS Remoting to a computer in an untrusted domain” scenario). WSMan would only let me set up a ClientCertificate mapping using a local account’s credentials.

Dave, any interest in doing a write-up of the procedure? I’d like to add it (crediting you, of course) to “Secrets of PowerShell Remoting,” since it’s one of the rarer use cases right now, and not really well documented.

Sure, I can do that. It’ll be fairly short, since you already have a full section on setting up an HTTPS Listener in that book.

Do you have a document template you’d like me to use, or should I just get the content into Word and let you format it later?

A Word doc is fine. I’ll have to merge it into the main document, which isn’t done in Word (I use Pages; it makes it easier to produce the EPUB format in addition to PDF).

[quote=9742]I got this working in a test environment, but it took a lot of fiddling…
[/quote]

Thanks Dave, now I know someone has got it to work and the way you described it makes a lot of sense. I will give this a go shortly and report back.

Paul

Strange. While I was going through all this again for the write-up, I couldn’t reproduce the certificate errors I had last night. I was able to authenticate successfully with a certificate based on the plain v1 “User” template that ships with AD CS. That makes the process much simpler (since any old Client Authentication certificate with a UPN in the Subject Alternative Name field should work), but now I don’t know why I had those errors last night.

The error I was receiving (and now cannot reproduce) was ERROR_WSMAN_CLIENT_INVALID_CERT_DNS_OR_UPN: The WinRM client cannot process the request. If you are using a machine certificate, it must contain a DNS name in the Subject Alternative Name extension or in the Subject Name field, and no UPN name. If you are using a user certificate, the Subject Alternative Name extension must contain a UPN name and must not contain a DNS name. Change the certificate structure and try the request again.

When I received the errors, I was using a v2 certificate based on the “User” template which contained both the UPN and the Email Name attributes in the Subject Alternative Name extension. Today, I was able to use three different certificate templates successfully (including the same one from last night).

Here’s a draft of the process. It probably needs some polishing (and testing on clean systems, different operating systems / PowerShell versions, etc), but the basic content of what worked in my lab is there. As time allows, I’ll rebuild my VMs to perform some of those tests from scratch.

Since I couldn’t reproduce the certificate errors, I removed the section on creating a new certificate template for WinRM authentication (which made the document about 1/3 shorter). If that content turns out to be required, I still have the original document.

Just finished retesting on clean installations. Everything worked fine (no certificate errors with the User template). The only explanation I can think of is that maybe I copied and pasted the wrong thumbprint on my first attempt the other night.

Dave,

I’ve tried this for myself and it isn’t working. On connection from remote machine to non-domain joined PC I get the following error:

New-PSSession : [Computer] Connecting to remote server Computer failed with the
following error message : WS-Management cannot process the request. The
operation failed because of an HTTP error. The HTTP error (12185) is: . For
more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:12

Could you please screenshot the client certificate calling out the subject field and subject alternate name for comparison?

Paul

Looks like error 12185 is ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY. It’s probably the SSL cert that’s missing its key and not the client cert, but you should check both.

Now that I’m back at my home computer, I can post these screenshots you requested. The three “ClientCert” screenshots come from the “Certificates - Current User” console on the client computer. “SSLCert” and “ClientTrust” screenshots are from the “Certificates - Local Computer” console of the remote computer. The ClientTrust.PNG screenshot is there for contrast with ClientCert1.PNG, showing that the client computer has the private key, and the remote computer doesn’t need it.

Dave,

Many thanks for taking the screenshots as it has helped me to determine that the user cert on domain joined machine doesn’t have the private key. I need to look at the CA templates. For reference this cert was generated automatically through auto-enrolment using a Windows 2012 Server Essentials deployment.

Paul

This was certainly an interesting read and I learned something from it. From a beginners perspective I was trying to think about how to accomplish this. How come you cannot just set the trustedhosts file on the workgroup computer? Something like:

set-item wsman:\localhost\Client\TrustedHosts -value <ComputerName>
set-item wsman:\localhost\Client\TrustedHosts -value 192.168.x.x

Now from my workgroup machine, I should be able to run my command on the Hyper-V server using -credential parameter.

Here’s why. Let’s call the initiating machine CLIENT, and the remote target SERVER.

With your suggestion, which is functional, CLIENT won’t care if it’s actually connecting to SERVER. That’s what TrustedHosts does: tells CLIENT, “hey, don’t worry about someone spoofing the target, just connect and send off the credential.” A bit like laying your car keys on the lawn and hoping for the best.

Also, with your suggestion, you have to provide a credential that the remote machine will recognize. That’s transmitted in clear text, unless an NTLM negotiation happens.

Your suggestion also doesn’t give SERVER any real control over who can connect. Anyone capable of providing a username and password could so so.

With the certificate-based approach that’s been discussed, CLIENT does indeed know that SERVER is actually SERVER, because the server certificate says so. Also, SERVER can authenticate CLIENT based on a client certificate mapping, so you don’t have to send off a credential. The credential isn’t sent in the clear, thanks both to the certificate and to the SSL channel.

So the certificate approach is more secure from a number of perspectives. It’s a much better long-term, production-quality approach, although it obviously does take more work to set up. Not that your suggestion is wrong at all - it just doesn’t meet some of the security requirements that the above discussion revolved around. Your approach is easier, and if all I needed to do was temporarily connect (maybe to a new server that I was going to add to the domain), I’d totally go that route.

[quote=9797]Here’s why. Let’s call the initiating machine CLIENT, and the remote target SERVER.
With your suggestion, which is functional, CLIENT won’t care if it’s actually connecting to SERVER. That’s what TrustedHosts does: tells CLIENT, “hey, don’t worry about someone spoofing the target, just connect and send off the credential.” A bit like laying your car keys on the lawn and hoping for the best.
Also, with your suggestion, you have to provide a credential that the remote machine will recognize. That’s transmitted in clear text, unless an NTLM negotiation happens.
Your suggestion also doesn’t give SERVER any real control over who can connect. Anyone capable of providing a username and password could so so.
With the certificate-based approach that’s been discussed, CLIENT does indeed know that SERVER is actually SERVER, because the server certificate says so. Also, SERVER can authenticate CLIENT based on a client certificate mapping, so you don’t have to send off a credential. The credential isn’t sent in the clear, thanks both to the certificate and to the SSL channel.
So the certificate approach is more secure from a number of perspectives. It’s a much better long-term, production-quality approach, although it obviously does take more work to set up. Not that your suggestion is wrong at all – it just doesn’t meet some of the security requirements that the above discussion revolved around. Your approach is easier, and if all I needed to do was temporarily connect (maybe to a new server that I was going to add to the domain), I’d totally go that route.
[/quote]

Well it’s good to know that I’m not completely crazy :slight_smile: I was also thinking that my approach would only be run in a test/development network only.

Yup, and in a test/dev environment I’d do exactly that. This whole discussion has been about a production environment, and I’m really glad to see someone thinking about the security of that - certificates are totally the way to go.

FWIW, EVERYONE should have at least a basic PKI set up to issue SSL certs to servers, and ideally to issue client certs to clients. Certs play a huge, and growing, role in IT, especially Microsoft IT. If you’re not up on AD CS, get up on it.

[quote=9799]FWIW, EVERYONE should have at least a basic PKI set up to issue SSL certs to servers, and ideally to issue client certs to clients. Certs play a huge, and growing, role in IT, especially Microsoft IT. If you’re not up on AD CS, get up on it.
[/quote]

Couldn’t agree more Don. Four years ago I knew very little about PKI beyond SSL certificates on websites. I forced myself to learn because I hated our Exchange certificates generating an error and wanted to know how I could stop this from happening. I discovered UCC certs and SAN names and from there my knowledge has slowly expanded to now be driving the requirements for an internal PKI infrastructure. LDAP look-ups on domain controllers, TLS for secure email exchange, network security in 802.1x, everything to do with mobility, code-signing, stop setting execution policy in PowerShell to unsigned and use remote signed, etc, etc. It’s all PKI and happening now, the beauty of AD is that lots of the complexity can be made transparent to the end user, as long as the AD IT Pro knows the possibilities.

Paul