Managing Windows hosts using Ansible Tower/AWX and SSH

I’ve recently been working with Ansible as a configuration management solution. Workloads deployed from vRealize Automation to the private cloud are handed off to Ansible Tower, whereas existing infrastructure is managed in the downstream product – AWX. This is mainly

to do with licencing, but it also enables me to play with the latest features that appear in AWX.

Managing Linux hosts with both Ansible Tower/AWX is trivial, but Windows requires extra work. The biggest challenge is the connection, and on whether to use WinRM or SSH. The former is quite complex to configure, but there’s not a lot of information around how to set up the latter.

It is also more preferable to have just the one protocol (in this case SSH) than having a separate one depending on the OS type.

In this post, I’ll demonstrate how to use Tower/AWX to connect to Windows hosts using SSH and then “become” the Administrator after retrieving the credentials from HashiCorp Vault.

As our Windows hosts are a mixture of standalone and domain-joined machines, the solution needs to accommodate both.

Windows host – Install SSH

The first step is to install SSH on our Windows hosts. I am fortunate enough to have migrated all but two of my Windows hosts to Windows Server 2019, so it is as simple as adding a feature to the operating system. For earlier versions of Windows, you need to install the Win32-OpenSSH package manually.

Please note: whilst you can run the following scripts manually on each host, I ensure all my server images are built with these features by incorporating them into my Packer builds. You can learn more about that at Automating VDI Template Creation with VMware Code Stream and HashiCorp Packer – Part 1: Building Windows.

Install SSH on Windows Server 2019 using the following code:

# Install OenSSH
Add-WindowsCapability Online Name OpenSSH.Server~~~~0.0.1.0
# Set service to automatic and start
Set-Service sshd StartupType Automatic
Start-Service sshd
# Configure PowerShell as the default shell
New-ItemProperty Path "HKLM:\SOFTWARE\OpenSSH" Name DefaultShell Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" PropertyType String Force
# Restart the service
Restart-Service sshd

view raw
Install-Ssh.ps1
hosted with ❤ by GitHub

Windows host – Configure a User Account for SSH

Now that we’ve installed SSH, we need to configure a user account we can use to connect. As we don’t know if our machines will be standalone or domain-joined, we will configure a local user.

Following the path of least privilege, the account we create will be a basic user account. If a playbook requires admin privileges, and the Tower/AWX operator who runs the job has sufficient permissions, then Ansible can later elevate itself (known as “become”) to the administrator.

To increase security we will be using SSH keys instead of passwords. This will require us to create a new key and a random, lengthy password for the user (since we won’t be using it). After you have created your new key, save the private key somewhere safe (we’ll need that for later on) and copy the contents of the public key.

Create the user account using the following (I have named my user account sa_ansible – substitute accordingly):

# Variables
$length = 10 ## characters
$nonAlphaChars = 5
Add-Type AssemblyName 'System.Web'
# Create the user
$user = "sa_ansible"
$pass = ([System.Web.Security.Membership]::GeneratePassword($length, $nonAlphaChars))
$secureString = ConvertTo-SecureString $pass AsPlainText Force
New-LocalUser Name $user Password $secureString
$credential = New-Object System.Management.Automation.PsCredential($user,$secureString)
# Create the home folder
$process = Start-Process cmd /c Credential $credential ErrorAction SilentlyContinue LoadUserProfile
# Set random password on account
$newPass = ([System.Web.Security.Membership]::GeneratePassword($length, $nonAlphaChars))
$newSecureString = ConvertTo-SecureString $newPass AsPlainText Force
Set-LocalUser Name $user Password $newSecureString
# Configure SSH public key
New-Item Path "C:\Users\$user" Name ".ssh" ItemType Directory
$content = @"
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfr9pOP8v6YDCaSEV90fzASzM4tbKE1TJ9oVen+euDZcbz5MihPuI5/EVfS98CQHVhn/dw3Bc/VK9lOWNymzpXWMkaNIvCcdGAB7EnLO0PjwOiueePZmVgGvFB4L8VeE+LNqQeiGJHa9qNhxQrc/hO2q+ziLQ7kA9h9e6g7HBBYvJ3WNodxQpmdcRcPHKZKHLJ8gtUIqaHFAABSueWfKlOl5FNFwEYuCu0I4aie1z6rIKyuej9zcoiEG3EDU7I0ozWlPcXiQCWfMAjzS/TCLM1zTP6UczlPcipW76YjMg7A9Zdge9KrT8ajSl01Wc4Q5HOUHWTLK5xfRLaGResom2yplWXLR6fjHum6xZtuxWOZXbhMWsqwrN2+06B3zfiubTnw2EEfBt4QYsL8fnBV4rT91ZFwfvmSgWfCLy2sUsrQqdrGH1M8b0nLu3fdsHemqcNBoDvP3eQGNcM5zy49P9+578fHmTtT6Swk+0GYC9IimAPK+NXHD4LWC/cUbCpqAM= sa_ansible
"@
# Write public key to file
$content | Set-Content Path "c:\users\$user\.ssh\authorized_keys"

Replace the SSH key on line 24 with your newly-created public key.

Please note: for the basic user account to become Administrator it requires the Impersonate a client after authentication (SeImpersonatePrivilege) right. If you don’t grant this, the become operation will fail:

You shall not pass!

Use the local security policy to grant the user account you created above the necessary privilege.

As we’ll be automating this script using Packer, we will use the following module from Tony Pombo to grant the required privilege. You can download it from https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0.

Use the following to import the module and grant the privilege (substitute accordingly):

Import-Module .\UserRights.psm1
Grant-UserRight sa_ansible SeImpersonatePrivilege

Configure Ansible Tower/AWX

Now we have configured our Windows machines (or Packer images) with SSH and our user account, it is time to configure Ansible.

Credential

Navigate to Credentials and create a new one. Give it a name, select your organization, and set the Credential Type to Machine. Specify the username (from the code above) and paste in your SSH private key:

Variables

We now need to define our variables which will be applied to our Windows hosts. To do this I have created a group for my hosts (aptly called “Windows”) and applied the following:

ansible_shell_type: powershell
ansible_become: yes
ansible_become_method: runas
ansible_become_user: Administrator
ansible_become_password: "{{ lookup('hashi_vault', 'secret=creds/production/{{ inventory_hostname }}:Password')}}"

view raw
variables.yaml
hosted with ❤ by GitHub

Please note: for more information on how the HashiCorp Vault lookup works, please refer to Enabling HashiCorp Vault Lookups in Ansible AWX.

Host

Add your Windows hosts to your inventory and to the group you have created above.

Testing It Out

To test our Windows connection, create a job template using the following simple playbook:

hosts: Windows
gather_facts: true
tasks:
name: "What's my name again?"
debug:
msg: '{{ ansible_user }}'
become: yes

view raw
gatherFacts.yml
hosted with ❤ by GitHub

Run the template and verify it is successful. If it is, the facts for those hosts will be updated.

One thought on “Managing Windows hosts using Ansible Tower/AWX and SSH

  1. Pingback: Managing Windows Hosts Using Ansible Tower/Awx and SSH - Gestalt IT

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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