Ansible to manage Windows servers

At the end of the last post, I mentioned that while Ansible is a Linux-based tool, it can also be used to manage Windows servers. In fact, there are dozens of pre-built modules available to do everything from configuring services to managing disks and processes.

But getting Ansible connected to Windows servers doesn’t just happen out of the box. That’s what this post is about, to provide an overview and some examples, so you can get Ansible talking to the Windows endpoints in your homelab or test environment using Windows Remote Management (WinRM).


Create a service account and enable WinRM

My test lab has an Active Directory (AD) domain, so this was pretty simple. First, I created a service account in AD that Ansible will use to connect to the Windows servers. Then, I created a group called ‘Local Admins (no interactive logon)’ and put my service account into this group.

I then created two new GPOs. The first allows the service account to log on as a batch job, but restricts it from being used to log in to an interactive session (screenshot below). After all this account isn’t supposed to be used by admins directly, it’s just for Ansible. The second GPO just adds the ‘Local Admins (no interactive logon)’ group to the Restricted Groups, so the Ansible service account can do things that require local Administrator privileges.

A third GPO (next two screenshots) gets WinRM enabled and configured on my Windows servers. This GPO makes sure the WinRM service is started automatically, and does not allow unencrypted WinRM traffic. In this lab setup, Kerberos provides message-level encryption of the WinRM connection and commands, using the default WinRM port 5985.

I also added explicit allow rules for WinRM in another GPO that manages the local Windows Firewall. And that’s it. Run gpupdate or reboot your Windows servers, and they should be ready to accept WinRM commands.


Set up the Ansible control node

Now is a good time to create a directory for your Windows playbooks. I chose /etc/ansible/playbooks, where I have a Linux and Windows folder. This helps me keep them organized. The Ansible control node needs a couple of packages installed. Note that I am using Red Hat 9 in my lab, so your commands may vary if you’re using something else.

  1. dnf install ansible-core
  2. dnf install python3-devel python3-pip
  3. dnf install krb5-workstation krb5-devel krb5-libs
  4. ansible-galaxy collection install ansible.windows

The first command installs some necessary Python packages. The second installs a client and tools necessary for the control node to get a Kerberos ticket, which Ansible can use ‘under the hood’ when running commands and playbooks on the Windows servers. The third installs a collection of Windows-specific tools and modules for Ansible.

The krb5 package makes a config file at /etc/krb5.conf. In this file, you specify the domain you want to get Kerberos tickets from. I have the domain controller set as the DNS server for my Ansible control node, but you could just put a line in the /etc/hosts file as well.

In this example, the AD domain name is ad.mydomain.local and my domain controller is called lab-dc1. Pay attention to the capitalization here – you want your krb5.conf file to look like this:

Then add some WinRM parameters to your Ansible hosts file. In my lab at the moment, I have a host group called Windows_Servers that contains a single dev/test server. Below the group, I have a group:vars section that specifies some Ansible parameters for that Windows_Servers group only. Here I tell Ansible that I want it to use WinRM with Kerberos on port 5985, and to use the AD\ansible service account:


Get a Kerberos ticket and run a playbook

Request a Kerberos ticket by running kinit ansible@AD.MYDOMAIN.LOCAL and providing the service account password when prompted. You can verify you have a valid ticket by running klist. The output of klist will show which account you have a ticket for, and when it will expire. Run kdestroy to delete all Kerberos tickets from the store.

Now just create or choose a playbook that specifies the Windows_Servers host group, and test it out: ansible-playbook /path/to/windows_playbook_1.yml

And there you go! Ansible just made an encrypted WinRM connection to a Windows server, and did some stuff!

The challenge from here is learning how to generate the kerberos tickets automatically, and run the playbooks on a schedule for recurring tasks. You could use Ansible Tower/AWX or the Automation Platform, of course. But for my lab, I want a more lightweight solution. I’ll let you know when I figure it out.