CIQ

Ascender Windows Quick Start Guide

Ascender Windows Quick Start Guide
Greg SowellNovember 10, 2023

Connecting Ascender and/or Ansible to a Windows host can seem a little obtuse at first, but the aim here is to get you up to speed with as few steps as possible. The demo will be showing a classic, pushing Windows updates, but with a twist; I’ll be creating a VMware snapshot first, performing updates; if it fails, it will rollback the snapshot (then delete it); if it succeeds, it will simply delete the snapshot and be done.

Video

https://youtu.be/2ANcQOwqXKk?feature=shared

Connecting To Windows Hosts

By default, Ansible assumes you will be connecting via SSH, and in our case, we want to utilize WinRM to connect to our Windows hosts. We can accomplish this by setting some key variables for the hosts (most often, this is done in the inventory under a group the server is a member of):

ansible_connection: winrm

Use winrm rather than the default SSH

ansible_port: 5985

By default WinRM uses ports 5986/HTTPS or 5985/HTTP

ansible_winrm_server_cert_validation: ignore

If using self signed certificates

ansible_winrm_transport: kerberos

Many choices for transport, specify chosen

ansible_winrm_kerberos_delegation: yes

When using kerberos allow delegation

In the above, ansible_connection and Ansible_winrm_server_cert_validation will generally be the same for everyone, but the others are variable. What you choose for transport often dictates the other options.  

Using the HTTP port 5985 is usually just fine, as WinRM itself is encrypted.

As for Transport, there are multiple options, listed here:

Basic

  • Not encrypted

NTLM

  • Enabled by default

  • Strong hash

  • Not as secure

Certificate

  • Very difficult to setup

  • Valid certs/CAs required

  • Certificate is based off user account

CredSSP

  • Supports Multi-Hop

  • Credentials delegation on remote machine

  • Utilizes TLS Tunnel / NTLM / Kerberos

Kerberos

  • Domain membership required

  • Kerberos tokens used for authentication

  • Supports Multi-hop when using delegation

Generally, NTLM and Kerberos are enabled by default. NTLM is often used to initially connect to and add a host to the domain. At this point, Kerberos is generally utilized, as it tends to be the most secure. If a host isn’t on a domain, CredSSP is most often used.

Here’s a screenshot of the settings added to a Windows group in Ascender:

Playbook

The playbook can be found here and is named win-updates.yml. I’ll break it into pieces for easier consumption:

---
- name: windows update in vmware with snapshots
  hosts: Greg-Win-IIS1
  gather_facts: false
  vars:
    vcenter_hostname: 10.1.2.3
    vcenter_username: "{{ gen1_user }}"
    vcenter_password: "{{ gen1_pword }}"
    datacenter_name: MNS

The above has gather_facts set to false. By default, it is enabled and will collect and variabilize information about the system for use in our automations. Since I’m not using any of that info, I turn it off to make the playbook run more efficiently. 

After that, I have some “vars,” or variables. I tend to put all variables here, even if they will be overwritten by extra vars being passed in at execution time, just so it’s easier to see what’s available for change in the playbook.

  tasks:
  - name: create VM snapshot
    community.vmware.vmware_guest_snapshot:
      validate_certs: false
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      datacenter: "{{ datacenter_name }}"
      folder: "/Greg/ciq/"
      name: "{{ inventory_hostname }}"
      state: present
      snapshot_name: snap-update
      description: snapshot for updates
      memory_dump: true
    delegate_to: localhost

  - name: device in maint mode
    debug:
      msg: "Put {{ inventory_hostname }} into maint mode"

This begins the task section, where each task is a unique, discrete task to perform. I start by connecting to my VMware VCenter and performing a snapshot on the VM. The next task is a placeholder where I would put a task to call my monitoring system and put this host into maintenance mode.

  - name: perform update procedure in block
    block:
      - name: perform updates on the server
        ansible.windows.win_updates:
          category_names:
            - CriticalUpdates
#            - SecurityUpdates
#            - UpdateRollups
# setting the state to searched below is akin to "check" mode.  It only does a lookup.
          state: searched
        register: update_res

    rescue:
      - name: win update failed, so rollback the snapshot
        community.vmware.vmware_guest_snapshot:
          validate_certs: false
          hostname: "{{ vcenter_hostname }}"
          username: "{{ vcenter_username }}"
          password: "{{ vcenter_password }}"
          datacenter: "{{ datacenter_name }}"
          folder: "/Greg/ciq/"
          name: "{{ inventory_hostname }}"
          state: revert
          snapshot_name: snap-update
        delegate_to: localhost

The next two tasks live inside a block. A block is a convenient way to group certain tasks together. Here I’m first performing the Windows update, though I have the state set to “searched,” which essentially means that it will check and see what would be updated. I leave it in this mode for demo purposes. In production, I would actually apply updates.

The task under the rescue section is only run if the update task errors out. This means if the update fails, then we will call the rescue section and restore the snapshot we just took, thus restoring the server to working order!

  - name: Completed processing, delete snapshot
#    when: update_res.changed == true
    community.vmware.vmware_guest_snapshot:
      validate_certs: false
      hostname: "{{ vcenter_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      datacenter: "{{ datacenter_name }}"
      folder: "/Greg/ciq/"
      name: "{{ inventory_hostname }}"
      state: absent
      snapshot_name: snap-update
    delegate_to: localhost
    ignore_errors: true

  - name: device out maint mode
    debug:
      msg: "Remove {{ inventory_hostname }} from maint mode"

The last real task calls vmware and deletes the snapshot.

After that is a debug that is essentially a placeholder for removing this device from maintenance mode.

Ascender

Inventory

We start configuring Ascender by adding an inventory. This is done via inventories, clicking add, and choosing inventory:

In here, I give the inventory a meaningful name and click save:

I now click on the hosts tab and then add a host:

From here, I fill in a meaningful name and then click save. If the name is a Fully Qualified Domain Name, then I’m done. In my case, it is not, so I add a special variable “ansible_host” that instructs Ansible to use the supplied IP address to connect to the host:

I’ll then create a group with the following variables:

---
ansible_connection: winrm
ansible_winrm_scheme: http
ansible_port: 5985
ansible_winrm_transport: ntlm

I’ll then go to the hosts tab inside the group and add my existing hosts:

Projects

Now I’ll add my project. A project connects Ascender to a git repository to bring in your playbooks, templates, etc. Click on projects under the resource menu, then click add:

I give it a meaningful name, choose “git” as the “source control type,” put my repository in the “source control URL”(https://github.com/gregsowell/ansible-windows), and click save:

Credentials

Next, I’m going to add some credentials, but first I need to create a custom credential. A custom credential gives me the ability to design a credential to collect and store any special information from a user in the credential section. I’ll do this by going to the administration menu, clicking on Credential Types, then adding:

I’m now creating what I call “generic credential 1”.

The input configuration is:

fields:- id: supp_gen1_user    type: string    label: Username  - id: supp_gen1_pword    type: string    label: Password    secret: truerequired:  - supp_gen1_user  - supp_gen1_pword

The injector configuration is:

extra_vars:
  gen1_user: '{{ supp_gen1_user }}'
  gen1_pword: '{{ supp_gen1_pword }}'

As you can see, I’m collecting a username and a password. I’ve designated the password as “secret” so that it will obfuscate the information. I then inject the credential as an extra variable at execution time; there are other options for injection, say for example, environment variables.

I’ll then go to the resource menu, then the credentials section, and add both a machine credential and a credential of type “generic credential 1”. The machine credential is the username/password that I’ll log into the Windows machine with:

The generic credential is what I use to connect to my VMware server:

Job Template

Next, I’ll create a job template that brings all of the components together. In the resources menu, click on templates, add, and then add a job template:

I’ll then give it a name, choose the inventory, choose the project, choose the playbook, and lastly, add my newly created credentials:

At this point, there’s nothing left to do but click launch:

Conclusion

As you can see, it really isn’t too bad to begin operating against Windows machines. Getting started should be even simpler with this Windows Quickstart Guide!

As always, if you have any questions or comments, please reach out to me or the CIQ team. Happy automating, my friends!

Related posts

Ascender Config as Code with Network Backups to Git and Rollback

Ascender Config as Code with Network Backups to Git and Rollback

Aug 23, 2023

Ascender Automation

Ascender Custom Dynamic Inventory Scripts

Ascender Custom Dynamic Inventory Scripts

Nov 14, 2023

Ascender Automation

Ascender Migrates Host From CentOS 7 To Rocky 8

Ascender Migrates Host From CentOS 7 To Rocky 8

Oct 11, 2023

Ascender Automation

123
7
>>>