White Paper
May 14, 2019
Ansible and Ansible Tower are known to be great automation and configuration management tools, and are enjoyed by developers and IT operations departments alike. Because the majority of environments with Ansible Tower are primarily comprised of Linux servers, I often receive questions about how well Ansible Tower works with Windows servers. To the surprise of some people, Ansible Tower is a great product for any IT environment! Teams can deploy and manage windows servers quite easily, as Ansible Tower by default comes with modules that can be used to deploy and manage Windows. The following content gives some information and use cases on how to use Ansible Tower with your Windows environment in AWS.
As with Linux, almost anything can be scripted and automated in Windows. Powershell is a very powerful tool that every savvy windows server administrator should know. In order for Ansible to manage Windows servers, WinRM and PSRemoting must be enabled.
Ansible and Ansible Tower uses the WinRM (Windows Remote Management) feature to execute commands, including Powershell scripts remotely. The PyWinRM python module that must be installed on the Ansible host provides the libraries to query the WinRM daemon.
Ansible provides a comprehensive solution to automating your entire environment, with an extensive list of pre-built modules. For example, there are modules for Cisco devices, NetApp, Servers (Linux & Windows), cryptography, etc. What this means for you and your environment is that you now have the capability to automate everything using a stable and high performance automation engine.
The specific scenario I will describe in this post, is a simple end-to-end deployment of an IIS application in a Windows server. Ansible will create and launch and AWS EC2 instance using an AMI, enable WinRM and PSRemoting, set the administrator credentials, install all of the required windows server features, and then deploy and test an application.
Several things will be needed for this exercise:
The first thing we need to do is prepare our Ansible Tower server. This blog post assumes you already have a base installation of Ansible Tower on a Red Hat Enterprise Linux server. I’m currently using Ansible Tower 3.3.0.
[root@ip-172-30-0-141 ~]# tower-manage --version
3.3.0
[root@ip-172-30-0-141 ~]# python --version
Python 2.7.5
[root@ip-172-30-0-141 ~]# yum install python2-pip
[root@ip-172-30-0-141 ~]# pip install pywinrm python2-boto python2-boto3 python2-botocore
A Project in Ansible Tower defines the location of the playbooks you wish to use in your template. The template will be the last object in Ansible Tower we will create.
---
ansible_connection: local
---
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
After you have completed adding the group, the inventory is complete. Next steps is to create the template.
The template is specifying all of the parameters needed to execute the job. We will be creating a survey — a pop-up prior to the job executing requesting you to fill out a list of variables. There are different types of data fields, including lists, text areas, and password fields. We will be using these three different field types so you can see the differences in how data is handled in Ansible Tower. Password fields, for example, are encrypted, and you can never actually see the data that has been entered; it will only show as ‘$encrypted$’.
Once you have clicked ‘+ADD’, you will see your new survey prompt field down at the bottom of the screen under PREVIEW, along with any default value you may have set.
Go through the list and add all of the variables from the list above. When you have finished adding the variable prompts, your PREVIEW section should look like the following.
---
aws_region: us-east-2
iis_roles_features: >-
Web-WebServer,Web-Common-Http,Web-Static-Content,Web-Default-Doc,Web-Http-Errors,Web-Http-Redirect,Web-ASP,Web-Http-Logging,AS-Web-Support
ami_name: Windows_Server-2012-R2_RTM-English-64Bit-Base-*
instance_type: t2.micro
ansible_user: Administrator
ansible_password: $encrypted$
aws_access_key_id: $encrypted$
aws_secret_access_key: $encrypted$
As you can see in the image above, the job completed successfully and also completed the test to ensure the application is online. This is all explained in the code review section. You can enter the url provided by the output of the execution log and insert in to a browser.
You can also verify that the server was deployed successfully by accessing the machine via RDP. The credentials are the ones specified in the survey prompts. As you can see, the response from the application is running in IIS, and the server name matches the hostname from the server properties I’ve displayed from the RDP session.
Before running the playbook:
After running the playbook:
We’re going to take a quick look at this demo playbooks code to see how it deploys an AWS EC2 Windows AMI, waits for it to become available, then installs IIS Features, deploys an application, and runs a test to ensure it’s up and running.
aws-ansible-demo/aws-windows.yml
---
- name: "Launch Windows AMI."
hosts: localhost
roles:
- aws-windows
- name: "Setup web application."
hosts: windows
roles:
- iis-webapp
There are two roles in this playbook, the first one is called ‘aws-windows’, and it executes on the localhost, which is all that is required to query the AWS API.
aws-ansible-demo/roles/aws-windows/tasks/main.yml
---
- name: "Find current, region-specific Windows AMI." - 1.1
ec2_ami_find:
aws_access_key: "{{ aws_access_key_id }}"
aws_secret_key: "{{ aws_secret_access_key }}"
region: "{{ aws_region }}"
platform: windows
virtualization_type: hvm
owner: amazon
name: "{{ ami_name }}"
no_result_action: fail
sort: name
sort_order: descending
register: found_amis
- set_fact:
win_ami_id: "{{ (found_amis.results | first).ami_id }}" - 1.2
when: found_amis.results is defined
- name: "Create security group for WinRM and RDP." - 1.3
ec2_group:
aws_access_key: "{{ aws_access_key_id }}"
aws_secret_key: "{{ aws_secret_access_key }}"
name: "WinRM RDP"
description: "Inbound WinRM and RDP"
region: "{{ aws_region }}"
rules:
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 5986
to_port: 5986
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 3389
to_port: 3389
cidr_ip: 0.0.0.0/0
register: security_group
- name: "Start Windows instances." - 1.4
ec2:
aws_access_key: "{{ aws_access_key_id }}"
aws_secret_key: "{{ aws_secret_access_key }}"
region: "{{ aws_region }}"
image: "{{ win_ami_id }}"
instance_type: "{{ instance_type }}"
group_id: "{{ security_group.group_id }}"
wait: yes
wait_timeout: 500
exact_count: 1
count_tag:
Name: ansible-managed
instance_tags:
Name: ansible-managed
user_data: "{{ lookup('template', '{{ role_path }}/templates/userdata.txt.j2') }}"
register: ec2_result
- name: "Wait for WinRM on all hosts." - 1.5
wait_for:
port: 5986
host: "{{ item.public_ip }}"
timeout: 300
with_items: "{{ ec2_result.tagged_instances }}"
- name: "Add hosts to inventory." - 1.6
add_host:
name: "{{ item.id }}"
ansible_host: "{{ item.public_ip }}"
groups: windows
changed_when: false
with_items: "{{ ec2_result.tagged_instances }}"
The tasks in the ‘aws-windows’ role prepare AWS EC2, finds the AMI requested in the survey, starts the Windows instance while using the ‘userdata.txt.j2’ template to run a simple Powershell script that enables PSRemoting, and sets the Administrator password. It waits for the instance to come available, then dynamically adds the instance to the ‘windows’ inventory group we created.
aws-ansible-demo/roles/iis-webapp/tasks/main.yml
---
- block:
- name: "Install IIS, roles, and features." - 2.1
win_feature:
name: "{{ iis_roles_features }}"
state: present
restart: no
include_sub_features: no
include_management_tools: no
notify: restart iis
when: iis_roles_features is defined
- name: "Create ping directory." - 2.2
win_file:
path: c:\inetpub\ping
state: directory
- name: "Create a default response page." - 2.3
win_copy:
src: "{{ role_path }}/files/default.aspx"
dest: c:\inetpub\ping\default.aspx
- name: "Create ping web application." - 2.4
win_iis_webapplication:
name: ping
physical_path: c:\inetpub\ping
site: Default Web Site
- name: "Test ping web application." - 2.5
uri:
url: http://{{ ansible_host }}/ping
return_content: yes
register: uri_out
delegate_to: localhost
until: uri_out.content | search("Pong from")
retries: 3
- debug: - 2.6
msg: Web application is available at http://{{ ansible_host }}/ping
The ‘iis-webapp’ role is specifically for configuring the Windows server, deploying the simple IIS web application, and then verifying it has deployed successfully.
We are an IT, strategy, and design consulting firm that combines the innovative DNA of a startup with the wisdom, scalability, and process rigor of a Fortune 100 company.
Levvel’s proven DevOps Assessment methodology delivers a precise strategy to enable your team to deliver on key practices that help organizations innovate faster through automating and streamlining the software development and infrastructure management processes.
We firmly believe that mentoring can be integrated with delivery. Our main focus is on saving our partners as much as possible on the lifetime total cost of ownership and maintainability of their systems. For more information, contact us at hello@levvel.io.
Authored By
Daniel Foley
DevOps Manager
Meet our Experts
DevOps Manager
Daniel Foley is a DevOps Manager at Levvel who is well-versed in many different applications including Apache, MySQL, Puppet, Ansible, Zerto Replication, Centrify, McAfee EPO, Bromium Security, EMC Avamar, OpenShift, Elasticsearch, Prometheus, Docker, Kubernetes, among others. Daniel enjoys scripting to make his life as a Systems Engineer easier and to aid teams and clients. He is extremely familiar with Bash scripting, Python programming, and some Perl and Ruby.
Let's chat.
You're doing big things, and big things come with big challenges. We're here to help.