ADMIN

2022

12

2022-11-29T12:00:00

Clientmanagement und Support

SCHWERPUNKT

070

Clientmanagement

Ansible

Clientmanagement mit Ansible

Nach Hause telefonieren

von Andreas Stolzenberger

Veröffentlicht in Ausgabe 12/2022 - SCHWERPUNKT

Ansible steuert Server und Netzwerkgeräte, rollt Maschinen in die Cloud aus oder konfiguriert Software-Setups. Zudem lässt es sich mithilfe von Callbacks auch im Clientmanagement geschickt einsetzen. Anwender können damit etwa vorgegebene Konfigurationen auf dem eigenen System durchführen, ohne Admin-Rechte zu benötigen. Wir zeigen, wie das funktioniert und welche Voraussetzungen Sie zunächst schaffen müssen.

Wer schon mit Ansible gearbeitet hat weiß, dass das Automatisierungstool ohne Client auskommt. Es pusht die Automation-Playbooks und -Templates vom Automation-Server zum jeweiligen Zielsystem. Damit scheint Ansible eigentlich für das Clientmanagement ungeeignet, denn anders als Server oder Infrastrukturgeräte wie Switches und Router sind Clients nicht rund um die Uhr in Betrieb. Um Aufgaben hier zu automatisieren, bedarf es einer Pull-Funktion, über die sich der Client beim Management melden kann.
Wenn der Client anruft
Eine häufig unterschätzte Funktion von AWX ist das "Provisioning Callback". Dies erlaubt, dass der "Anruf" eines Clients via Rest-API am AWX-Server den Start eines Templates auslöst. Dabei ändern sich die Laufparameter dieses Templates nicht. Lediglich die eigentliche Ausführung beschränkt sich auf das Zielsystem, das den Callback auslöst.
Diese Funktion beschreibt am besten ein praktisches Beispiel: Sie erstellen ein Ansible-Playbook, das eine bestimmte Software auf ihren Zielsystemen installiert, und erzeugen auf AWX damit ein Automation-Template. Als Inventory – die Liste aller Systeme, die Ansible mit der Automation anspricht – nutzen Sie dabei alle Clients im LAN. In AWX hinterlegen Sie Credentials, die ihrem AWX-Server dabei Root/Admin-Rechte auf den Zielsystemen für die Automatisierung gewähren.
Wer schon mit Ansible gearbeitet hat weiß, dass das Automatisierungstool ohne Client auskommt. Es pusht die Automation-Playbooks und -Templates vom Automation-Server zum jeweiligen Zielsystem. Damit scheint Ansible eigentlich für das Clientmanagement ungeeignet, denn anders als Server oder Infrastrukturgeräte wie Switches und Router sind Clients nicht rund um die Uhr in Betrieb. Um Aufgaben hier zu automatisieren, bedarf es einer Pull-Funktion, über die sich der Client beim Management melden kann.
Wenn der Client anruft
Eine häufig unterschätzte Funktion von AWX ist das "Provisioning Callback". Dies erlaubt, dass der "Anruf" eines Clients via Rest-API am AWX-Server den Start eines Templates auslöst. Dabei ändern sich die Laufparameter dieses Templates nicht. Lediglich die eigentliche Ausführung beschränkt sich auf das Zielsystem, das den Callback auslöst.
Diese Funktion beschreibt am besten ein praktisches Beispiel: Sie erstellen ein Ansible-Playbook, das eine bestimmte Software auf ihren Zielsystemen installiert, und erzeugen auf AWX damit ein Automation-Template. Als Inventory – die Liste aller Systeme, die Ansible mit der Automation anspricht – nutzen Sie dabei alle Clients im LAN. In AWX hinterlegen Sie Credentials, die ihrem AWX-Server dabei Root/Admin-Rechte auf den Zielsystemen für die Automatisierung gewähren.
Würden Sie das Template direkt in AWX ausführen, installierte es die definierte Software auf allen Clients. Hier kommt nun der Trick mit dem Callback ins Spiel: Weisen Sie dem Template ein Provisioning Callback zu, gibt Ihnen AWX eine URL zurück, die das Template von außerhalb starten lässt. Den Zugang zum Callback schützt ein Passwort. Ruft nun ein Client die Callback-URL mit dem korrekten Passwort auf, startet AWX das Automation-Template und nutzt dabei die Option "limit", die die Ausführung des Playbooks auf das eine anrufende System beschränkt. Natürlich muss dieses System Teil des Inventorys sein.
Die Ausführung des Templates erfolgt auf dem Zielsystem mit Root-Rechten – den Aufruf der Callback-URL kann hingegen jeder gewöhnliche Benutzer starten. Zudem lässt sich der Aufruf sehr einfach als statisches HTML in Webseiten einbetten. So können Sie beispielsweise einen Softwarekatalog als statische Webseite oder als Teil eines internen Wiki erstellen. Damit dürften Clientnutzer ohne Root-Rechte über simple Klicks auf Weblinks Softwareinstallationen, Updates oder ähnliche Wartungsarbeiten auf ihrem System auslösen.
Bild 1: Schaltet der Admin im AWX-Template die Option "Provisioning Callbacks" ein, kann der Client selbst den Start eines Playbooks auslösen.
Nötige Vorbereitungen mit AWX
Die Vorbereitung eines solchen Setups nimmt etwas Zeit in Anspruch, vorausgesetzt, Sie haben noch keinen AWX-Dienst im LAN. Der AWX-Server, die Open-Source-Variante des "Ansible Controllers" (früher: Ansible Tower), benötigt eine Kubernetes-Umgebung. Im Workshop verwenden wir einmal mehr Micro­Shift, das wir bereits an anderer Stelle vorgestellt haben [1].
Richten Sie sich eine virtuelle Maschine mit zwei vCPUs und 8 GByte RAM ein. Als Betriebssysteme verwenden Sie bevorzugt CentOS 8 Streams, Fedora Linux 35 oder einen EL8-Klon. Installieren Sie MicroShift wie auf [2] beschrieben. Im Workshop bezeichnen wir das System als "micro.test.ip" und gehen davon aus, dass es auf der IP-Adresse "192.168.2.100" läuft. Sie müssen diese Werte entsprechend Ihrer Umgebung anpassen. Stellen Sie sicher, dass ihr lokaler DNS-Server alle Wildcards von "*.micro.test.ip" auf "192.168.2.100" auflöst. Damit kann der Reverse-Proxy der MicroShift-Installation den IP-Traffic passend routen. Bei einem dnsmasq-Server sieht der Eintrag wie folgt aus:
address=/.micro.test.ip/192.168.2.100
Sobald Ihr MicroShift-Server arbeitet, richten Sie den "awx-operator" [3] in einem passenden Kubernetes-Namespace wie "awx" mit Hilfe des Tools "kustomize" ein. Der AWX-Operator legt eine Custom-Ressource-Definition "awx" in Kubernetes an. Darüber können Sie nun eine oder mehrere AWX-Instanzen bequem starten. Eine passende Datei namens "awx1.yml" sieht so aus:
---
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
     name: awx1
spec:
     service_type: nodeport
     nodeport_port: 3000
Den Rollout starten Sie wie üblich mit
oc create -f awx1.yml -n awx
oder, falls Sie nicht das OC-Tool verwenden, mit
kubectl apply -f awx1.yml -n awx
Der AWX-Operator startet dann einen AWX-Server bestehend aus zwei Pods mit insgesamt fünf Containern. Ein Pod beherbergt die PostgreSQL-Datenbank, der andere Pod die vier Container "task", "web", "redis" und "ee". Über den AWX-Operator verwalten Sie übrigens auch alle Updates. Gibt es eine neue Version von AWX und dem Operator, müssen Sie lediglich in der "Deployment"-Konfiguration des Operators die Versionsnummer des Images ändern, beispielsweise von
- name: awx-manager
      image: quay.io/ansible/awx-operator:0.28.0
 auf diesen Inhalt:
- name: awx-manager
      image: quay.io/ansible/awx-operator:0.29.0
Der Operator wird sich dann zuerst selbst und im Anschluss alle laufenden AWX-Setups automatisch und ohne Datenverlust auf die neue Version updaten.
Um sich an Ihrem AWX-Server anmelden zu können, benötigen Sie das Passwort, das der Operator zufällig erzeugt und in einem Secret ablegt. Wenn Ihr AWX-Server im Namespace "awx" arbeitet und Sie ihm den Namen "awx1" gegeben haben, erhalten Sie das initiale Admin-Passwort wie folgt:
oc get secret awx1-admin-password -n awx \
      -o json | jq '.data.password' | xargs \
      | base64 --decode
Jetzt können Sie sich an Ihrem AWX-Server auf "http://micro.test.ip:3000" anmelden. Wenn Sie MicroShift verwenden und den zuvor erwähnten Wildcard-DNS-Eintrag in ihrem DNS-Server vorgenommen haben, richten Sie wie im Listing 1 alternativ eine Kubernetes-Route ein. Mit dieser erreichen Sie den AWX-Server dann auch über die URL "http://awx1.micro.test.ip".
Listing 1: Kubernetes-Route
awx1-route.awx apiVersion: route.openshift.io/v1 kind: Route metadata:       name: awx1-route       namespace: awx spec:       host: awx1.micro.test.ip       port:          targetPort: http       to:          kind: Service          name: awx1-service          weight: 100
Jetzt folgen die üblichen Vorbereitungen für Ihren AWX-Server. Sie benötigen ein Git-Repository für Ihre Playbooks, die passenden Access-Credentials dazu sowie eine Container-Registry nebst Credentials. In der Registry sichern Sie später das angepasste Container-Template für Ihr Execution-Environment. Eine detaillierte Beschreibung hierzu finden Sie im IT-Administrator-Artikel [4].
Windows-Clients verwalten
Die meisten Clients arbeiten mit Windows als Betriebssystem. Daher stellt unser Workshop passende Playbooks für dieses Szenario vor. Damit alles überhaupt funktioniert, muss der AWX-Server auf die Windows-Systeme zugreifen können. Im Automatisierungs-Sonderheft von 2021 [5] haben wir ausführlich beschrieben, wie Sie Ansible über Win-RM oder WinPSRP Zugang zu Win-dows-Systemen verschaffen. In einem Netzwerk mit Active Directory funktioniert das relativ simpel mithilfe einer Gruppenrichtlinie. Dort deklarieren Sie den WinRM-Dienst, konfigurieren ihn und legen die passende Firewallregel bei. Sobald Sie diese "WinRM-Policy" ihren Clientcomputern im AD zuweisen, lassen diese sich dann von Ansible aus ansprechen. In diesem Workshop wollen wir zudem einen anderen möglichen Zugang vorstellen, der 2021 noch nicht so richtig funktionierte: OpenSSH.
Das Einrichten des OpenSSH-Zugangs zu Windows ist denkbar simpel und lässt sich mit einem einfachen Ansible-Playbook erledigen, aber natürlich nur dann, wenn Ansible den Windows-Rechner bereits über einen anderen Pfad wie WinRM oder PSRP erreichen kann. Für übersichtliche Umgebungen mit wenigen Clients ohne ADS sieht der Installationspfad so aus: Richten Sie zunächst den Softwaremanager Chocolatey auf ihrem Windows-Client ein. Die Workshop-Beispiele brauchen ohnehin dieses Tool. Wie auf der Homepage noch ausführlicher beschrieben [6], tippen Sie die folgende Zeile in einer PowerShell-Sitzung mit Admin-Rechten ein, um Chocolatey aufzusetzen:
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).Download-String('https://community.chocolatey.org/install.ps1'))
Im Anschluss nutzen sie das frisch installierte Chocolatey, um den OpenSSH-Server für Windows einzurichten:
choco install --package-parameters=/SSHServerFeature openssh
Es gibt eine SSH-Server-Implementierung von Microsoft selbst, doch die hatte in der Vergangenheit Probleme im Zusammenspiel mit Ansible. Wenn Sie sich jetzt von einem andern System per
ssh <User>@<Windows-System>
einloggen, landen Sie auf einer CMD-Shell ihres Windows-Clients. Für Ansible sollte der SSH-Server jedoch die PowerShell öffnen. Daher ändern Sie die Konfiguration des OpenSSH-Servers im Registry-Editor. Erzeugen Sie im Pfad "HKLM:\ SOFTWARE\OpenSSH" den Schlüssel "DefaultShell" mit dem Wert (String) "C:\Windows\System32\WindowsPowerShell\v1.\ powershell.exe". Wenn Sie sich jetzt per SSH am Windows-System anmelden, landen Sie direkt in der PowerShell.
Bild 2: Aus einem PowerShell-Skript heraus oder über den Link auf einer Webseite startet der Client den Callback.
Ansible via Callback
In AWX schaffen Sie ein neues Projekt "Windows" mit dem dazu erstellten Git-Repository. In dieses kommen im weiteren Verlauf die YML-Dateien für Playbooks und Inventories. Für unseren Workshop-Aufbau erstellen Sie zunächst ein simples statisches Inventory "hosts. yml", das erst einmal nur einen Client enthält. In unserem Beispiel läuft dieser mit der IP-Adresse "192.168.2.213". Später lässt sich die Installation natürlich beliebig ausbauen.
all:
      vars:
       ansible_user: ansible
        ansible_connetion: ssh
        ansible_shell_type: powershell
     hosts:
        192.168.2.213:
In AWX bauen Sie dazu das Inventory "Windows-Clients" und legen in dessen Tab "Source" die Datei "hosts.yml" als Typ "Sourced from Project" an. In den Credentials erzeugen Sie dazu passend ein "Machine"-Credential mit dem User "ansible" und seinem Windows-Passwort.
Das setzt voraus, dass Sie auf dem System oder im ADS einen Nutzer namens "ansible" haben, der über Admin-Rechte am Windows-System verfügt. Jetzt folgt ein simples Playbook namens "choco.yml", das Software via Chocolatey installiert oder löscht:
- hosts: all
    gather_facts: false
    tasks:
    - name: Install Choco Pakets chocolatey.chocolatey.win_chocolatey:
                   name: "{{ choco_packet }}"
                   state: "{{ packet_state
    }}"
Das benötigte Modul "win_chocolatey" befindet sich neuerdings in einer eigenen Collection namens "chocolatey.chocolatey". Um dies aus AWX heraus nutzen zu können, müssen Sie diese Collection entweder zur Laufzeit über die Datei "collections/requirements.yml" in den Ansible-Container integrieren, der später die eigentliche Ausführung übernimmt – das Execution-Environment. Wenn Sie aber häufiger mit Windows-Clients arbeiten, bietet es sich ohnehin an, ein eigenes Execution-Environment zu erstellen, das die erforderlichen Collections von Haus aus integriert (siehe Kasten). Passend dazu legen Sie danach im AWX-Server die Credentials für den Zugriff auf die Registry sowie das Execution-Environment mit der URL zum Container Image an.
Execution-Environment für Windows
Damit die Ausführung Ihrer Windows-Automatisierung aus AWX heraus flotter läuft, empfiehlt es sich, mit Hilfe des Ansible Builders ein eigenes Execution-Environment zu bauen, dass alle nötigen Collections enthält. Richten Sie auf einem Fedora-System (35 oder 36) sowohl Podman als auch "ansbile-builder" (Letzteres via pip) ein. Legen Sie in einem leeren Verzeichnis die Datei "requirements.yml" mit folgendem Inhalt an:---collections:- community.general- ansible.posix- - ansible.windows- chocolatey.chocolateyFalls nötig, fügen Sie weitere Collections der Liste hinzu. In dasselbe Verzeichnis kommt dann auch die Datei "execution-environment.yml mit folgenden Zeilen:---version: 1build_arg_defaults:      EE_BASE_IMAGE: 'quay.io/ansible/awx-ee: latest'dependencies:      galaxy: requirements.ymladditional_build_steps:     prepend: |          RUN pip3 install --upgrade pip setup toolsDann lassen Sie den Builder Ihr Container-Image bauen:ansible-builder build --tag ee_win --container-runtime podmanDas fertige Image legen Sie dann auf einer Container-Registry ihrer Wahl ab:Podman login <Registry-URL>Podman push ee_win <Registry-URL>/<Projekt>/ee_win:<Tag>
Automation-Template anlegen
Mit dem Playbook, dem Inventory und dem Execution-Environment legen Sie nun noch das Automation-Template in AWX an. Im Beispiel soll ein Template das Open-Source-Bildbearbeitungsprogramm Gimp auf dem Zielsystem einrichten. Das Template heißt folglich "Install_gimp", verweist auf das "choco. yml"-Playbook und bekommt dazu die Variablen:
---
choco_packet: "gimp"
packet_state: present
Das Praktische hierbei ist, dass Sie das Playbook in vielen verschiedenen Templates nutzen können. Die Variablendeklaration gibt an, um welche Pakete es geht und ob diese zu installieren oder zu löschen sind. Beispielsweise entfernt
---
choco_packet:
      - "Shotcut"
      - "gimp"
 
packet_state: absent
die Programme "gimp" und "Shotcut" vom Zielsystem. Als Administrator könnten Sie das Template theoretisch in AWX starten und somit Gimp auf allen Win­dows-Systemen im Inventory aufspielen. Die Idee war jedoch, dass der Client die Automatisierung selbst auslöst. Damit dies richtig funktioniert, gilt es noch zwei Kleinigkeiten am AWX-Server zu konfigurieren.
Um eine Callback-URL zu erstellen, muss der AWX-Server erst einmal seinen eigenen Namen kennen. Gehen Sie in der AWX-UI in den Tab "Settings" und dort auf "Miscellaneous System settings". Geben Sie unter "Base URL of the service" die URL des AWX-Dienstes ein. Je nachdem, ob Sie eine Route verwenden oder nicht, ist das in diesem Fall entweder "http://micro.test.ip:3000" oder "http:// awx1.micro.test.ip". Aus dem Web-Callback ermittelt der AWX-Server zudem die IP-Adresse des "rufenden" Systems.
Da AWX auf Kubernetes läuft, befindet sich in der Regel ein Reverse-Proxy zwischen dem eigentlichen AWX-Web-Container und dem Callback-Client. Im noch offenen Dialog der "Miscellaneous System settings" finden Sie weiter unten ein Feld mit dem Namen "Remote Host Headers". Das gibt an, wie die Callback-Funktion die IP-Adresse des Zielsystems aus dem HTTP-Request heraus filtert. Der Default-Eintrag funktioniert nicht mit einem zwischengeschalteten Proxy, sodass Callbacks immer mit der Fehlermeldung abbrechen "No matching host could be found!". Erweitern Sie das Array um den Eintrag "HTTP_X_FORWARDED_ FOR", damit es dann wie folgt aussieht:
[
      "HTTP_X_FORWARDED_FOR",
      "REMOTE_ADDR",
      "REMOTE_HOST"
]
Jetzt erkennt AWX die Ziel-IP auch mit dem Kubernetes-Proxy-Service. Zurück in den Einstellungen des Templates "Install_gimp" schalten Sie nun die Checkbox "Provisioning Callbacks" ein. AWX erzeugt nun eine URL wie beispielsweise: "http:// awx1.micro.test.ip/api/v2/job_templates/22/callback". Dazu müssen Sie einen so genannten "Host Config Key" angeben, also ein Passwort für den Zugang zum Callback. Im Beispiel nennen wir ihn "Give- MeGimp". Jetzt kann ein Client aus dem Inventory sich bei AWX melden und das Template starten. Aus einer PowerShell-Sitzung heraus sieht ein Clientaufruf in etwa so aus wie im Listing 2. Um die Automatisierung via Click im Browser zu starten, müssen Sie noch einen simplen HTML-Code nach dem folgenden Beispiel in die Webseite einbauen:
<form id="form" method="post" action="http://awx.kube.test.ip/api/v2/job_templates/22/callback/">
<input type="hidden" name="host_config_key" value="GiveMeGimp" /><a onclick="document.getElementById('form').submit(); return false;">
Install Gimp</a> </form>
Listing 2: Clientaufruf bei AWX
$data = @{       host_config_key = 'GiveMeGimp' } $invoke_params = @{       ContentType = 'application/json'       Method = 'POST'       Body = (ConvertTo-Json $data)       Uri = "http://awx.kube.test.ip/api/v2/job_templates/22/callback/"       UseBasicParsing = $true       ErrorAction = 'Stop' }
Neben der hier gezeigten Funktion können Sie natürlich das ganze Spektrum von Ansible für Windows mit Callbacks einsetzen. So könnten Clients auch Systemupdates via Playbook anfordern:
- name: Install all critical and security updates
     win_updates:
          category_names:
              - CriticalUpdates
              - SecurityUpdates
           state: installed
Gerade bei mobilen Clients erleichtern Callbacks das Management. Startet ein Mitarbeiter sein Notebook, kann ein lokales automatisch getriggertes PS1-Skript erst einmal ermitteln, ob der Rechner im sicheren LAN des Unternehmens läuft und im Anschluss daran beim AWX-Dienst die neusten Security-Updates und Fixes anfordern.
Fazit
Auf den ersten Blick sieht der Aufwand für Provisioning Callbacks relativ groß aus. Das liegt in erster Linie daran, dass dieser Artikel die komplette Basisinstallation für AWX samt Anpassung für Windows beschreibt. Steht die Grundlage mit dem AWX-Dienst auf Kubernetes erst einmal, fällt es leicht, weitere Automation-Templates zu erstellen und mit Callbacks zu versehen. Damit können Anwender simple Verwaltungsaufgaben über einen Webkatalog selbst anstoßen. Der Workshop listet Beispiele für simple Windows-Aufgaben auf – natürlich greift das Konzept auch für Linux- und Mac-Clients.
(ln)
Link-Codes
[1] "Datenbanken containerisieren" in IT-Administrator 09/2022: https://www.it-administrator.de/magazin/heftarchiv/artikel/378688.html
[2] Erste Schritte mit MicroShift: https://microshift.io/docs/getting-started/
[4] "Automatisierung mit Ansible ab 2.10" in IT-Administrator 04/2022: https://www.it-administrator.de/magazin/heftarchiv/artikel/371945.html
[6] Installation von Chocolatey: https://chocolatey.org/install#individual