How to Configure WinRM over HTTPS for Ansible

choubertsprojects

VPN offers!

1. NordVPN

2. Surfshark

3. ExpressVPN

Ansible is a configuration management and IT automation tool that can be used to set up, configure, and deploy software on multiple systems. WinRM is Microsoft’s implementation of over-the-internet Remote Management technology. It provides remote administration capabilities for Windows computers as a service through the use of HTTP or HTTPS protocols. In this article, we will show you how to enable Ansible to communicate with your machines via WinRM when using an SSL certificate configured for HTTPS transport security.,

How to Configure WinRM over HTTPS for Ansible

Ansible uses WinRM to communicate with remote machines. It is possible to configure WinRM over HTTPS for Ansible, but it must be done manually.

Ansible is quickly becoming one of, if not the most popular, configuration management tools available. Ansible is a useful (and, in most instances, free) tool that enables DevOps engineers, system engineers, and administrators to develop and manage infrastructure across many environments in an idempotent, infrastructure-as-code way. However, setting it to communicate with Windows (Ansible using WinRM) might be difficult.

Ansible can deploy and manage configuration state across Windows hosts, much as many other infrastructure components. Although they’re experimenting with SSH, Ansible connects to these Windows systems using WinRM.

When using WinRm to connect to Windows hosts, you have a few choices ranging from simplicity of setup to security consequences. Many individuals opt for the simple solution of basic HTTP authentication. Even if you skip the certificate procedure, it’s never a good idea to transfer unencrypted data across a network unless absolutely necessary.

In this article, you’ll learn how to configure WinRm to use self-signed certificates for certificate-based authentication so that Ansible can communicate with it.

This tutorial’s configuration isn’t limited to Ansible as the client. Other WinRm clients, as well as other Windows hosts, may use certificate-based authentication.

Assumptions

This post will be a walkthrough with tutorials. The tutorial will assume the following if you wish to follow the instructions outlined here:

  • Ansible is already installed on a Linux host.
  • Based on your Windows hosts, you’ve created an Ansible inventory.
  • You’re in charge of a Windows Server 2016 or later. Some of the cmdlets in this lesson will not operate in previous Windows versions.
  • There is no domain for the Windows host. Despite the fact that the examples were conducted on a non-domain-joined host, the setup should work on domain-joined servers as well.
  • You are signed in as a local administrator and have RDP or console access to the Windows host.
  • You’ve used PowerShell before. To make changes on the Windows host, almost all examples will utilize PowerShell code.

Each part will employ a piece of code that is dependent on the previous one. Some snippets will refer to variables that were previously declared. If you’re going to copy/paste this code verbatim, be sure to keep your terminal open while doing so.

You may download this GitHub gist if you only want the code without the explanation.

For Ansible WinRM, enable PowerShell Remoting.

Although PowerShell Remoting is enabled on all servers running Windows Server 2016 or later, it’s always a good idea to double-check.

Open a PowerShell console as an administrator on the Windows host to manage and execute the following code snippet. The WinRm service is launched and configured to start automatically when the machine boots up using this code snippet.

Start-Service -Name “WinRM” -StartupType Automatic Set-Service -Name “WinRM” -StartupType Automatic Start-Service -Name “WinRM”

Next, verify whether PowerShell Remoting is enabled by looking for any current session setups. If it doesn’t, make sure it doesn’t have any listeners. At least one listener is required by WinRm. Run Enable-PSRemoting if none of these criteria returns nothing.

(-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:localhostListener)) if ## Use SkipNetworkProfileCheck to make public profiles visible even on Windows Firewall. ## Use Force to avoid being asked whether we’re sure. -SkipNetworkProfileCheck -Force Enable-PSRemoting

Authentication using certificates is enabled.

WinRM is not set for certificate-based authentication by default. This must be enabled using the WSMan configuration provided below.

#region Enable certificate-based authentication Set-Item -Value $true -Path WSMan:localhostServiceAuthCertificate #endregion

Create a User Account for Local Use

You must “map” a local user account to a certificate to utilize certificate-based authentication with Ansible. You could accomplish this using the local administrator account, but it’s usually better to establish a separate account to make maintenance simpler.

If no such account exists, the following code snippet creates one named ansibletestuser with the password [email protected]$w0rd12. That account’s password will never expire to guarantee that it is constantly current.

$ansibletestuser = $testUserAccountName (ConvertTo-SecureString -String ‘[email protected]’) $testUserAccountPassword if (-not (Get-LocalUser -Name)) $w0rd12′ -AsPlainText -Force) $testUserAccountName -IgnoreErrorAction)) @ $newUserParams = $newUserParams AccountNeverExpires = $true PasswordNeverExpires = $true Password = $testUserAccountPassword Name = $testUserAccountName @newUserParams $null = New-LocalUser

Make a Client Certificate.

You’ll need two certificates to enable certificate-based authentication with Ansible: a client cert and a server cert.

You may use the same certificate for both client and server, although this technique caused me troubles. You may find instructions for producing the client certificate using PowerShell’s New-SelfSignedCert cmdlet in the Ansible manuals and many other places. Although this strategy could work, I couldn’t get it to work for me.

To Make a Client Certificate., you must create a private and a public key. Start by SSHing to the Ansible host and run the following openssl command. This command creates a private key in a file called cert_key.pem and a public key called cert.pem. The key usage will be client authentication (1.3.6.1.4.1.311.20.2.3) “mapped” to the local user account you created earlier called ansibletestuser.

## This is the public key generated from the Ansible server using: cat > openssl.conf << EOL distinguished_name = req_distinguished_name [req_distinguished_name] [v3_req_client] extendedKeyUsage = clientAuth subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:[email protected] EOL export OPENSSL_CONF=openssl.conf openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj “/CN=ansibletestuser” -extensions v3_req_client rm openssl.conf

Ansible WinRM authentication is one step closer!

Import the Certificate of the Client

You’ll need to import the client certificate into two certificate stores on the Windows server once you’ve generated it on the Ansible host. To do so, first copy the public key cert.pem to the Windows host. The following example assumes the key is located at C:cert.pem.

Import the public certificate into the Trusted Root Certification Authorities and Trusted People certificate stores on the Windows host using Import-Certificate, as illustrated below.

‘C:cert.pem’ as $pubKeyFilePath ## Use Trusted Root Certification Authorities and Trusted People to import the public key. Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineRoot’ $pubKeyFilePath Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineTrustedPeople’ $pubKeyFilePath

Make a certificate for the server.

For server authentication, Ansible requires a certificate with a key. This certificate will be stored in the LocalMachineMy certificate store on the Windows host. Using the code snippet below, create a self-signed certificate.

$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation ‘Cert:LocalMachineMy’ $hostname = hostname

Make the WinRm Ansible Listener

You must now build a WinRm listener on the Windows host once you’ve generated both certificates. This listener starts listening for incoming connections on port 5986. This listener takes incoming connections and tries to encrypt data using the server certificate established before.

Once authentication is complete, PowerShell Remoting utilizes this WinRM listener as a transport.

You can see an excellent example of checking for an existing HTTPS listener in the code snippet below. If the server certificate produced above fails to find a listener, it will generate a new one.

## Search for all HTTPS listners Get-ChildItem -Path $httpsListeners where-object

Ansible is quickly becoming one of, if not the most popular, configuration management tools available. Ansible is a useful (and, in most instances, free) tool that enables DevOps engineers, system engineers, and administrators to develop and manage infrastructure across many environments in an idempotent, infrastructure-as-code way. However, setting it to communicate with Windows (Ansible using WinRM) might be difficult.

Ansible can deploy and manage configuration state across Windows hosts, much as many other infrastructure components. Although they’re experimenting with SSH, Ansible connects to these Windows systems using WinRM.

When using WinRm to connect to Windows hosts, you have a few choices ranging from simplicity of setup to security consequences. Many individuals opt for the simple solution of basic HTTP authentication. Even if you skip the certificate procedure, it’s never a good idea to transfer unencrypted data across a network unless absolutely necessary.

In this article, you’ll learn how to configure WinRm to use self-signed certificates for certificate-based authentication so that Ansible can communicate with it.

This tutorial’s configuration isn’t limited to Ansible as the client. Other WinRm clients, as well as other Windows hosts, may use certificate-based authentication.

Assumptions

This post will be a walkthrough with tutorials. The tutorial will assume the following if you wish to follow the instructions outlined here:

  • Ansible is already installed on a Linux host.
  • Based on your Windows hosts, you’ve created an Ansible inventory.
  • You’re in charge of a Windows Server 2016 or later. Some of the cmdlets in this lesson will not operate in previous Windows versions.
  • There is no domain for the Windows host. Despite the fact that the examples were conducted on a non-domain-joined host, the setup should work on domain-joined servers as well.
  • You are signed in as a local administrator and have RDP or console access to the Windows host.
  • You’ve used PowerShell before. To make changes on the Windows host, almost all examples will utilize PowerShell code.

Each part will employ a piece of code that is dependent on the previous one. Some snippets will refer to variables that were previously declared. If you’re going to copy/paste this code verbatim, be sure to keep your terminal open while doing so.

You may download this GitHub gist if you only want the code without the explanation.

For Ansible WinRM, enable PowerShell Remoting.

Although PowerShell Remoting is enabled on all servers running Windows Server 2016 or later, it’s always a good idea to double-check.

Open a PowerShell console as an administrator on the Windows host to manage and execute the following code snippet. The WinRm service is launched and configured to start automatically when the machine boots up using this code snippet.

Start-Service -Name “WinRM” -StartupType Automatic Set-Service -Name “WinRM” -StartupType Automatic Start-Service -Name “WinRM”

Next, verify whether PowerShell Remoting is enabled by looking for any current session setups. If it doesn’t, make sure it doesn’t have any listeners. At least one listener is required by WinRm. Run Enable-PSRemoting if none of these criteria returns nothing.

(-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:localhostListener)) if ## Use SkipNetworkProfileCheck to make public profiles visible even on Windows Firewall. ## Use Force to avoid being asked whether we’re sure. -SkipNetworkProfileCheck -Force Enable-PSRemoting

Authentication using certificates is enabled.

WinRM is not set for certificate-based authentication by default. This must be enabled using the WSMan configuration provided below.

#region Enable certificate-based authentication Set-Item -Value $true -Path WSMan:localhostServiceAuthCertificate #endregion

Create a User Account for Local Use

You must “map” a local user account to a certificate to utilize certificate-based authentication with Ansible. You could accomplish this using the local administrator account, but it’s usually better to establish a separate account to make maintenance simpler.

If no such account exists, the following code snippet creates one named ansibletestuser with the password [email protected]$w0rd12. That account’s password will never expire to guarantee that it is constantly current.

$ansibletestuser = $testUserAccountName (ConvertTo-SecureString -String ‘[email protected]’) $testUserAccountPassword if (-not (Get-LocalUser -Name)) $w0rd12′ -AsPlainText -Force) $testUserAccountName -IgnoreErrorAction)) @ $newUserParams = $newUserParams AccountNeverExpires = $true PasswordNeverExpires = $true Password = $testUserAccountPassword Name = $testUserAccountName @newUserParams $null = New-LocalUser

Make a Client Certificate.

You’ll need two certificates to enable certificate-based authentication with Ansible: a client cert and a server cert.

You may use the same certificate for both client and server, although this technique caused me troubles. You may find instructions for producing the client certificate using PowerShell’s New-SelfSignedCert cmdlet in the Ansible manuals and many other places. Although this strategy could work, I couldn’t get it to work for me.

To Make a Client Certificate., you must create a private and a public key. Start by SSHing to the Ansible host and run the following openssl command. This command creates a private key in a file called cert_key.pem and a public key called cert.pem. The key usage will be client authentication (1.3.6.1.4.1.311.20.2.3) “mapped” to the local user account you created earlier called ansibletestuser.

## This is the public key generated from the Ansible server using: cat > openssl.conf << EOL distinguished_name = req_distinguished_name [req_distinguished_name] [v3_req_client] extendedKeyUsage = clientAuth subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:[email protected] EOL export OPENSSL_CONF=openssl.conf openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj “/CN=ansibletestuser” -extensions v3_req_client rm openssl.conf

Ansible WinRM authentication is one step closer!

Import the Certificate of the Client

You’ll need to import the client certificate into two certificate stores on the Windows server once you’ve generated it on the Ansible host. To do so, first copy the public key cert.pem to the Windows host. The following example assumes the key is located at C:cert.pem.

Import the public certificate into the Trusted Root Certification Authorities and Trusted People certificate stores on the Windows host using Import-Certificate, as illustrated below.

‘C:cert.pem’ as $pubKeyFilePath ## Use Trusted Root Certification Authorities and Trusted People to import the public key. Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineRoot’ $pubKeyFilePath Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineTrustedPeople’ $pubKeyFilePath

Make a certificate for the server.

For server authentication, Ansible requires a certificate with a key. This certificate will be stored in the LocalMachineMy certificate store on the Windows host. Using the code snippet below, create a self-signed certificate.

$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation ‘Cert:LocalMachineMy’ $hostname = hostname

Make the WinRm Ansible Listener

You must now build a WinRm listener on the Windows host once you’ve generated both certificates. This listener starts listening for incoming connections on port 5986. This listener takes incoming connections and tries to encrypt data using the server certificate established before.

Once authentication is complete, PowerShell Remoting utilizes this WinRM listener as a transport.

You can see an excellent example of checking for an existing HTTPS listener in the code snippet below. If the server certificate produced above fails to find a listener, it will generate a new one.

## Find all HTTPS listners $httpsListeners = Get-ChildItem -Path WSMan:localhostListener | where-object { $_.Keys -match ‘Transport=HTTPS’ } ## If not listeners are defined at all or no listener is configured to work with ## the server cert created, create a new one with a Subject of the computer’s host name ## and bound to the server certificate. if ((-not $httpsListeners) -or -not (@($httpsListeners).where( { $_.CertificateThumbprint -ne $serverCert.Thumbprint }))) { $newWsmanParams = @{ ResourceUri = ‘winrm/config/Listener’ SelectorSet = @{ Transport = “HTTPS”; Address = “*” } ValueSet = @{ Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint } # UseSSL = $true } $null = New-WSManInstance @newWsmanParams }

The Client Certificate is “mapped” to the Local User Account.

The next step is to make sure that when Ansible connects to the Windows host with the server certificate, it executes all commands as a local user. Ansible will utilize the local user account, ansibletestuser, for all activities in this situation.

$credential = New-Object System.Management.Automation -TypeName $credential -ArgumentList PSCredential $testUserAccountPassword, $testUserAccountName ## Find the certificate thumbprint for the Ansible host’s client certificate. Get-ChildItem -Path ‘Cert:LocalMachineRoot’ | Where-Object $ansibleCert ‘CN=ansibletestuser’ -eq

Ansible is quickly becoming one of, if not the most popular, configuration management tools available. Ansible is a useful (and, in most instances, free) tool that enables DevOps engineers, system engineers, and administrators to develop and manage infrastructure across many environments in an idempotent, infrastructure-as-code way. However, setting it to communicate with Windows (Ansible using WinRM) might be difficult.

Ansible can deploy and manage configuration state across Windows hosts, much as many other infrastructure components. Although they’re experimenting with SSH, Ansible connects to these Windows systems using WinRM.

When using WinRm to connect to Windows hosts, you have a few choices ranging from simplicity of setup to security consequences. Many individuals opt for the simple solution of basic HTTP authentication. Even if you skip the certificate procedure, it’s never a good idea to transfer unencrypted data across a network unless absolutely necessary.

In this article, you’ll learn how to configure WinRm to use self-signed certificates for certificate-based authentication so that Ansible can communicate with it.

This tutorial’s configuration isn’t limited to Ansible as the client. Other WinRm clients, as well as other Windows hosts, may use certificate-based authentication.

Assumptions

This post will be a walkthrough with tutorials. The tutorial will assume the following if you wish to follow the instructions outlined here:

  • Ansible is already installed on a Linux host.
  • Based on your Windows hosts, you’ve created an Ansible inventory.
  • You’re in charge of a Windows Server 2016 or later. Some of the cmdlets in this lesson will not operate in previous Windows versions.
  • There is no domain for the Windows host. Despite the fact that the examples were conducted on a non-domain-joined host, the setup should work on domain-joined servers as well.
  • You are signed in as a local administrator and have RDP or console access to the Windows host.
  • You’ve used PowerShell before. To make changes on the Windows host, almost all examples will utilize PowerShell code.

Each part will employ a piece of code that is dependent on the previous one. Some snippets will refer to variables that were previously declared. If you’re going to copy/paste this code verbatim, be sure to keep your terminal open while doing so.

You may download this GitHub gist if you only want the code without the explanation.

For Ansible WinRM, enable PowerShell Remoting.

Although PowerShell Remoting is enabled on all servers running Windows Server 2016 or later, it’s always a good idea to double-check.

Open a PowerShell console as an administrator on the Windows host to manage and execute the following code snippet. The WinRm service is launched and configured to start automatically when the machine boots up using this code snippet.

Start-Service -Name “WinRM” -StartupType Automatic Set-Service -Name “WinRM” -StartupType Automatic Start-Service -Name “WinRM”

Next, verify whether PowerShell Remoting is enabled by looking for any current session setups. If it doesn’t, make sure it doesn’t have any listeners. At least one listener is required by WinRm. Run Enable-PSRemoting if none of these criteria returns nothing.

(-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:localhostListener)) if ## Use SkipNetworkProfileCheck to make public profiles visible even on Windows Firewall. ## Use Force to avoid being asked whether we’re sure. -SkipNetworkProfileCheck -Force Enable-PSRemoting

Authentication using certificates is enabled.

WinRM is not set for certificate-based authentication by default. This must be enabled using the WSMan configuration provided below.

#region Enable certificate-based authentication Set-Item -Value $true -Path WSMan:localhostServiceAuthCertificate #endregion

Create a User Account for Local Use

You must “map” a local user account to a certificate to utilize certificate-based authentication with Ansible. You could accomplish this using the local administrator account, but it’s usually better to establish a separate account to make maintenance simpler.

If no such account exists, the following code snippet creates one named ansibletestuser with the password [email protected]$w0rd12. That account’s password will never expire to guarantee that it is constantly current.

$ansibletestuser = $testUserAccountName (ConvertTo-SecureString -String ‘[email protected]’) $testUserAccountPassword if (-not (Get-LocalUser -Name)) $w0rd12′ -AsPlainText -Force) $testUserAccountName -IgnoreErrorAction)) @ $newUserParams = $newUserParams AccountNeverExpires = $true PasswordNeverExpires = $true Password = $testUserAccountPassword Name = $testUserAccountName @newUserParams $null = New-LocalUser

Make a Client Certificate.

You’ll need two certificates to enable certificate-based authentication with Ansible: a client cert and a server cert.

You may use the same certificate for both client and server, although this technique caused me troubles. You may find instructions for producing the client certificate using PowerShell’s New-SelfSignedCert cmdlet in the Ansible manuals and many other places. Although this strategy could work, I couldn’t get it to work for me.

To Make a Client Certificate., you must create a private and a public key. Start by SSHing to the Ansible host and run the following openssl command. This command creates a private key in a file called cert_key.pem and a public key called cert.pem. The key usage will be client authentication (1.3.6.1.4.1.311.20.2.3) “mapped” to the local user account you created earlier called ansibletestuser.

## This is the public key generated from the Ansible server using: cat > openssl.conf << EOL distinguished_name = req_distinguished_name [req_distinguished_name] [v3_req_client] extendedKeyUsage = clientAuth subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:[email protected] EOL export OPENSSL_CONF=openssl.conf openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj “/CN=ansibletestuser” -extensions v3_req_client rm openssl.conf

Ansible WinRM authentication is one step closer!

Import the Certificate of the Client

You’ll need to import the client certificate into two certificate stores on the Windows server once you’ve generated it on the Ansible host. To do so, first copy the public key cert.pem to the Windows host. The following example assumes the key is located at C:cert.pem.

Import the public certificate into the Trusted Root Certification Authorities and Trusted People certificate stores on the Windows host using Import-Certificate, as illustrated below.

‘C:cert.pem’ as $pubKeyFilePath ## Use Trusted Root Certification Authorities and Trusted People to import the public key. Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineRoot’ $pubKeyFilePath Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineTrustedPeople’ $pubKeyFilePath

Make a certificate for the server.

For server authentication, Ansible requires a certificate with a key. This certificate will be stored in the LocalMachineMy certificate store on the Windows host. Using the code snippet below, create a self-signed certificate.

$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation ‘Cert:LocalMachineMy’ $hostname = hostname

Make the WinRm Ansible Listener

You must now build a WinRm listener on the Windows host once you’ve generated both certificates. This listener starts listening for incoming connections on port 5986. This listener takes incoming connections and tries to encrypt data using the server certificate established before.

Once authentication is complete, PowerShell Remoting utilizes this WinRM listener as a transport.

You can see an excellent example of checking for an existing HTTPS listener in the code snippet below. If the server certificate produced above fails to find a listener, it will generate a new one.

## Search for all HTTPS listners Get-ChildItem -Path $httpsListeners where-object

Ansible is quickly becoming one of, if not the most popular, configuration management tools available. Ansible is a useful (and, in most instances, free) tool that enables DevOps engineers, system engineers, and administrators to develop and manage infrastructure across many environments in an idempotent, infrastructure-as-code way. However, setting it to communicate with Windows (Ansible using WinRM) might be difficult.

Ansible can deploy and manage configuration state across Windows hosts, much as many other infrastructure components. Although they’re experimenting with SSH, Ansible connects to these Windows systems using WinRM.

When using WinRm to connect to Windows hosts, you have a few choices ranging from simplicity of setup to security consequences. Many individuals opt for the simple solution of basic HTTP authentication. Even if you skip the certificate procedure, it’s never a good idea to transfer unencrypted data across a network unless absolutely necessary.

In this article, you’ll learn how to configure WinRm to use self-signed certificates for certificate-based authentication so that Ansible can communicate with it.

This tutorial’s configuration isn’t limited to Ansible as the client. Other WinRm clients, as well as other Windows hosts, may use certificate-based authentication.

Assumptions

This post will be a walkthrough with tutorials. The tutorial will assume the following if you wish to follow the instructions outlined here:

  • Ansible is already installed on a Linux host.
  • Based on your Windows hosts, you’ve created an Ansible inventory.
  • You’re in charge of a Windows Server 2016 or later. Some of the cmdlets in this lesson will not operate in previous Windows versions.
  • There is no domain for the Windows host. Despite the fact that the examples were conducted on a non-domain-joined host, the setup should work on domain-joined servers as well.
  • You are signed in as a local administrator and have RDP or console access to the Windows host.
  • You’ve used PowerShell before. To make changes on the Windows host, almost all examples will utilize PowerShell code.

Each part will employ a piece of code that is dependent on the previous one. Some snippets will refer to variables that were previously declared. If you’re going to copy/paste this code verbatim, be sure to keep your terminal open while doing so.

You may download this GitHub gist if you only want the code without the explanation.

For Ansible WinRM, enable PowerShell Remoting.

Although PowerShell Remoting is enabled on all servers running Windows Server 2016 or later, it’s always a good idea to double-check.

Open a PowerShell console as an administrator on the Windows host to manage and execute the following code snippet. The WinRm service is launched and configured to start automatically when the machine boots up using this code snippet.

Start-Service -Name “WinRM” -StartupType Automatic Set-Service -Name “WinRM” -StartupType Automatic Start-Service -Name “WinRM”

Next, verify whether PowerShell Remoting is enabled by looking for any current session setups. If it doesn’t, make sure it doesn’t have any listeners. At least one listener is required by WinRm. Run Enable-PSRemoting if none of these criteria returns nothing.

(-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:localhostListener)) if ## Use SkipNetworkProfileCheck to make public profiles visible even on Windows Firewall. ## Use Force to avoid being asked whether we’re sure. -SkipNetworkProfileCheck -Force Enable-PSRemoting

Authentication using certificates is enabled.

WinRM is not set for certificate-based authentication by default. This must be enabled using the WSMan configuration provided below.

#region Enable certificate-based authentication Set-Item -Value $true -Path WSMan:localhostServiceAuthCertificate #endregion

Create a User Account for Local Use

You must “map” a local user account to a certificate to utilize certificate-based authentication with Ansible. You could accomplish this using the local administrator account, but it’s usually better to establish a separate account to make maintenance simpler.

If no such account exists, the following code snippet creates one named ansibletestuser with the password [email protected]$w0rd12. That account’s password will never expire to guarantee that it is constantly current.

$ansibletestuser = $testUserAccountName (ConvertTo-SecureString -String ‘[email protected]’) $testUserAccountPassword if (-not (Get-LocalUser -Name)) $w0rd12′ -AsPlainText -Force) $testUserAccountName -IgnoreErrorAction)) @ $newUserParams = $newUserParams AccountNeverExpires = $true PasswordNeverExpires = $true Password = $testUserAccountPassword Name = $testUserAccountName @newUserParams $null = New-LocalUser

Make a Client Certificate.

You’ll need two certificates to enable certificate-based authentication with Ansible: a client cert and a server cert.

You may use the same certificate for both client and server, although this technique caused me troubles. You may find instructions for producing the client certificate using PowerShell’s New-SelfSignedCert cmdlet in the Ansible manuals and many other places. Although this strategy could work, I couldn’t get it to work for me.

To Make a Client Certificate., you must create a private and a public key. Start by SSHing to the Ansible host and run the following openssl command. This command creates a private key in a file called cert_key.pem and a public key called cert.pem. The key usage will be client authentication (1.3.6.1.4.1.311.20.2.3) “mapped” to the local user account you created earlier called ansibletestuser.

## This is the public key generated from the Ansible server using: cat > openssl.conf << EOL distinguished_name = req_distinguished_name [req_distinguished_name] [v3_req_client] extendedKeyUsage = clientAuth subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:[email protected] EOL export OPENSSL_CONF=openssl.conf openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj “/CN=ansibletestuser” -extensions v3_req_client rm openssl.conf

Ansible WinRM authentication is one step closer!

Import the Certificate of the Client

You’ll need to import the client certificate into two certificate stores on the Windows server once you’ve generated it on the Ansible host. To do so, first copy the public key cert.pem to the Windows host. The following example assumes the key is located at C:cert.pem.

Import the public certificate into the Trusted Root Certification Authorities and Trusted People certificate stores on the Windows host using Import-Certificate, as illustrated below.

‘C:cert.pem’ as $pubKeyFilePath ## Use Trusted Root Certification Authorities and Trusted People to import the public key. Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineRoot’ $pubKeyFilePath Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineTrustedPeople’ $pubKeyFilePath

Make a certificate for the server.

For server authentication, Ansible requires a certificate with a key. This certificate will be stored in the LocalMachineMy certificate store on the Windows host. Using the code snippet below, create a self-signed certificate.

$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation ‘Cert:LocalMachineMy’ $hostname = hostname

Make the WinRm Ansible Listener

You must now build a WinRm listener on the Windows host once you’ve generated both certificates. This listener starts listening for incoming connections on port 5986. This listener takes incoming connections and tries to encrypt data using the server certificate established before.

Once authentication is complete, PowerShell Remoting utilizes this WinRM listener as a transport.

You can see an excellent example of checking for an existing HTTPS listener in the code snippet below. If the server certificate produced above fails to find a listener, it will generate a new one.

## Find all HTTPS listners $httpsListeners = Get-ChildItem -Path WSMan:localhostListener | where-object { $_.Keys -match ‘Transport=HTTPS’ } ## If not listeners are defined at all or no listener is configured to work with ## the server cert created, create a new one with a Subject of the computer’s host name ## and bound to the server certificate. if ((-not $httpsListeners) -or -not (@($httpsListeners).where( { $_.CertificateThumbprint -ne $serverCert.Thumbprint }))) { $newWsmanParams = @{ ResourceUri = ‘winrm/config/Listener’ SelectorSet = @{ Transport = “HTTPS”; Address = “*” } ValueSet = @{ Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint } # UseSSL = $true } $null = New-WSManInstance @newWsmanParams }

The Client Certificate is “mapped” to the Local User Account.

The next step is to make sure that when Ansible connects to the Windows host with the server certificate, it executes all commands as a local user. Ansible will utilize the local user account, ansibletestuser, for all activities in this situation.

$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUserAccountName, $testUserAccountPassword ## Find the cert thumbprint for the client certificate created on the Ansible host $ansibleCert = Get-ChildItem -Path ‘Cert:LocalMachineRoot’ | Where-Object {$_.Subject -eq ‘CN=ansibletestuser’} $params = @{ Path = ‘WSMan:localhostClientCertificate’ Subject = “[email protected]” URI = ‘*’ Issuer = $ansibleCert.Thumbprint Credential = $credential Force = $true } New-Item @params

Allow User Account Control for WinRm (UAC)

If you’re mapping a certificate to a local account, you’ll need to set the LocalAccountTokenFilterPolicy to 1 to prevent UAC from interfering. The LocalAccountTokenFilterPolicy applies to all local accounts (not domain accounts) and limits your token to your Network login. This will prevent it from signing on since Windows does not recognize it as an administrator, and WinRM expects the user to be a local administrator by default.

Setting the LocalAccountTokenFilterPolicy tells Windows not to produce a limited token for a local account’s network logons and instead to utilize its full token.

Path = ‘HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem’ Name = ‘LocalAccountTokenFilterPolicy’ $newItemParams = @ Value = 1 Force = $true PropertyType = ‘DWORD’ @newItemParams $null = New-ItemProperty

On the Windows Firewall, open Port 5986.

The port 5986 is used by WinRm over HTTPS. This port must be opened if the Windows Firewall is active. You may accomplish that by using the PowerShell code snippet below. This code snippet is much too lenient, enabling it to be used by any machine. If you want to tighten things up even further, use the LocalAddress argument and specify Ansible’s IP.

#region Make sure WinRM 5986 is allowed over the firewall. $rule ‘Windows Remote Management (HTTPS-In)’ is the display name. if (-not (Get-NetFirewallRule $ruleDisplayName -ErrorAction Ignore)) @ $newRuleParams = $newRuleParams Direction = ‘Inbound’ DisplayName = $ruleDisplayName 5986 LocalPort Enabled = ‘True’ Group = ‘Windows Remote Management’ RemoteAddress = ‘Any’ Protocol = ‘TCP’ Action = ‘Allow’ Enabled = ‘True’ @newRuleParams $null = New-NetFirewallRule #endregion

Join the Administrators Group using the Local User.

You may be asking why this tutorial didn’t just Join the Administrators Group using the Local User. earlier. The reason is because for some unknown reason, when you attempt to map the client certificate to the user, the user account cannot be a local admin.

To add the ansibletestuser local user account to the administrators group, run the following code snippet.

## Join the Administrators Group using the Local User.. If this step isn’t doing, Ansible sees an “AccessDenied” error Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group ‘Administrators’

Conclusion

You should now be able to run Ansible commands on a Windows host if you followed these steps exactly. To do your tests, use the win shell module. You have successfully setup WinRM cert-based authentication if this module succeeds!

.Keys -match ‘Transport=HTTPS’ WSMan:localhostListener Create a new one with a Subject of the computer’s host name and tied to the server certificate if no listeners are specified or no listener is set to interact with the server certificate. if ((-not $httpsListeners) where($ .CertificateThumbprint -ne $serverCert.Thumbprint @ $newWsmanParams = $newWsmanParams ‘winrm/config/Listener’ as ResourceUri @ SelectorSet Address = “*”; Transport = “HTTPS” @ ValueSet = # UseSSL = $true; Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint @newWsmanParams $null = New-WSManInstance

The Client Certificate is “mapped” to the Local User Account.

The next step is to make sure that when Ansible connects to the Windows host with the server certificate, it executes all commands as a local user. Ansible will utilize the local user account, ansibletestuser, for all activities in this situation.

$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUserAccountName, $testUserAccountPassword ## Find the cert thumbprint for the client certificate created on the Ansible host $ansibleCert = Get-ChildItem -Path ‘Cert:LocalMachineRoot’ | Where-Object {$_.Subject -eq ‘CN=ansibletestuser’} $params = @{ Path = ‘WSMan:localhostClientCertificate’ Subject = “[email protected]” URI = ‘*’ Issuer = $ansibleCert.Thumbprint Credential = $credential Force = $true } New-Item @params

Allow User Account Control for WinRm (UAC)

If you’re mapping a certificate to a local account, you’ll need to set the LocalAccountTokenFilterPolicy to 1 to prevent UAC from interfering. The LocalAccountTokenFilterPolicy applies to all local accounts (not domain accounts) and limits your token to your Network login. This will prevent it from signing on since Windows does not recognize it as an administrator, and WinRM expects the user to be a local administrator by default.

Setting the LocalAccountTokenFilterPolicy tells Windows not to produce a limited token for a local account’s network logons and instead to utilize its full token.

Path = ‘HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem’ Name = ‘LocalAccountTokenFilterPolicy’ $newItemParams = @ Value = 1 Force = $true PropertyType = ‘DWORD’ @newItemParams $null = New-ItemProperty

On the Windows Firewall, open Port 5986.

The port 5986 is used by WinRm over HTTPS. This port must be opened if the Windows Firewall is active. You may accomplish that by using the PowerShell code snippet below. This code snippet is much too lenient, enabling it to be used by any machine. If you want to tighten things up even further, use the LocalAddress argument and specify Ansible’s IP.

#region Make sure WinRM 5986 is allowed over the firewall. $rule ‘Windows Remote Management (HTTPS-In)’ is the display name. if (-not (Get-NetFirewallRule $ruleDisplayName -ErrorAction Ignore)) @ $newRuleParams = $newRuleParams Direction = ‘Inbound’ DisplayName = $ruleDisplayName 5986 LocalPort Enabled = ‘True’ Group = ‘Windows Remote Management’ RemoteAddress = ‘Any’ Protocol = ‘TCP’ Action = ‘Allow’ Enabled = ‘True’ @newRuleParams $null = New-NetFirewallRule #endregion

Join the Administrators Group using the Local User.

You may be asking why this tutorial didn’t just Join the Administrators Group using the Local User. earlier. The reason is because for some unknown reason, when you attempt to map the client certificate to the user, the user account cannot be a local admin.

To add the ansibletestuser local user account to the administrators group, run the following code snippet.

## Join the Administrators Group using the Local User.. If this step isn’t doing, Ansible sees an “AccessDenied” error Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group ‘Administrators’

Conclusion

You should now be able to run Ansible commands on a Windows host if you followed these steps exactly. To do your tests, use the win shell module. You have successfully setup WinRM cert-based authentication if this module succeeds!

.Subject $params = @ ‘WSMan:localhostClientCertificate’ is the path. Subject = “e-mail: [email protected] “URI = ‘*’ Force = $true Issuer = $ansibleCert.Thumbprint Credential = $credential @params New-Item

Allow User Account Control for WinRm (UAC)

If you’re mapping a certificate to a local account, you’ll need to set the LocalAccountTokenFilterPolicy to 1 to prevent UAC from interfering. The LocalAccountTokenFilterPolicy applies to all local accounts (not domain accounts) and limits your token to your Network login. This will prevent it from signing on since Windows does not recognize it as an administrator, and WinRM expects the user to be a local administrator by default.

Setting the LocalAccountTokenFilterPolicy tells Windows not to produce a limited token for a local account’s network logons and instead to utilize its full token.

Path = ‘HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem’ Name = ‘LocalAccountTokenFilterPolicy’ $newItemParams = @ Value = 1 Force = $true PropertyType = ‘DWORD’ @newItemParams $null = New-ItemProperty

On the Windows Firewall, open Port 5986.

The port 5986 is used by WinRm over HTTPS. This port must be opened if the Windows Firewall is active. You may accomplish that by using the PowerShell code snippet below. This code snippet is much too lenient, enabling it to be used by any machine. If you want to tighten things up even further, use the LocalAddress argument and specify Ansible’s IP.

#region Make sure WinRM 5986 is allowed over the firewall. $rule ‘Windows Remote Management (HTTPS-In)’ is the display name. if (-not (Get-NetFirewallRule $ruleDisplayName -ErrorAction Ignore)) @ $newRuleParams = $newRuleParams Direction = ‘Inbound’ DisplayName = $ruleDisplayName 5986 LocalPort Enabled = ‘True’ Group = ‘Windows Remote Management’ RemoteAddress = ‘Any’ Protocol = ‘TCP’ Action = ‘Allow’ Enabled = ‘True’ @newRuleParams $null = New-NetFirewallRule #endregion

Join the Administrators Group using the Local User.

You may be asking why this tutorial didn’t just Join the Administrators Group using the Local User. earlier. The reason is because for some unknown reason, when you attempt to map the client certificate to the user, the user account cannot be a local admin.

To add the ansibletestuser local user account to the administrators group, run the following code snippet.

## Join the Administrators Group using the Local User.. If this step isn’t doing, Ansible sees an “AccessDenied” error Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group ‘Administrators’

Conclusion

You should now be able to run Ansible commands on a Windows host if you followed these steps exactly. To do your tests, use the win shell module. You have successfully setup WinRM cert-based authentication if this module succeeds!

.Keys -match ‘Transport=HTTPS’ WSMan:localhostListener Create a new one with a Subject of the computer’s host name and tied to the server certificate if no listeners are specified or no listener is set to interact with the server certificate. if ((-not $httpsListeners) where($ .CertificateThumbprint -ne $serverCert.Thumbprint @ $newWsmanParams = $newWsmanParams ‘winrm/config/Listener’ as ResourceUri @ SelectorSet Address = “*”; Transport = “HTTPS” @ ValueSet = # UseSSL = $true; Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint @newWsmanParams $null = New-WSManInstance

The Client Certificate is “mapped” to the Local User Account.

The next step is to make sure that when Ansible connects to the Windows host with the server certificate, it executes all commands as a local user. Ansible will utilize the local user account, ansibletestuser, for all activities in this situation.

$credential = New-Object System.Management.Automation -TypeName $credential -ArgumentList PSCredential $testUserAccountPassword, $testUserAccountName ## Find the certificate thumbprint for the Ansible host’s client certificate. Get-ChildItem -Path ‘Cert:LocalMachineRoot’ | Where-Object $ansibleCert ‘CN=ansibletestuser’ -eq

Ansible is quickly becoming one of, if not the most popular, configuration management tools available. Ansible is a useful (and, in most instances, free) tool that enables DevOps engineers, system engineers, and administrators to develop and manage infrastructure across many environments in an idempotent, infrastructure-as-code way. However, setting it to communicate with Windows (Ansible using WinRM) might be difficult.

Ansible can deploy and manage configuration state across Windows hosts, much as many other infrastructure components. Although they’re experimenting with SSH, Ansible connects to these Windows systems using WinRM.

When using WinRm to connect to Windows hosts, you have a few choices ranging from simplicity of setup to security consequences. Many individuals opt for the simple solution of basic HTTP authentication. Even if you skip the certificate procedure, it’s never a good idea to transfer unencrypted data across a network unless absolutely necessary.

In this article, you’ll learn how to configure WinRm to use self-signed certificates for certificate-based authentication so that Ansible can communicate with it.

This tutorial’s configuration isn’t limited to Ansible as the client. Other WinRm clients, as well as other Windows hosts, may use certificate-based authentication.

Assumptions

This post will be a walkthrough with tutorials. The tutorial will assume the following if you wish to follow the instructions outlined here:

  • Ansible is already installed on a Linux host.
  • Based on your Windows hosts, you’ve created an Ansible inventory.
  • You’re in charge of a Windows Server 2016 or later. Some of the cmdlets in this lesson will not operate in previous Windows versions.
  • There is no domain for the Windows host. Despite the fact that the examples were conducted on a non-domain-joined host, the setup should work on domain-joined servers as well.
  • You are signed in as a local administrator and have RDP or console access to the Windows host.
  • You’ve used PowerShell before. To make changes on the Windows host, almost all examples will utilize PowerShell code.

Each part will employ a piece of code that is dependent on the previous one. Some snippets will refer to variables that were previously declared. If you’re going to copy/paste this code verbatim, be sure to keep your terminal open while doing so.

You may download this GitHub gist if you only want the code without the explanation.

For Ansible WinRM, enable PowerShell Remoting.

Although PowerShell Remoting is enabled on all servers running Windows Server 2016 or later, it’s always a good idea to double-check.

Open a PowerShell console as an administrator on the Windows host to manage and execute the following code snippet. The WinRm service is launched and configured to start automatically when the machine boots up using this code snippet.

Start-Service -Name “WinRM” -StartupType Automatic Set-Service -Name “WinRM” -StartupType Automatic Start-Service -Name “WinRM”

Next, verify whether PowerShell Remoting is enabled by looking for any current session setups. If it doesn’t, make sure it doesn’t have any listeners. At least one listener is required by WinRm. Run Enable-PSRemoting if none of these criteria returns nothing.

(-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:localhostListener)) if ## Use SkipNetworkProfileCheck to make public profiles visible even on Windows Firewall. ## Use Force to avoid being asked whether we’re sure. -SkipNetworkProfileCheck -Force Enable-PSRemoting

Authentication using certificates is enabled.

WinRM is not set for certificate-based authentication by default. This must be enabled using the WSMan configuration provided below.

#region Enable certificate-based authentication Set-Item -Value $true -Path WSMan:localhostServiceAuthCertificate #endregion

Create a User Account for Local Use

You must “map” a local user account to a certificate to utilize certificate-based authentication with Ansible. You could accomplish this using the local administrator account, but it’s usually better to establish a separate account to make maintenance simpler.

If no such account exists, the following code snippet creates one named ansibletestuser with the password [email protected]$w0rd12. That account’s password will never expire to guarantee that it is constantly current.

$ansibletestuser = $testUserAccountName (ConvertTo-SecureString -String ‘[email protected]’) $testUserAccountPassword if (-not (Get-LocalUser -Name)) $w0rd12′ -AsPlainText -Force) $testUserAccountName -IgnoreErrorAction)) @ $newUserParams = $newUserParams AccountNeverExpires = $true PasswordNeverExpires = $true Password = $testUserAccountPassword Name = $testUserAccountName @newUserParams $null = New-LocalUser

Make a Client Certificate.

You’ll need two certificates to enable certificate-based authentication with Ansible: a client cert and a server cert.

You may use the same certificate for both client and server, although this technique caused me troubles. You may find instructions for producing the client certificate using PowerShell’s New-SelfSignedCert cmdlet in the Ansible manuals and many other places. Although this strategy could work, I couldn’t get it to work for me.

To Make a Client Certificate., you must create a private and a public key. Start by SSHing to the Ansible host and run the following openssl command. This command creates a private key in a file called cert_key.pem and a public key called cert.pem. The key usage will be client authentication (1.3.6.1.4.1.311.20.2.3) “mapped” to the local user account you created earlier called ansibletestuser.

## This is the public key generated from the Ansible server using: cat > openssl.conf << EOL distinguished_name = req_distinguished_name [req_distinguished_name] [v3_req_client] extendedKeyUsage = clientAuth subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:[email protected] EOL export OPENSSL_CONF=openssl.conf openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj “/CN=ansibletestuser” -extensions v3_req_client rm openssl.conf

Ansible WinRM authentication is one step closer!

Import the Certificate of the Client

You’ll need to import the client certificate into two certificate stores on the Windows server once you’ve generated it on the Ansible host. To do so, first copy the public key cert.pem to the Windows host. The following example assumes the key is located at C:cert.pem.

Import the public certificate into the Trusted Root Certification Authorities and Trusted People certificate stores on the Windows host using Import-Certificate, as illustrated below.

‘C:cert.pem’ as $pubKeyFilePath ## Use Trusted Root Certification Authorities and Trusted People to import the public key. Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineRoot’ $pubKeyFilePath Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineTrustedPeople’ $pubKeyFilePath

Make a certificate for the server.

For server authentication, Ansible requires a certificate with a key. This certificate will be stored in the LocalMachineMy certificate store on the Windows host. Using the code snippet below, create a self-signed certificate.

$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation ‘Cert:LocalMachineMy’ $hostname = hostname

Make the WinRm Ansible Listener

You must now build a WinRm listener on the Windows host once you’ve generated both certificates. This listener starts listening for incoming connections on port 5986. This listener takes incoming connections and tries to encrypt data using the server certificate established before.

Once authentication is complete, PowerShell Remoting utilizes this WinRM listener as a transport.

You can see an excellent example of checking for an existing HTTPS listener in the code snippet below. If the server certificate produced above fails to find a listener, it will generate a new one.

## Search for all HTTPS listners Get-ChildItem -Path $httpsListeners where-object

Ansible is quickly becoming one of, if not the most popular, configuration management tools available. Ansible is a useful (and, in most instances, free) tool that enables DevOps engineers, system engineers, and administrators to develop and manage infrastructure across many environments in an idempotent, infrastructure-as-code way. However, setting it to communicate with Windows (Ansible using WinRM) might be difficult.

Ansible can deploy and manage configuration state across Windows hosts, much as many other infrastructure components. Although they’re experimenting with SSH, Ansible connects to these Windows systems using WinRM.

When using WinRm to connect to Windows hosts, you have a few choices ranging from simplicity of setup to security consequences. Many individuals opt for the simple solution of basic HTTP authentication. Even if you skip the certificate procedure, it’s never a good idea to transfer unencrypted data across a network unless absolutely necessary.

In this article, you’ll learn how to configure WinRm to use self-signed certificates for certificate-based authentication so that Ansible can communicate with it.

This tutorial’s configuration isn’t limited to Ansible as the client. Other WinRm clients, as well as other Windows hosts, may use certificate-based authentication.

Assumptions

This post will be a walkthrough with tutorials. The tutorial will assume the following if you wish to follow the instructions outlined here:

  • Ansible is already installed on a Linux host.
  • Based on your Windows hosts, you’ve created an Ansible inventory.
  • You’re in charge of a Windows Server 2016 or later. Some of the cmdlets in this lesson will not operate in previous Windows versions.
  • There is no domain for the Windows host. Despite the fact that the examples were conducted on a non-domain-joined host, the setup should work on domain-joined servers as well.
  • You are signed in as a local administrator and have RDP or console access to the Windows host.
  • You’ve used PowerShell before. To make changes on the Windows host, almost all examples will utilize PowerShell code.

Each part will employ a piece of code that is dependent on the previous one. Some snippets will refer to variables that were previously declared. If you’re going to copy/paste this code verbatim, be sure to keep your terminal open while doing so.

You may download this GitHub gist if you only want the code without the explanation.

For Ansible WinRM, enable PowerShell Remoting.

Although PowerShell Remoting is enabled on all servers running Windows Server 2016 or later, it’s always a good idea to double-check.

Open a PowerShell console as an administrator on the Windows host to manage and execute the following code snippet. The WinRm service is launched and configured to start automatically when the machine boots up using this code snippet.

Start-Service -Name “WinRM” -StartupType Automatic Set-Service -Name “WinRM” -StartupType Automatic Start-Service -Name “WinRM”

Next, verify whether PowerShell Remoting is enabled by looking for any current session setups. If it doesn’t, make sure it doesn’t have any listeners. At least one listener is required by WinRm. Run Enable-PSRemoting if none of these criteria returns nothing.

(-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:localhostListener)) if ## Use SkipNetworkProfileCheck to make public profiles visible even on Windows Firewall. ## Use Force to avoid being asked whether we’re sure. -SkipNetworkProfileCheck -Force Enable-PSRemoting

Authentication using certificates is enabled.

WinRM is not set for certificate-based authentication by default. This must be enabled using the WSMan configuration provided below.

#region Enable certificate-based authentication Set-Item -Value $true -Path WSMan:localhostServiceAuthCertificate #endregion

Create a User Account for Local Use

You must “map” a local user account to a certificate to utilize certificate-based authentication with Ansible. You could accomplish this using the local administrator account, but it’s usually better to establish a separate account to make maintenance simpler.

If no such account exists, the following code snippet creates one named ansibletestuser with the password [email protected]$w0rd12. That account’s password will never expire to guarantee that it is constantly current.

$ansibletestuser = $testUserAccountName (ConvertTo-SecureString -String ‘[email protected]’) $testUserAccountPassword if (-not (Get-LocalUser -Name)) $w0rd12′ -AsPlainText -Force) $testUserAccountName -IgnoreErrorAction)) @ $newUserParams = $newUserParams AccountNeverExpires = $true PasswordNeverExpires = $true Password = $testUserAccountPassword Name = $testUserAccountName @newUserParams $null = New-LocalUser

Make a Client Certificate.

You’ll need two certificates to enable certificate-based authentication with Ansible: a client cert and a server cert.

You may use the same certificate for both client and server, although this technique caused me troubles. You may find instructions for producing the client certificate using PowerShell’s New-SelfSignedCert cmdlet in the Ansible manuals and many other places. Although this strategy could work, I couldn’t get it to work for me.

To Make a Client Certificate., you must create a private and a public key. Start by SSHing to the Ansible host and run the following openssl command. This command creates a private key in a file called cert_key.pem and a public key called cert.pem. The key usage will be client authentication (1.3.6.1.4.1.311.20.2.3) “mapped” to the local user account you created earlier called ansibletestuser.

## This is the public key generated from the Ansible server using: cat > openssl.conf << EOL distinguished_name = req_distinguished_name [req_distinguished_name] [v3_req_client] extendedKeyUsage = clientAuth subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:[email protected] EOL export OPENSSL_CONF=openssl.conf openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj “/CN=ansibletestuser” -extensions v3_req_client rm openssl.conf

Ansible WinRM authentication is one step closer!

Import the Certificate of the Client

You’ll need to import the client certificate into two certificate stores on the Windows server once you’ve generated it on the Ansible host. To do so, first copy the public key cert.pem to the Windows host. The following example assumes the key is located at C:cert.pem.

Import the public certificate into the Trusted Root Certification Authorities and Trusted People certificate stores on the Windows host using Import-Certificate, as illustrated below.

‘C:cert.pem’ as $pubKeyFilePath ## Use Trusted Root Certification Authorities and Trusted People to import the public key. Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineRoot’ $pubKeyFilePath Import-Certificate -FilePath $null -CertStoreLocation ‘Cert:LocalMachineTrustedPeople’ $pubKeyFilePath

Make a certificate for the server.

For server authentication, Ansible requires a certificate with a key. This certificate will be stored in the LocalMachineMy certificate store on the Windows host. Using the code snippet below, create a self-signed certificate.

$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation ‘Cert:LocalMachineMy’ $hostname = hostname

Make the WinRm Ansible Listener

You must now build a WinRm listener on the Windows host once you’ve generated both certificates. This listener starts listening for incoming connections on port 5986. This listener takes incoming connections and tries to encrypt data using the server certificate established before.

Once authentication is complete, PowerShell Remoting utilizes this WinRM listener as a transport.

You can see an excellent example of checking for an existing HTTPS listener in the code snippet below. If the server certificate produced above fails to find a listener, it will generate a new one.

## Find all HTTPS listners $httpsListeners = Get-ChildItem -Path WSMan:localhostListener | where-object { $_.Keys -match ‘Transport=HTTPS’ } ## If not listeners are defined at all or no listener is configured to work with ## the server cert created, create a new one with a Subject of the computer’s host name ## and bound to the server certificate. if ((-not $httpsListeners) -or -not (@($httpsListeners).where( { $_.CertificateThumbprint -ne $serverCert.Thumbprint }))) { $newWsmanParams = @{ ResourceUri = ‘winrm/config/Listener’ SelectorSet = @{ Transport = “HTTPS”; Address = “*” } ValueSet = @{ Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint } # UseSSL = $true } $null = New-WSManInstance @newWsmanParams }

The Client Certificate is “mapped” to the Local User Account.

The next step is to make sure that when Ansible connects to the Windows host with the server certificate, it executes all commands as a local user. Ansible will utilize the local user account, ansibletestuser, for all activities in this situation.

$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUserAccountName, $testUserAccountPassword ## Find the cert thumbprint for the client certificate created on the Ansible host $ansibleCert = Get-ChildItem -Path ‘Cert:LocalMachineRoot’ | Where-Object {$_.Subject -eq ‘CN=ansibletestuser’} $params = @{ Path = ‘WSMan:localhostClientCertificate’ Subject = “[email protected]” URI = ‘*’ Issuer = $ansibleCert.Thumbprint Credential = $credential Force = $true } New-Item @params

Allow User Account Control for WinRm (UAC)

If you’re mapping a certificate to a local account, you’ll need to set the LocalAccountTokenFilterPolicy to 1 to prevent UAC from interfering. The LocalAccountTokenFilterPolicy applies to all local accounts (not domain accounts) and limits your token to your Network login. This will prevent it from signing on since Windows does not recognize it as an administrator, and WinRM expects the user to be a local administrator by default.

Setting the LocalAccountTokenFilterPolicy tells Windows not to produce a limited token for a local account’s network logons and instead to utilize its full token.

Path = ‘HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem’ Name = ‘LocalAccountTokenFilterPolicy’ $newItemParams = @ Value = 1 Force = $true PropertyType = ‘DWORD’ @newItemParams $null = New-ItemProperty

On the Windows Firewall, open Port 5986.

The port 5986 is used by WinRm over HTTPS. This port must be opened if the Windows Firewall is active. You may accomplish that by using the PowerShell code snippet below. This code snippet is much too lenient, enabling it to be used by any machine. If you want to tighten things up even further, use the LocalAddress argument and specify Ansible’s IP.

#region Make sure WinRM 5986 is allowed over the firewall. $rule ‘Windows Remote Management (HTTPS-In)’ is the display name. if (-not (Get-NetFirewallRule $ruleDisplayName -ErrorAction Ignore)) @ $newRuleParams = $newRuleParams Direction = ‘Inbound’ DisplayName = $ruleDisplayName 5986 LocalPort Enabled = ‘True’ Group = ‘Windows Remote Management’ RemoteAddress = ‘Any’ Protocol = ‘TCP’ Action = ‘Allow’ Enabled = ‘True’ @newRuleParams $null = New-NetFirewallRule #endregion

Join the Administrators Group using the Local User.

You may be asking why this tutorial didn’t just Join the Administrators Group using the Local User. earlier. The reason is because for some unknown reason, when you attempt to map the client certificate to the user, the user account cannot be a local admin.

To add the ansibletestuser local user account to the administrators group, run the following code snippet.

## Join the Administrators Group using the Local User.. If this step isn’t doing, Ansible sees an “AccessDenied” error Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group ‘Administrators’

Conclusion

You should now be able to run Ansible commands on a Windows host if you followed these steps exactly. To do your tests, use the win shell module. You have successfully setup WinRM cert-based authentication if this module succeeds!

.Keys -match ‘Transport=HTTPS’ WSMan:localhostListener Create a new one with a Subject of the computer’s host name and tied to the server certificate if no listeners are specified or no listener is set to interact with the server certificate. if ((-not $httpsListeners) where($ .CertificateThumbprint -ne $serverCert.Thumbprint @ $newWsmanParams = $newWsmanParams ‘winrm/config/Listener’ as ResourceUri @ SelectorSet Address = “*”; Transport = “HTTPS” @ ValueSet = # UseSSL = $true; Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint @newWsmanParams $null = New-WSManInstance

The Client Certificate is “mapped” to the Local User Account.

The next step is to make sure that when Ansible connects to the Windows host with the server certificate, it executes all commands as a local user. Ansible will utilize the local user account, ansibletestuser, for all activities in this situation.

$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUserAccountName, $testUserAccountPassword ## Find the cert thumbprint for the client certificate created on the Ansible host $ansibleCert = Get-ChildItem -Path ‘Cert:LocalMachineRoot’ | Where-Object {$_.Subject -eq ‘CN=ansibletestuser’} $params = @{ Path = ‘WSMan:localhostClientCertificate’ Subject = “[email protected]” URI = ‘*’ Issuer = $ansibleCert.Thumbprint Credential = $credential Force = $true } New-Item @params

Allow User Account Control for WinRm (UAC)

If you’re mapping a certificate to a local account, you’ll need to set the LocalAccountTokenFilterPolicy to 1 to prevent UAC from interfering. The LocalAccountTokenFilterPolicy applies to all local accounts (not domain accounts) and limits your token to your Network login. This will prevent it from signing on since Windows does not recognize it as an administrator, and WinRM expects the user to be a local administrator by default.

Setting the LocalAccountTokenFilterPolicy tells Windows not to produce a limited token for a local account’s network logons and instead to utilize its full token.

Path = ‘HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem’ Name = ‘LocalAccountTokenFilterPolicy’ $newItemParams = @ Value = 1 Force = $true PropertyType = ‘DWORD’ @newItemParams $null = New-ItemProperty

On the Windows Firewall, open Port 5986.

The port 5986 is used by WinRm over HTTPS. This port must be opened if the Windows Firewall is active. You may accomplish that by using the PowerShell code snippet below. This code snippet is much too lenient, enabling it to be used by any machine. If you want to tighten things up even further, use the LocalAddress argument and specify Ansible’s IP.

#region Make sure WinRM 5986 is allowed over the firewall. $rule ‘Windows Remote Management (HTTPS-In)’ is the display name. if (-not (Get-NetFirewallRule $ruleDisplayName -ErrorAction Ignore)) @ $newRuleParams = $newRuleParams Direction = ‘Inbound’ DisplayName = $ruleDisplayName 5986 LocalPort Enabled = ‘True’ Group = ‘Windows Remote Management’ RemoteAddress = ‘Any’ Protocol = ‘TCP’ Action = ‘Allow’ Enabled = ‘True’ @newRuleParams $null = New-NetFirewallRule #endregion

Join the Administrators Group using the Local User.

You may be asking why this tutorial didn’t just Join the Administrators Group using the Local User. earlier. The reason is because for some unknown reason, when you attempt to map the client certificate to the user, the user account cannot be a local admin.

To add the ansibletestuser local user account to the administrators group, run the following code snippet.

## Join the Administrators Group using the Local User.. If this step isn’t doing, Ansible sees an “AccessDenied” error Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group ‘Administrators’

Conclusion

You should now be able to run Ansible commands on a Windows host if you followed these steps exactly. To do your tests, use the win shell module. You have successfully setup WinRM cert-based authentication if this module succeeds!

.Subject $params = @ ‘WSMan:localhostClientCertificate’ is the path. Subject = “e-mail: [email protected] “URI = ‘*’ Force = $true Issuer = $ansibleCert.Thumbprint Credential = $credential @params New-Item

Allow User Account Control for WinRm (UAC)

If you’re mapping a certificate to a local account, you’ll need to set the LocalAccountTokenFilterPolicy to 1 to prevent UAC from interfering. The LocalAccountTokenFilterPolicy applies to all local accounts (not domain accounts) and limits your token to your Network login. This will prevent it from signing on since Windows does not recognize it as an administrator, and WinRM expects the user to be a local administrator by default.

Setting the LocalAccountTokenFilterPolicy tells Windows not to produce a limited token for a local account’s network logons and instead to utilize its full token.

Path = ‘HKLM:SOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem’ Name = ‘LocalAccountTokenFilterPolicy’ $newItemParams = @ Value = 1 Force = $true PropertyType = ‘DWORD’ @newItemParams $null = New-ItemProperty

On the Windows Firewall, open Port 5986.

The port 5986 is used by WinRm over HTTPS. This port must be opened if the Windows Firewall is active. You may accomplish that by using the PowerShell code snippet below. This code snippet is much too lenient, enabling it to be used by any machine. If you want to tighten things up even further, use the LocalAddress argument and specify Ansible’s IP.

#region Make sure WinRM 5986 is allowed over the firewall. $rule ‘Windows Remote Management (HTTPS-In)’ is the display name. if (-not (Get-NetFirewallRule $ruleDisplayName -ErrorAction Ignore)) @ $newRuleParams = $newRuleParams Direction = ‘Inbound’ DisplayName = $ruleDisplayName 5986 LocalPort Enabled = ‘True’ Group = ‘Windows Remote Management’ RemoteAddress = ‘Any’ Protocol = ‘TCP’ Action = ‘Allow’ Enabled = ‘True’ @newRuleParams $null = New-NetFirewallRule #endregion

Join the Administrators Group using the Local User.

You may be asking why this tutorial didn’t just Join the Administrators Group using the Local User. earlier. The reason is because for some unknown reason, when you attempt to map the client certificate to the user, the user account cannot be a local admin.

To add the ansibletestuser local user account to the administrators group, run the following code snippet.

## Join the Administrators Group using the Local User.. If this step isn’t doing, Ansible sees an “AccessDenied” error Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group ‘Administrators’

Conclusion

You should now be able to run Ansible commands on a Windows host if you followed these steps exactly. To do your tests, use the win shell module. You have successfully setup WinRM cert-based authentication if this module succeeds!

Ansible is an open-source automation tool that can manage systems and applications. It uses SSH to connect to remote servers, but not all servers support SSH. To work around this issue, Ansible supports WinRM over HTTPS. This article will teach you how to configure WinRM over HTTPS for Ansible. Reference: ansible_connection=winrm.

Related Tags

  • ansible winrm example
  • ansible windows modules
  • ansible_winrm_transport
  • ansible winrm kerberos
  • ansible winrm or requests is not installed: no module named winrm

Table of Content