As I’m studying Ansible, one of my goal is to manage my several Windows machines with it. I know it sounds strange as Ansible was first designed to deal with Linux systems, but this powerful configuration management platform supports Windows since version 1.7, and is completely agentless: it relies on SSH for linux/unix machines, and Windows Remote Management (WinRM) for Windows machines. Through WinRM, Ansible can connect to Windows machines ard run PowerShell scripts. The idea of using Powershell as the main code to execute tasks in Windows systems, together with the agentless approach, made me be even more curious in learning more about the Windows support.
Prerequisites
WinRM is available since Windows Vista SP1 or Windows 2008, so older machines cannot be managed by Ansible. But this is not a limit for me as I’m using at least 2008 R2 in my entire lab, and I try as much as possible to not use OS that are not supported anymore by Microsoft. I hope also people that are considering a configuration management software like Ansible would use it as a part of a modern datacenter, and not to run VBS scripts against Windows NT dinosaurs…
Second, PowerShell 3.0 or higher is needed for most of the provided Ansible modules for Windows. PowerShell 3.0 is only supported on Windows 7 SP1, Windows Server 2008 SP1, and later releases of Windows. It can be installed in older Windows versions, but again is not something I need.
Basically, in general once you have at least Windows 7 SP1 or Windows Server 2008 SP1, you are good to go with Ansible.
Prepare Ansible
First, we need to have Ansible up and running with the required modules to be able to manage Windows machines. The Ansible docs on Windows are extremely well written, but just for not having to jump in and out of this blog post, here’s what you have to do once you have a running Ansible installation. My examples are created on a CentOS 7 machine, have a look at the official documentation or other resources if you are using a different distribution.
First, you need to instal Ansible itself. It’s available in the EPEL repository, so add it and install the software:
yum -y install epel-release yum -y update yum -y install ansible
Once installed, check the version to be sure you have at least version 1.7, as said the first to support Windows OS:
[root@ansible ~]# ansible --version ansible 2.1.1.0 configured module search path = Default w/o overrides
Ok, now we need PIP to install additional modules. PIP is a Python package manager, and it’s not installed by default. It’s available too in the EPEL repository, so its installation is pretty easy since we have already EPEL configured:
yum install -y python-pip
Ansible will be run from a Linux control machine, and will use the “winrm” Python module to talk to remote hosts. We use PIP to install this module:
pip install https://github.com/diyan/pywinrm/archive/master.zip#egg=pywinrm
If you wish to connect to domain accounts published through Active Directory, as opposed to local accounts created on the remote host, you will need Kerberos module. Note that this does not installs kerberos itself. Kerberos is installed and configured by default on many Linux distributions. If your control machine has not already done this for you, you will need to (before installing the kerberos PIP module):
yum -y install gcc python-devel krb5-devel krb5-workstation pip install kerberos
In /etc/ansible/hosts, we add the Windows machines we want to manage:
[windows] dc01.skunkworks.local dc02.skunkworks.local vcenter.skunkworks.local veeamsrv.skunkworks.local [windows:vars] ansible_ssh_user=administrator@SKUNKWORKS.LOCAL ansible_ssh_pass=SecretPasswordGoesHere ansible_ssh_port=5986 ansible_connection=winrm
I’ve defined the common variables for the [windows] group in the [windows:vars] section of the file. You can also have a dedicated file to specify these values. Note that it says ssh, but in reality those parameters are used for WinRM connections. It’s just that Ansible is SSH oriented…
Since I’ve used the administrator@domain format in the username, this means Ansible will try to use kerberos to authenticate against Active Directory. So, we also need to configure Kerberos in the linux machine. Edit /etc/krb5.conf and make it like this:
[logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmind.log [libdefaults] dns_lookup_realm = false ticket_lifetime = 24h renew_lifetime = 7d forwardable = true rdns = false default_realm = SKUNKWORKS.LOCAL default_ccache_name = KEYRING:persistent:%{uid} default_tgs_enctypes = arcfour-hmac-md5 des-cbc-crc des-cbc-md5 default_tkt_enctypes = arcfour-hmac-md5 des-cbc-crc des-cbc-md5 [realms] SKUNKWORKS.LOCAL = { kdc = dc01.skunkworks.local admin_server = dc01.skunkworks.local } [domain_realm] .skunkworks.local = SKUNKWORKS.LOCAL skunkworks.local = SKUNKWORKS.LOCAL
Test that domain authentication via kerberos is working (write the realm in Capitol as it’s written in kerberos configuration file, and it should also be like this in Ansible vars):
[root@ansible ansible]# kinit administrator@SKUNKWORKS.LOCAL Password for administrator@SKUNKWORKS.LOCAL: [root@ansible ansible]#
If login to AD is successful, the shell whould return an empty answer. You can check that you correctly obtained a Kerberos ticket:
[root@ansible ansible]# klist Ticket cache: KEYRING:persistent:0:0 Default principal: administrator@SKUNKWORKS.LOCAL Valid starting Expires Service principal 08/12/2015 11:56:39 08/12/2015 21:56:39 krbtgt/SKUNKWORKS.LOCAL@SKUNKWORKS.LOCAL renew until 08/19/2015 11:56:36
Good, Kerberos is working, and we can use a single user to login from Ansible in any AD-joined machine.
With Kerberos in place, we can try to check WinRM connection:
[root@ansible ansible]# ansible dc01.skunkworks.local -m win_ping dc01.skunkworks.local | FAILED => 500 WinRMTransport. [Errno 111] Connection refused
Note that the command is not a TCP ping, but it tries to connect to WinRM. The connection is refused, which means we need first to setup WinRM on the Windows machines.
Existing machines
Chances are you environment is already running Windows machines, either physical servers or VMs. I’m talking about VMs in my examples, but any windows machine can be managed in the same way. As explained before, both required components are already available in a running system, but we still need to check if they can be used. This is because some configurations of WinRM prevent remote access to it, or it could be configured in a way that Ansible doesn’t like.
The Ansible documentation has a nice script to enable and configure WinRM in any Windows machine. It’s written obviously in Powershell (eat your own dog food!) and it’s easy to use, but it’s a bit of a “Catch 22” situation, we should use the script against Windows machines from Ansible, but there’s no configuration yet to allow Ansible to reach WinRM.
I’ve found a different solution for existing machines: Solarwinds has a free tool called Remote Execution Enabler for PowerShell, that does exactly what it says:
After the Windows machine has been enabled, the Ansible win_ping command is now working:
[root@ansible ansible]# ansible dc01.skunkworks.local -m win_ping dc01.skunkworks.local | success >> { "changed": false, "ping": "pong" }
[root@ansible ansible]# ansible windows -m win_ping vcenter.skunkworks.local | success >> { "changed": false, "ping": "pong" }dc01.skunkworks.local | success >> { "changed": false, "ping": "pong" }dc02.skunkworks.local | success >> { "changed": false, "ping": "pong" }veeamsrv.skunkworks.local | success >> { "changed": false, "ping": "pong" }
Once the system is ready, you can start looking at the Ansible Windows modules. Among the many that are available, I’m just highlighting a few like win_feature (Installs and uninstalls Windows Features) or win_regedit (Add, Edit, or Remove Registry Keys and Values). Or, you may not even need to load and use a module, other than the “script” module, that can be used to run arbitrary PowerShell scripts.
Finally, just as with Linux/Unix, facts can be gathered for windows hosts, which will return things such as the operating system version. To see what variables are available about a windows host, run the following:
[root@ansible ansible]# ansible vcenter.skunkworks.local -m setup vcenter.skunkworks.local | success >> { "ansible_facts": { "ansible_distribution": "Microsoft Windows NT 6.1.7601 Service Pack 1", "ansible_distribution_version": "6.1.7601.65536", "ansible_fqdn": "VCENTER.skunkworks.local", "ansible_hostname": "VCENTER", "ansible_interfaces": [ { "default_gateway": "10.2.50.254", "dns_domain": null, "interface_index": 12, "interface_name": "vmxnet3 Ethernet Adapter" } ], "ansible_ip_addresses": [ "10.2.50.111", "fe80::c5a0:88d2:3e5b:411" ], "ansible_os_family": "Windows", "ansible_powershell_version": 3, "ansible_system": "Win32NT", "ansible_totalmem": 8589934592, "ansible_winrm_certificate_expires": "2065-07-29 16:16:09" }, "changed": false }