Kontakt: +49 511 59095 – 942

Chef Interactive

Thumbnail

Es ist vermutlich bekannt, dass Chef ein Tool für die automatische Provisionierung und Konfiguration von Systemen ist. Sobald man also ein Problem hat, dass diese beiden Bereiche verlässt, werden Internetposts und Supportanfragen jeder Art wahrscheinlich in eine von zwei Antworten münden: „Das ist nicht möglich“ oder „So macht man das aber nicht“.

Aber – was wenn man einen echten, exotischen Anwendungsfall hat. Und das möglicherweise nur als Übergangslösung?

Use Cases

Für den Inhalt dieses Posts sind uns bisher zwei Use Cases untergekommen: Die Modernisierung eines Provisionierungsworkflows oder der Einsatz von Tools, die nur interaktiv installiert werden können.

Beispiel hier wäre eine Firma, in der IT Systeme als Teil einer größeren Lösung vorinstalliert werden. Diese Systeme sind also nur ein kleiner Teil des Produktes und wahrscheinlich sogar einer, der als nicht-zentral für das Endresultat gesehen wird. Insbesondere dann, wenn dieser Workflow ausgelagert ist zu einem Dienstleister, müssen einige Bedingungen beachtet werden bis fortgeschrittene Lösungen ausgerollt werden können. Natürlich würde ein „Big Bang“ besser sein und direkt alles auf die neuen Tools optimieren. Aber wie oft hat dieser Ansatz in der Vergangenheit wirklich funktioniert?

In unserem nicht-ganz-so-hypothetischen Fall werden wir uns einen Workflow vorstellen, in dem Mitarbeiter daran gewohnt sind, eine frische Windowsinstanz zu starten und dann diverse Aufgaben zur Einrichtung durchzuführen. Viele dieser Aufgaben können wir schon mit Chef-basierten Lösungen ersetzen. Aber wie handhaben wir, wenn Server mit der falschen Anzahl von Festplatten geliefert werden? Oder wenn wir Konfigurationsabweichungen haben, die nur manuell gelöst werden können? Normalerweise sollten diese Fälle in der Fertigung nicht auftreten – jeder, der die Lean Bewegung verfolgt hat, kennt vermutlich das Jidoka-Prinzip. Aber gehen wir davon aus, dass wir dieses Thema nicht beeinflussen können und einen Umweg brauchen.

Einige dieser Punkte klingen vielleicht bekannt. Setups die aus unverständlichen Gründen keine automatisierte Installation beherrschen. Keine Parameter für den Installer – oder schlimmer, ein Popupfenster in das Aktivierungsschlüssel eingegeben werden müssen. Eine pragmatische Lösung ist es, Tools wie AutoIt oder AutoHotkey zu nutzen um auf diese Events zu warten und dann Tastatureingaben/Mausklicks zu simulieren.

Das Kernproblem ist dann, dass Chef als Hintergrundprozess arbeitet und keinen UI-Zugriff hat. Nicht einmal eine simulierte UI – damit kommt auch AutoIt nicht klar.

Schritt 1: Interaktiv werden

Zwei Ansätze sind hier möglich: der eine mit einem Tool aus der Sysinternals Suite von Microsoft mit Namen „psexec“ und einer, der rein mit Windows-Bordmitteln funktioniert. Beides erfordert eine interaktive Windows-Session, also ist dies unsere erste Aufgabe.

Windowssysteme haben die Möglichkeit, einen Benutzer automatisch beim Systemstart anzumelden. Ganz offensichtlich ist dies sicherheitstechnisch bedenklich, in unserem Use Case sind wir aber in einem einmaligen Workflow – wir können diese temporäre Sicherheitslücke also später wieder entfernen.

Aktuell besitzt Chef keine Ressource, um Autologin zu aktivieren oder deaktivieren. Aber wir können uns eine simple Custom Resource schreiben die mit der registry_key resource die passenden Werte setzt:

resource_name :autologin
 
property :user, String, name_property: true
property :password, String
 
default_action :enable
 
action :enable do
  registry_key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' do
    values [
      { name: 'DefaultUserName', type: :string, data: new_resource.user },
      { name: 'DefaultPassword', type: :string, data: new_resource.password },
      { name: 'AutoAdminLogon', type: :dword, data: 1 },
    ]
    sensitive true
    action :create
    notifies :reboot_now, 'reboot[now]', :immediate
  end
 
  reboot 'now' do
    action :nothing
  end
end
 
action :disable do
  registry_key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' do
    values [
      { name: 'DefaultUserName', type: :string, data: '' },
      { name: 'DefaultPassword', type: :string, data: '' },
      { name: 'AutoAdminLogon', type: :dword, data: 0 },
    ]
    action :create
  end
end

Wie man sieht, enthält diese Lösung einen bedingten Reboot und wir brauchen tatsächlich einen Neustart zu diesem Zeitpunkt. Darüber hinaus: Benutzer und Passwort stehen im Klartext in der Registry! Leider gibt es aber keinen alternativen Weg, ich bin für Kommentare natürlich dankbar.

Bei der Verwendung dieser Ressource müssen zwei Punkte bedacht werden:

  • autologin muss nach dem Abschluss wieder deaktiviert werden (hier ist allerdings kein Reboot notwendig)
  • dieser Task wird bei jeder Aktivierung einen Neustart bewirken, wir brauchen also einen Guard um die Schritte nur einmal zu starten (z.B. ein Registry Key ob das Programm schon installiert ist)

Schritt 2: Arbeitsplanung

Wie können wir jetzt eine Ressource ausführen, nachdem der Server gestartet ist? Einen Hinweis gibt der Titel – wir werden nämlich den Windows Task Scheduler nutzen, der eine Konfiguration bietet die uns hilft:

  • den Zeitpunkt des Tasks als „on logon” definieren
  • die Eigenschaft „Start when a user is logged on” (dafür brauchten wir die Autologin Ressource)
  • Nutzer/Passwort für den Task

Da der Task in der gleichen Session starten soll, die per Autologin eingeloggt wurde, können wir uns die Zugangsdaten direkt aus der Registry besorgen. Keine Duplikation und sogar ein Vorteil von der Speicherung in Klartext. Die Chef windows_task resource macht die Einrichtung einfach.

resource_name :execute_interactive
 
property :command, String, name_property: true
 
default_action :enable
 
action :enable do
  require 'securerandom'

  # Extract from autologin settings
  autologin = registry_get_values('HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon')
  user_auto = autologin.select { |data| data[:name] == 'DefaultUserName' }.first[:data]
  password_auto = autologin.select { |data| data[:name] == 'DefaultPassword' }.first[:data]
  taskname = format('execute-interactive-%s', SecureRandom.hex(4))
 
  windows_task 'Create task ' + taskname do
    action [:create, :run]
    task_name taskname
    command new_resource.command
 
    interactive_enabled true
    user user_auto
    password password_auto
    sensitive true
 
    run_level :highest
    frequency :once
    start_time Time.now.strftime('%H:%M')
  end
 
  powershell_script 'Wait for completion of ' + taskname do
    action :run
    code <<~PS1
      Do {
        Start-Sleep -Seconds 1
      } while ((Get-ScheduledTaskInfo -TaskName #{taskname}).LastTaskResult -ge 0x41301)
    PS1
  end
 
  windows_task 'Remove task ' + taskname do
    task_name taskname
    action :delete
  end
end

Diese Lösung ist natürlich ein absolutes Minimum und eine produktive Implementation hat noch ein paar Zusatzpunkte. Aber es funktioniert! Für alle fortgeschrittenen Chef User sei dazugesagt, dass diese Lösung immer konvergierte Ressourcen produziert – falls darauf also in einer Pipeline getestet wird, um „idempotenten“ Code zu erzwingen, sollte das berücksichtigt werden.

Falls AutoIt/AutoHotkey genutzt wird, empfehle ich eine Custom Ressource in Chef die nur den Code des Scripts annimmt. Damit enthält das Chef-Recipe alle Punkte der Infrastruktur und die Lösung ist nicht auf mehrere Dateien verteilt. Für einen fortgeschrittenen Chef-Practitioner sollte das kein Problem sein.

Alternative: PSExec

Der zweite Weg funktioniert mit der Sysinternals Suite von Microsoft, die ein Tool zur Taskausführung enthält. PSExec hat Parameter für interaktiven Start und auch die Nutzung des System Accounts. Falls also aus diversen Gründen die Windows Task-Lösung nicht gewünscht ist und die Nutzung externer Ressourcen akzeptabel ist, geht auch diese Variante. Auch hier wird allerdings die Autologin Ressource notwendig, nur die execute_interactive Custom Resource muss anders geschrieben werden.

Zusammenfassung

Auch wenn diverse Leute (meist zu recht) davon abraten, Programme mit Chef interaktiv zu starten – es ist möglich. Die Anwendung dieser Ideen sollte aber immer ein letztes Mittel oder eine Übergangslösung sein. In unserem Beispiel der Fertigung wäre es ohnehin besser, wenn immer gleiche Server geliefert würden oder unterliegende Schritte angepasst werden. Die Virtualisierung von Servern zusammen mit automatischem Deployment von VMware ESX wäre hier wesentlich besser.

Übersetzungen


Author Image
Thomas Heinen

Thomas is a Cloud Consultant and Trainer at tecRacer Consulting with a focus on Chef, AWS, DevOps and Security.

Teilen