How to use WSMan config provider for certificate authentication
WSMan Client certificate authentication is primarily used in non-domain cases: client can specify certain certificate as credential, after authentication each other, it’s mapped to a local account on the server, meaning the WinRM service runs under the context of the mapped account when processing the request. When using client certificates, multiple client certificates can be mapped to a single account using pattern matching rules
In this blog, we discuss three topics:
• Enable config settings for certificate auth
• Configure cert mapping entry on the server machine
• Perform remote operation using certificate auth on the client machine
1) Enable config settings for certificate auth
There’re specific config settings that control whether WinRM client and service will support Certificate Based Authentication
1.a) Client stack support for certificate auth is enabled by default, so you don’t need to change it if Certificate Based Authentication is desired
PS C:\Windows\system32> dir WSMan:\localhost\Client\Auth\Certificate
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client\Auth
Name Value Type
---- ----- ----
Certificate true System.String
1.b) Service support for certificate auth is disabled by default to reduce attack surface, so you’ll have to explicitly enable it if Certificate Based Authentication is desired
PS C:\Windows\system32> dir WSMan:\localhost\Service\Auth\Certificate
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Service\Auth
Name Value Type
---- ----- ----
Certificate false System.String
PS C:\Windows\system32> set-item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
2) Configure cert mapping entry
There are no entries in the certificate mapping table by default, but you can use certificate mapping resource URI "https://schemas.microsoft.com/wbem/wsman/1/config/service/certmapping" to perform get, put, create, delete, and enumerate operations using WSMan-related PS cmdlet such as “Get-WSManInstance, Set-WSManInstance, New-WSManInstance, Remove-WSManInstance”, but here in this blog I show examples using WSMan config provider instead as demonstrated by the following traversal.
PS C:\Windows\system32> cd WSMan:\localhost\ClientCertificate
PS WSMan:\localhost\ClientCertificate>
Before configuring cert mapping entries on the server machine, let’s look at some of the key properties in the cert mapping entry
• Subject : it’s the Subject field or Subject Alternative Name (SAN) field of client certificate, which contains the name of the entity that the certificate was issued to, first “*” character could match anything. For example:
o If the certificate is issued to a user: then it contains the username in the form “Principal Name=user@domain.com”
o If the certificate is issued to a machine: then it contains the name of the machine in the form “DNS Name=machine.foo.com”
• Issuer: it’s the certificate thumbprint of the CA that issued the certificate. The certificate identified by the thumbprint must be present in the server machine “CA” store. The certificate must have key usage that allows it to sign other certificates (CERT_KEY_CERT_SIGN_KEY_USAGE), unless it’s a self-signed certificate in which case the key usage is not required
• URI: it’s the URI or URI prefix for which this cert mapping will apply, last “*” character could match anything
2.1) Create cert mapping entry if the entry does not already exist, following PS script automates this process: first find user certificate which has the usage “Client Authentication (1.3.6.1.5.5.7.3.2)” as this is required for subsequent client cert auth; then get ISSUER name for the above user certificate, get the ISSUER thumbprint, which was used in the last line to create cert mapping entry, so remote access to WinRM using client certificates is mapped to user “certAdminAccount1” on the server machine. Please note if this local user is not in “administrators” group, you need to configure security to allow non-admin through but this is out of the scope of this blog, We’ll discuss “How to configure security for different URI” in a separate blog.
foreach ($cert in get-childitem cert:\CurrentUser\My)
{
foreach ($ext in $cert.Extensions)
{
if ($ext.Oid.FriendlyName -eq "Enhanced Key Usage")
{
$ekey = [System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]$ext
$oids = $ekey.EnhancedKeyUsages
foreach ($oid in $oids)
{
if ($oid.FriendlyName -eq "Client Authentication")
{
$usercerts=$cert
}
}
}
}
}
if ($usercerts.count -eq $null) {$issuername = (, $usercerts)[0].Issuer} else {$issuername = $usercerts[0].Issuer}
$IssuerThumbprint=(get-childitem -path cert:\CurrentUser\ca | where-object { $_.Subject -eq $issuername }).Thumbprint
net user certAdminAccount1 /delete
net user certAdminAccount1 Dummy_pswd /add
net localgroup administrators certAdminAccount1 /add
$password = ConvertTo-SecureString Dummy_pswd -AsPlainText –Force
$adminuser = New-Object System.Management.Automation.PSCredential certAdminAccount1,$password
New-Item -Path WSMan:\localhost\ClientCertificate -URI https://microsoft.test.mig.wsman/\* -Subject *.com -Issuer $IssuerThumbprint -Credential $adminuser -force
Output is similar to the following
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\ClientCertificate
Name Type Keys
---- ---- ----
ClientCertificate_6047... Container {URI=https://microsoft.test.mig.wsman/*, Issuer=1B3FD224D66C6413FE20D2...
2.2) Get cert mapping entry with specific keys if the entry exists
PS C:\Windows\System32> Get-Item -Path WSMan:\localhost\ClientCertificate\ClientCertificate_604778647\* -force
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\ClientCertificate\ClientCertificate_604778647
Name Value Type
---- ----- ----
URI https://microsoft.test.mig.wsman/\* System.String
Subject *.com System.String
Issuer 1B3FD224D66C6413FE20D21E38B304226D192DFE System.String
UserName certAdminAccount1 System.String
Enabled true System.String
Password System.String
2.3) change any non-keys of cert mapping entry if the entry already exists [The Issuer, Subject, and URI properties are keys for the purposes of WS-Transfer operations.]
PS C:\Windows\System32> Set-Item WSMan:\localhost\ClientCertificate\ClientCertificate_604778647\Enabled $true -force
2.4) Enumerate will list all existing cert mapping entries
PS C:\Windows\System32> Get-Item -Path WSMan:\localhost\ClientCertificate\* -force
WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\ClientCertificate
Name Type Keys
---- ---- ----
ClientCertificate_6047... Container {URI=https://microsoft.test.mig.wsman/*, Issuer=1B3FD224D66C6413FE20D2...
2.5) Delete cert mapping entry if the entry exists
PS C:\Windows\System32> Remove-Item -Path WSMan:\localhost\ClientCertificate\ClientCertificate_* -Recurse -force
3) Perform remote operation using certificate auth on the client machine
In the above first step, you enable both client and server config settings for certificate auth. In the second step, you configure cert mapping entry on the server machine that defines the actual mapping behavior. So here’s the final step on how to perform remote operation using certificate auth. These demo scripts in this blog may need to be changed a little bit to make it work for yourself such as valid URI, valid server name etc…
3.1) On the server machine you must have https listener and port is opened for through traffic, as client certificate authentication is allowed only when connecting to a https address.
PS D:\Windows\system32> Set-WSManQuickConfig -UseSSL -Force
WinRM already is set up to receive requests on this machine.
WinRM has been updated for remote management.
Created a WinRM listener on HTTPS://* to accept WS-Man requests to any IP on this machine.
Configured CertificateThumbprint setting for the service.
PS D:\Windows\system32> netsh advfirewall firewall add rule name="Port 443" dir=in action=allow protocol=TCP localport=443
Ok.
3.2) On the client machine, following PS script demonstrates the process to perform a remote GET operation using certificate auth: first find user certificate which has the usage “Client Authentication (1.3.6.1.5.5.7.3.2)” as this is required for client cert auth; its thumbprint was used in the last line as the client credential
foreach ($cert in get-childitem cert:\CurrentUser\My)
{
foreach ($ext in $cert.Extensions)
{
if ($ext.Oid.FriendlyName -eq "Enhanced Key Usage")
{
$ekey = [System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]$ext
$oids = $ekey.EnhancedKeyUsages
foreach ($oid in $oids)
{
if ($oid.FriendlyName -eq "Client Authentication")
{
$usercertThumbprint=$cert.Thumbprint
}
}
}
}
}
winrm g https://microsoft.test.mig.wsman/test -r:https://machine.STBTEST.MICROSOFT.COM -a:certificate -certificate:$usercertThumbprint
Comments
Anonymous
March 23, 2009
PingBack from http://blog.a-foton.ru/index.php/2009/03/24/how-to-use-wsman-config-provider-for-certificate-authentication/Anonymous
November 28, 2012
Hi, It is very informative and very helpful on my research regarding seo techniques. Thanks for sharing this post. <a href="www.certificate-attestation.in/apostille.html">Apostille </a>.Anonymous
December 09, 2015
For the client certificate, you say If the certificate is issued to a user: then it contains the username in the form “Principal Name=user@domain.com” Local users aren't in domains. What is the SAN for them?