DEV Community

Hamzza K
Hamzza K

Posted on

Automate your Hyper-V Windows through Docker Ansible

But why, you may wonder?
Let me explain the problem I'm currently facing and the rationale behind my chosen approach. One of my job responsibilities involves deploying software that exclusively operates on Windows.
Performing this task manually is exceptionally tedious, to say the least.
So, why not automate it, you might ask?
The challenge lies in the fact that my work laptop runs on Windows, and I'm unable to create Linux-based VMs due to company policies. Unfortunately, Ansible doesn't function within Windows when running inside Hyper-V.
Although I've contemplated using WSL, I wasn't in the mood for it, plus I have a preference for Docker.
Consequently, I arrived at this solution after spending several days troubleshooting these issues. I hope this explanation proves beneficial to anyone encountering a similar predicament.

Pre-requisites

before beginning, make sure you configure the following:

  • Hyper-V Virtual Switch
  • WinRM on your Target
  • Firewall Ports on your Target

Hyper-V Virtual Switch

Since we are working with Windows Hyper-V we need to set up the connection type for our VM to use.

Image description

Go to Actions → Virtual Switch Manager → New virtual network switch
to create a new connection. Make sure to connect you LAN and select External Network also allow your OS to share the network adapter otherwise you won’t be able use internet on your host machine.
💡

Sharing your adapter whilst on WiFi might behave unexpectedly.

💡

Internal Network isolates your VM from the network. You won’t be able to communicate with it using your host machine. However, it is possible to ping/communicate through another VM running in the same hyper-V manager. Private Network is almost the same except it restricts communication from other devices that are not on the same network.

Image description
apply and save the changes. Select your target VM, make sure it is turned-off, right click and go to → settings, assign the virtual switch you just created.

Image description
log into your VM and open up powershell/cmd.
type ipconfig and note the IPv4 address.

Now open up the shell on your host machine (if you are on the same network) and ping the ip-address. if you get the response, you’re good to go.

WinRM

WinRM stands for Windows Remote Management, which is a Microsoft technology that allows for remote management of Windows machines. It uses the open standard WS-Management protocol for secure and reliable communication between the machines.
fire up the powershell and type:

Image description
if the service is not running the type: Start-Service -Name WinRM
Now enable the remote connection by typing Enable-PSRemoting -Force

Image description

Chocolatey

Install the chocolatey package which is to be used by ansible to install the softwares.
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

Ports

check the following ports (5985, 5986) in your Windows defender firewall. These ports are required by ansible_winrm to communicate.

Image description
if you don’t see these ports then simply create a new Inbound rule for the given ports and enable it for all Profiles.

Host Setup

Now it’s time to set up the host node which will control your hyper-V VM. Before diving, make sure you have Docker installed. Create a new directory and cd into it. Create the following three files and leave them empty for now.

  • Dockerfile
  • inventory.ini
  • playbook.yaml (ignore .gitignore, LICENSE and README for now)

Image description

Playbook

Ansible playbooks are files containing a series of tasks that can be executed in order to automate IT infrastructure configurations and deployment processes. Playbooks are written in YAML format and can be used to execute tasks on a single or multiple hosts, depending on the requirements. They are a powerful tool for automating complex tasks and can greatly simplify IT operations.
Enter the following contents into the playbook and save it.

---
- name: Install Software on Windows VM
  hosts: windows_vm
  gather_facts: false
  vars:
    ansible_winrm_transport: ntlm
  tasks:
    - name: Install NeoVim
      win_command: choco install neovim -y

    - name: Install Git
      win_command: choco install git -y

    - name: Install Google Chrome
      win_command: choco install googlechrome -y
Enter fullscreen mode Exit fullscreen mode


Inventory
In Ansible, an inventory is a file or collection of files that defines the hosts and groups of hosts on which Ansible commands and playbooks will run. It serves as the source of truth for Ansible about the infrastructure it manages. The inventory can include details about hostnames, IP addresses, remote connection information, host grouping, and variables that provide essential context for executing automation tasks across a network.
Enter the following contents and save the file.
[windows_vm]
<ip-address> ansible_user=<username> ansible_password=<password> ansible_connection=winrm ansible_winrm_server_cert_validation=ignore


In the context of Ansible and WinRM, ansible_winrm_transport is an Ansible variable that specifies the transport method used for communication between the Ansible control node and the Windows VM. The two common options for this variable are ntlm and kerberos.

  • NTLM (NT LAN Manager): NTLM is a Microsoft authentication protocol that uses a challenge-response mechanism. It is an older authentication method and may be suitable for simpler setups or legacy systems.
  • Kerberos: Kerberos is a network authentication protocol that provides strong security and is the recommended authentication method for WinRM communication. It relies on a trusted third-party authentication server and provides secure mutual authentication between the Ansible control node and the Windows VM. To determine which transport method to use, you should consider the configuration of your Windows VM and the authentication mechanisms supported by your environment. If your Windows VM is part of an Active Directory domain and Kerberos is configured, it is generally recommended to use Kerberos for more secure authentication. However, if you are working in a non-domain environment or have specific requirements, NTLM can be used as an alternative.

Dockerfile

open up your editor and enter the following contents into the file and save it. (You can also use the official ansible image)

Image description

Build your Dockerfile

Now its time to build and run your image. Enter the following command:

docker build -t <tag-name> .
Enter fullscreen mode Exit fullscreen mode


You should see the following output:

Image description
Now run your image:
docker run <tag-name>

if successful, you should see the following output:

Image description
Go to your target VM and check the tools installed by running the following command:

choco list
​
Enter fullscreen mode Exit fullscreen mode

Image description

Troubleshooting Errors

If you get the following error: “auth method ntlm requires a username”

Image description
then check if the

  • service is running
  • ports are opened NTLM uses port 5986, check whether the WinRM Listener is listening on the required port. open up the powershell and type Get-WSManListener ​ Make sure the port is correct. If the port is correct then the issue might be the certificates NTLM requires. Run the following command:

New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbPrint <thumbprint> -Force

Replace with the actual thumbprint from your certificate:
Get-ChildItem -Path Cert:\LocalMachine\My
Image description

If you only have the self-signed certificate (localhost) then just omit the -CertificateThumbPrint parameter otherwise it will result in an error.
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -Force

if Windows cannot find the certificate due to any issue then create a new one
$cert = New-SelfSignedCertificate -DnsName "localhost" -CertStoreLocation "cert:\LocalMachine\My"

Make a note of the thumbprint value displayed after this command:
$cert.Thumbprint

Finally, run this command to include the local certificate:
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force

Restart the WinRM service to apply the changes:
Restart-Service -Name WinRM

Hopefully ansible works after this.

You can find the Dockerfile here:
https://github.com/hamzza-K/docker-ansible-hyperV.git

Top comments (0)