Configuring Windows machines for Ansible

0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- 0 Flares ×

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

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:

Solarwinds winrm

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"
}
Using the Solarwinds tool, you can quickly and easily re-configure all existing machines to be ready to be controlled by Ansible, and obviously a good practice is to also run the tool against vSphere templates, so that any new VM deployed from the template is already enabled. My entire group of Windows servers can now be managed via Ansible:
[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
}

 

0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- 0 Flares ×