Das Automatisieren des Patch-Deployments auf Windows mit Ansible / AWX, Teil 5: das Inventar, der erste Kontakt und das erste Playbook

Teil 5 der Artikelserie über die Automatisierung mit Ansible.

Vorwort

In Teil 5 der Artikelserie über die Automatisierung mit Ansible anhand des Beispiels “Patch Deployment auf Windows” erstellen wir unser Inventar, testen die Verbindung mit unseren Hosts und verfassen unser erstes Playbook.

Das Inventar

Ansible kann gleichzeitig gegen (bzw. mit) mehrere Systeme in Deiner Infrastruktur arbeiten. Damit es das kann, ist eine Inventar-Datei notwendig, aus welchem sich Ansible die notwendigen Informationen (FQDN, Gruppenzugehörigkeit, eventuell Variablen) holt.

Erstelle bitte im Git-Repo eine Datei namens “inventory” und bearbeite sie:

Für unser Beispiel bilden wir eine Host-Gruppe namens “windows”, welche alle unsere Windows Server Hosts enthält:

Moment mal. Du wirst Dich nun sicher fragen, ob das nicht zu kurzfristig gedacht ist? Richtig! Nicht alle Windows-Server sollten gleichzeitig aktualisiert und potentiell neu gestartet werden… Ändern wir also unser Inventar geringfügig:

Wir haben nun je eine Gruppe für die WSUS-Server, die generischen Server und die ADC’s erstellt. Die ADC’s sind in zwei Gruppen unterteilt, damit niemals alle gleichzeitig bearbeitet werden.

Zusätzlich haben wir eine Gruppe erstellt, welche die anderen Gruppen zusammenfasst. Beachte den :children-Zusatz im Gruppenname, damit signalisieren wir Ansible, dass es sich um eine Gruppe von Gruppen handelt.

Nun müssen wir Ansible noch sagen, wie wir auf die Hosts zugreifen möchten.

Dazu fügen wir den folgenden Abschnitt in die Inventardatei ein:

[windows:vars]
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
ansible_winrm_operation_timeout_sec=60
ansible_winrm_read_timeout_sec=70
ansible_become=false

Mit diesem Abschnitt definierst Du, dass Du mit den Hosts in der Gruppe “windows” mit WinRM über Port 5986 kommunizieren möchtest, dass Du das Serverzertifikat ignorieren möchtest (Achtung: Das ist ein Sicherheitsproblem, ich werde in einem späteren Kapitel noch darauf eingehen), definierst einige Timeouts und sagst, dass Ansible “become” (bsp. sudo unter Linux, runas unter Windows) nicht nutzen soll.

Verbindung testen

Nun können wir erstmals die Verbindung zwischen dem Ansible-Host und den Windows-Servern testen. Dazu ziehst Du Dir ein neues Kerberos-Ticket, falls es abgelaufen ist (Siehe Teil 4):

Auf geht’s, lassen wir Ansible die Windows-Hosts “pingen” (wir benutzen das Ansible-Modul ping, nicht ICMP echo request). Bitte setze folgendes Kommando ab:

ansible -i inventory windows -m win_ping \
  -u {{ windows_upn }} -k

Die Parameder bewirken folgendes:

  • -i inventory: Diese Inventar-Datei wird verwendet.
  • windows: Auf diese Hostgruppe wird der Befehl angewendet.
  • -m win_ping: Führe das Modul “win_ping” aus.
  • -u {{ windows_upn }}: Benutze diesen Benutzernamen, muss mit dem Kerberos-Anmeldenahmen übereinstimmen.
  • -k: frage nach dem Kennwort

Enttäuschend, nicht wahr? In Teil 4 habe ich leider einen kleinen Fehler eingebaut – die von Ubuntu angebotene python-winrm-Version ist leider zu alt. Wir entfernen diese, installieren die notwendigen python- und kerberos-dev Pakete und “pip”, den python package manager:

sudo apt remove python-winrm
sudo apt install python-pip gcc python-dev libkrb5-dev

Nun können wir mit pip pywinrm und requests-kerberos installieren:

sudo pip install pywinrm requests-kerberos

Mal sehen, ob Ansible jetzt mit den Windows-Servern kommunizieren kann:

Ta-Da!

Das erste Playbook

Wir erstellen nun unser erstes Playbook. Erstelle bitte eine neue Datei und editiere diese:

nano -w windows-updates-search.yml

Unser erstes Playbook sieht so aus:

---
- hosts: Windows
  tasks:
    - name: search for windows updates
      win_updates:
        category_names:
        - Application
        - Connectors
        - CriticalUpdates
        - DefinitionUpdates
        - DeveloperKits
        - FeaturePacks
        - Guidance
        - SecurityUpdates
        - ServicePacks
        - Tools
        - UpdateRollups
        - Updates
        reboot: no
        state: searched
      register: win_updates
    - name: print variable
      debug:
        msg: '{{ win_updates }}'

Lass uns das Playbook Zeilenweise durchgehen:

01 ---
02 - hosts: windows
03   tasks:
04     - name: search for windows updates
05       win_updates:
06         category_names:
07         - Application
08         - Connectors
09         - CriticalUpdates
10         - DefinitionUpdates
11         - DeveloperKits
12         - FeaturePacks
13         - Guidance
14         - SecurityUpdates
15         - ServicePacks
16         - Tools
17         - UpdateRollups
18         - Updates
19         reboot: no
20         state: searched
21       register: win_updates
22     - name: print variable
23       debug:
24         msg: '{{ win_updates }}'
  1. Präambel.
  2. Auf diese Hostgruppe wird werden die nachfolgenden Tasks angewendet. Es ist möglich, einen Host, eine Gruppe, mehrere Hosts, mehrere Gruppen oder ein Gemisch anzugeben.
  3. Diese Zeile zeigt an, dass nun die einzelnen Tasks der Hosts innerhalb dieses Playbooks folgen.
  4. Name des Tasks. Das Minus oder der Bindestrich zeigt, dass es sich um eine geordnete Liste mehrerer Objekte, in diesem Fall Tasks, handelt.
  5. Das in diesem Task verwendete Ansible-Modul, hier “win_updates”.
  6. Parameter “category_names” des Modules.
  7. bis 18. Wird befüllt mit der Liste [u’Application’,u’Connectors’,u’CriticalUpdates’,u’DefinitionUpdates’,u’DeveloperKits’,u’FeaturePacks’,u’Guidance’,u’SecurityUpdates’,u’ServicePacks’,u’Tools’,u’UpdateRollups’,u’Updates’]. Der Einfachheit halber nehmen wir für den Moment einfach alle Update-Kategorien. Dies werden wir in einem späteren Kapitel anpassen.
  8. Wir setzen den Parameter “reboot” des Moduls aus “no”, der Server soll nicht automatisch neu starten.
  9. Wir setzen den Parameter “status” des Moduls aus “searched”, der Server soll nur nach Updates suchen.
  10. Mit dieser Zeile sorgen wir dafür, dass die Ausgabe des Moduls in die Variable “win_updates” registriert. Im zweiten Task möchten wir den Inhalt dieser Variable ausgeben. Beachte bitte, dass es sich hier nicht um ein Parameter des Moduls handelt, sondern um eine Option des Tasks, daher ist das Schlüsselwort auf der Höhe der Taskdefinition eingerückt.
  11. Eine neue Taskbeschreibung beginnt. Wir setzen den Namen auf “print variable”
  12. Für diesen Task benutzen wir das Modul “debug” …
  13. … und setzen den Parameter “msg” auf “‘{{ win_updates }}'”. Du siehst, dass Du die Variabel mit {{ }} umschliessen musst, und den ganzen Ausdruck in Hochkommata oder Anführungszeichen setzen musst.

Der Einrückungsstil eines Playbooks entspricht dem von Python. Es soll für den Interpreter als auch für den Menschen gut verständlich sein. Falls Du von einer anderen Programmiersprache kommst, wirst Du damit Mühe haben, glaub mir. Ich arbeite seit bald zwei Jahren mit Ansible und habe immer noch hin- und wieder Mühe damit. 15 Jahre Perl/C/C++/PHP/C-Gartenzaun gewinnen gegen 2 Jahre Ansible :-).

Weitere Informationen zum Playbook findest Du in der offiziellen Dokumentation. Sie ist ziemlich gut, schau’ mal rein!

Jetzt ist es an der Zeit, das Playbook zu testen:

ansible-playbook -i inventory -u {{ windows_upn }} \
   -k windows-updates-search.yml

Damit sind wir am Ende des 5. Teil. Weiter geht’s demnächst mit dem Patch Deployment.

PS: Falls Du Dich nun fragst, warum hier unterbreche: Ganz einfach – der WSUS in meinem Lab liefert keine Patches aus, ich muss erst dieses Problem lösen 🙂

Leave a Reply

Your email address will not be published.

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