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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
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):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
— | |
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')}}" |
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
— | |
– hosts: Windows | |
gather_facts: true | |
tasks: | |
– name: "What's my name again?" | |
debug: | |
msg: '{{ ansible_user }}' | |
become: yes |
Run the template and verify it is successful. If it is, the facts for those hosts will be updated.
Pingback: Managing Windows Hosts Using Ansible Tower/Awx and SSH - Gestalt IT
https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0 is dead i dont find the right script to allow
LikeLike