Ansible in Windows 10 box

Share this:

Do you want to test or start learning Ansible and you have only Windows 10?
Following steps will help you to install and configure Ansible in Windows Subsystem for Linux.

Here, I have to make a disclaimer: all bellow information is already available in one form or another if you google it; what I’ve done is to make my own recipe and I hope, dear reader, you’ll like it.

So let’s get started!

What is Windows Subsystem for Linux (WSL) and how to install it

Windows Subsystem for Linux (WSL) is a compatibility layer for running Linux binary executables (in ELF format) natively on Windows 10 and Windows Server 2019. In May 2019, Microsoft has announced WSL2, introducing a real Linux kernel through a subset of Hyper-V features. WSL 2 will be available in Windows 10 builds 18917 (20H1) or higher. My Windows 10 build is 18363 (19H2) so we’ll use WSL.

So, WSL installation consists in 2 steps:

1. Enable WSL feature

Microsoft documentation is clear about this: open PowerShell as Administrator, run the command and reboot:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

2. Install Linux Distribution from Microsoft Store

Open Microsoft Store and search for linux. Don’t ask about language. I have set it English but I am located in a region with default French.

I choose Ubuntu 18.04 LTS. After download you can launch it:

Installation is straightforward:

When finished, you’ll be asked for initial user and password. You can also reset the root password with a secure one:

Install Ansible

Now it is time to install Ansible packages. For more info you can check Ansible documentation; I have added the commands needed for Windows connectivity via WinRM:

$ sudo apt update
$ sudo apt install software-properties-common
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible
$ sudo apt install python-pip
$ pip install pywinrm

A summary of commands used:

Configure WinRM on Windows to use it with Ansible

WinRM is a management protocol used by Windows to remotely communicate with another server and is included in all recent Windows operating systems. Since Windows Server 2012, WinRM has been enabled by default, but we need extra configuration to use WinRM with Ansible.

There’s a Configure Remoting for Ansible script you can run on the remote Windows machine (in a PowerShell console as an Admin) to turn on WinRM and set up a https listener.

After running the script, check WinRM listeners with following command:

winrm enumerate winrm/config/Listener  

The result should look like:

When connecting to a Windows host, there are several different options that can be used for authenticating with an account. These are detailed well in Ansible documentation.

I choose certificate authentication which uses certificates as keys similar to SSH key pairs; for this I create on windows a local account, dedicated to Ansible:

Then, we need a certificate associated to this user. We can use different methods to create a certificate. I will use PowerShell:

# Set the name of the local user that will have the key mapped
$username = "ansibleusr"
$output_path = "C:\temp\scripts"

# Instead of generating a file, the cert will be added to the personal
# LocalComputer folder in the certificate store
$cert = New-SelfSignedCertificate -Type Custom `
    -Subject "CN=$username" `
    -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2","2.5.29.17={text}upn=$username@localhost") `
    -KeyUsage DigitalSignature,KeyEncipherment `
    -KeyAlgorithm RSA `
    -KeyLength 2048

# Export the public key
$pem_output = @()
$pem_output += "-----BEGIN CERTIFICATE-----"
$pem_output += [System.Convert]::ToBase64String($cert.RawData) -replace ".{64}", "$&`n"
$pem_output += "-----END CERTIFICATE-----"
[System.IO.File]::WriteAllLines("$output_path\cert.pem", $pem_output)

# Export the private key in a PFX file
[System.IO.File]::WriteAllBytes("$output_path\cert.pfx", $cert.Export("Pfx"))

We will convert now the PFX file to a pem and private key that pywinrm can use, with the following command with OpenSSL:

# openssl pkcs12 -in cert.pfx -clcerts -nokeys -out cert.pem
# openssl pkcs12 -in cert.pfx -nocerts -nodes -out cert_key.pem

Once a certificate has been generated, we need to import the issuing certificate into the Trusted Root Certificate Authorities of the LocalMachine store, and the client certificate public key must be present in the Trusted People folder of the LocalMachine store. For this example, both the issuing certificate and public key are the same.

$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import("cert.pem")

$store_name = [System.Security.Cryptography.X509Certificates.StoreName]::Root
$store_location = [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $store_name, $store_location
$store.Open("MaxAllowed")
$store.Add($cert)
$store.Close()

For public key, the code:

$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import("cert.pem")

$store_name = [System.Security.Cryptography.X509Certificates.StoreName]::TrustedPeople
$store_location = [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store -ArgumentList $store_name, $store_location
$store.Open("MaxAllowed")
$store.Add($cert)
$store.Close()

Then, we map the certificate to the local user account:

$username = "ansibleusr"
$password = ConvertTo-SecureString -String "password" -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $password

# This is the issuer thumbprint which in the case of a self generated cert
# is the public key thumbprint, additional logic may be required for other
# scenarios
$thumbprint = (Get-ChildItem -Path cert:\LocalMachine\root | Where-Object { $_.Subject -eq "CN=$username" }).Thumbprint

New-Item -Path WSMan:\localhost\ClientCertificate `
    -Subject "$username@localhost" `
    -URI * `
    -Issuer $thumbprint `
    -Credential $credential `
    -Force

Certificate authentication is not enabled by default, we will enable by running the following in PowerShell:

Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true

Finally, we need now to copy the certificate to Ansible configuration folder. From Windows side we can access linux file system from WSL with:

\\wsl$\{distro name}

where {distro name} is the name of a running distro.

Finishing configuration on Ansible side and test connection

As already mentioned above, there are several different options that can be used when authenticating with an account. The authentication type may be set on inventory hosts or groups with the ansible_winrm_transport variable.

On WSL side, we edit /etc/ansible/hosts file with command

# sudo nano /etc/ansible/hosts

and we add following lines:

[myhost]
127.0.0.1

[myhost:vars]
ansible_connection = winrm
ansible_winrm_cert_pem = /etc/ansible/cert.pem
ansible_winrm_cert_key_pem = /etc/ansible/cert_key.pem
ansible_wirm_transport = certificate
ansible_winrm_server_cert_validation = ignore

The line ansible_winrm_server_cert_validation = ignore is needed because we are using self-signed certificates and there is no CA to validate our certs.

Also, notice 127.0.0.1 as myhost. Windows and WSL are sharing the same network configuration.

Now we can test the connection:

Conclusion

Next step is to create playbooks and test Ansible. Happy automation!

About Gica Livada

Gica is working in Luxembourg as Technical Specialist and is former member of the VMware Centre of Excellence team from IBM Delivery Center in Brno, Czech Republic. He is passionate about virtualization, security and cloud technologies, holds multiple industry certifications.
Bookmark the permalink.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.