Sicheres WinRM für Ansible mit Zertifikaten in 10 Schritten

Ansible wird immer mehr zu einem der wichtigsten, wenn nicht sogar dem wichtigsten Konfigurationsverwaltungstools von heute. Ansible ist ein praktisches (und in den meisten Fällen kostenloses) Tool, mit dem DevOps-Ingenieure und Systemingenieure/Administratoren die Infrastruktur in allen Umgebungen auf eine idempotente Infrastruktur-als-Code-Weise aufbauen und verwalten können. Allerdings kann die Konfiguration von Ansible zur Kommunikation mit Windows über WinRM eine Herausforderung sein.

Wie viele andere Infrastrukturkomponenten kann Ansible Konfigurationszustände auf Windows-Hosts bereitstellen und verwalten. Ansible stellt eine Verbindung zu diesen Windows-Hosts über WinRM her, auch wenn sie SSH experimentieren.

Bei der Konfiguration von WinRM für Ansible haben Sie verschiedene Optionen, die von der einfachen Einrichtung bis hin zu Sicherheitsimplikationen reichen. Viele Menschen wählen den einfachen Ansatz: Grundlegende Authentifizierung mit HTTP. Obwohl Sie dabei auf zusätzliche Arbeit mit Zertifikaten verzichten, ist es nie eine gute Idee, unverschlüsselte Daten über ein Netzwerk zu senden, es sei denn, es ist unbedingt erforderlich.

In diesem Artikel erfahren Sie, wie Sie WinRm für Ansible mithilfe der Zertifikat-basierten Authentifizierung einrichten können. Dabei werden selbstsignierte Zertifikate verwendet, damit Ansible mit ihnen kommunizieren kann.

Die in diesem Tutorial vermittelte Einrichtung gilt nicht nur für Ansible als Client. Diese zertifikatbasierte Authentifizierung kann ebenso auf andere WinRm-Clients wie andere Windows-Hosts angewendet werden.

Voraussetzungen

Dieser Artikel ist ein Tutorial-Walkthrough. Wenn Sie beabsichtigen, den hier vorgestellten Schritten zu folgen, um WinRm für Ansible zu konfigurieren, wird davon ausgegangen, dass:

  • Sie Ansible bereits auf einem Linux-Host installiert haben.
  • Sie ein Ansible-Inventar basierend auf Ihren Windows-Hosts eingerichtet haben.
  • Sie einen Windows Server 2016 oder neuer verwalten möchten. Einige Cmdlets, die in diesem Tutorial verwendet werden, funktionieren nicht mit älteren Windows-Versionen.
  • Der Windows-Host befindet sich nicht in einer Domäne. Obwohl die Beispiele auf einem nicht in eine Domäne eingebundenen Host durchgeführt wurden, sollte diese Konfiguration trotzdem auch auf in eine Domäne eingebundenen Hosts funktionieren.
  • Sie haben RDP- oder Konsolenzugriff auf den Windows-Host und sind als lokaler Administrator angemeldet.
  • Sie sind mit PowerShell vertraut. Fast alle Beispiele verwenden PowerShell-Code, um Änderungen am Windows-Host vorzunehmen.

Jeder Abschnitt verwendet einen Code-Schnipsel, der vom vorherigen abhängt. Einige Schnipsel beziehen sich auf zuvor definierte Variablen. Stellen Sie sicher, dass Sie Ihre Konsole geöffnet lassen, während Sie diesen Code kopieren/einfügen, wenn Sie genau danach vorgehen möchten.

Wenn Sie nur den Code ohne die ganze Erklärung möchten, können Sie gerne diesen GitHub-Gist herunterladen.

Aktivieren Sie PowerShell Remoting für WinRm für Ansible

Auch wenn alle Windows Server 2016 oder neuer PowerShell Remoting aktiviert haben, ist es immer eine gute Idee, dies zu bestätigen.

Öffnen Sie auf dem zu verwaltenden Windows-Host eine PowerShell-Konsole als Administrator und führen Sie den folgenden Code-Schnipsel aus. Dieser Code-Schnipsel stellt sicher, dass der WinRm-Dienst gestartet wird und beim Systemstart automatisch gestartet wird.

Set-Service -Name "WinRM" -StartupType Automatic
Start-Service -Name "WinRM"

Stellen Sie als nächstes sicher, dass PowerShell-Remoting aktiviert ist, indem Sie zunächst überprüfen, ob es aktive Sitzungskonfigurationen gibt. Wenn nicht, stellen Sie sicher, dass keine Listener verfügbar sind. WinRm für Ansible muss mindestens einen Listener haben. Wenn eine dieser Bedingungen nichts zurückgibt, führen Sie Enable-PSRemoting aus.

if (-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:\localhost\Listener))) {
    ## Verwenden Sie SkipNetworkProfileCheck, um es auch in Windows Firewall öffentlichen Profilen verfügbar zu machen
    ## Verwenden Sie Force, um nicht gefragt zu werden, ob wir sicher sind oder nicht.
    Enable-PSRemoting -SkipNetworkProfileCheck -Force
}
Configuring WinRM for Ansible (a listener) via the winrm command

Aktivieren Sie die zertifikatbasierte Authentifizierung

Standardmäßig ist WinRM nicht für die Authentifizierung mit Zertifikaten konfiguriert. Sie müssen dies aktivieren, indem Sie WSMan wie unten gezeigt konfigurieren.

#region Aktiviere zertifikatsbasierte Authentifizierung
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
#endregion

Erstellen Sie ein lokales Benutzerkonto

Um WinRM für die Zertifikat-basierte Authentifizierung mit Ansible zu verwenden, müssen Sie ein lokales Benutzerkonto einem Zertifikat „zuordnen“. Sie könnten das lokale Administrator-Konto dafür verwenden, aber es ist immer eine gute Idee, ein spezifisches Konto zu erstellen, um die Verwaltung zu vereinfachen.

Der folgende Codeausschnitt erstellt ein lokales Benutzerkonto für WinRM für Ansible mit dem Namen ansibletestuser und einem Passwort von p@$$w0rd12, falls es nicht vorhanden ist. Um sicherzustellen, dass es immer aktiv bleibt, läuft das Passwort dieses Kontos nie ab.

$testUserAccountName = 'ansibletestuser'
$testUserAccountPassword = (ConvertTo-SecureString -String 'p@$$w0rd12' -AsPlainText -Force)
if (-not (Get-LocalUser -Name $testUserAccountName -ErrorAction Ignore)) {
    $newUserParams = @{
        Name                 = $testUserAccountName
        AccountNeverExpires  = $true
        PasswordNeverExpires = $true
        Password             = $testUserAccountPassword
    }
    $null = New-LocalUser @newUserParams
}

Erstellen Sie das Client-Zertifikat

WinRM für Ansible (sicher) benötigt zwei Zertifikate: ein Client-Zertifikat und ein Server-Zertifikat.

Sie können dasselbe Zertifikat für Client und Server verwenden, aber ich bin auf Probleme mit diesem Ansatz gestoßen. In der Ansible-Dokumentation und vielen anderen Quellen finden Sie Anweisungen zur Generierung des Client-Zertifikats über den PowerShell-Befehl New-SelfSignedCert. Obwohl diese Methode funktionieren kann, konnte ich dies nicht einfach zum Laufen bringen.

Um das Client-Zertifikat für WinRM für Ansible zu erstellen, müssen Sie einen privaten und einen öffentlichen Schlüssel erstellen. Gehen Sie wie folgt vor, um sich mit dem Ansible-Host über SSH zu verbinden und den folgenden openssl-Befehl auszuführen. Dieser Befehl erstellt einen privaten Schlüssel in einer Datei namens cert_key.pem und einen öffentlichen Schlüssel namens cert.pem. Die Schlüsselverwendung wird die Client-Authentifizierung (1.3.6.1.4.1.311.20.2.3) sein, die dem zuvor erstellten lokalen Benutzerkonto mit dem Namen ansibletestuser „zugeordnet“ wird.

## Dies ist der öffentliche Schlüssel, der vom Ansible-Server generiert wurde:
cat > openssl.conf << EOL
distinguished_name = req_distinguished_name
[req_distinguished_name]
[v3_req_client]
extendedKeyUsage = clientAuth
subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:ansibletestuser@localhost
EOL
export OPENSSL_CONF=openssl.conf
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out cert.pem -outform PEM -keyout cert_key.pem -subj "/CN=ansibletestuser" -extensions v3_req_client
rm openssl.conf 

Noch ein Schritt näher zur Ansible WinRM-Authentifizierung!

Importieren des Client-Zertifikats

Nachdem Sie das Client-Zertifikat für WinRM für Ansible erstellt haben, müssen Sie es in zwei Zertifikatsspeichern auf dem Windows-Host importieren, damit WinRM auf Ansible funktioniert. Übertragen Sie dazu zuerst den öffentlichen Schlüssel cert.pem auf den Windows-Host. Das folgende Beispiel geht davon aus, dass der Schlüssel unter C:\cert.pem existiert.

Nachdem Sie das öffentliche Zertifikat auf dem Windows-Host haben, importieren Sie es in die Zertifikatsspeicher Vertrauenswürdige Stammzertifizierungsstellen und Vertrauenswürdige Personen mithilfe von Import-Certificate wie unten gezeigt.

$pubKeyFilePath = 'C:\cert.pem'

## Importieren Sie den öffentlichen Schlüssel in die Zertifizierungsstellen Vertrauenswürdige Stammzertifizierungsstellen und Vertrauenswürdige Personen
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\Root'
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\TrustedPeople'

Erstellen des Serverzertifikats

WinRM für Ansible benötigt ein Zertifikat mit einer Schlüsselverwendung für die Serverauthentifizierung. Dieses Zertifikat wird im Zertifikatsspeicher Lokaler Computer\Mein des Windows-Hosts gespeichert. Erstellen Sie das selbstsignierte Zertifikat mit dem folgenden Code-Schnipsel.

$hostname = hostname
$serverCert = New-SelfSignedCertificate -DnsName $hostName -CertStoreLocation 'Cert:\LocalMachine\My'

Erstellen Sie den Ansible WinRm-Listener

Nachdem Sie beide Zertifikate erstellt haben, müssen Sie nun einen WinRm-Listener auf dem Windows-Host erstellen. Dieser Listener hört auf Port 5986 auf eingehende Verbindungen. Sobald erstellt, akzeptiert dieser Listener eingehende Verbindungen und versucht, Daten mit dem oben erstellten Serverzertifikat zu verschlüsseln.

PowerShell Remoting verwendet diesen WinRM-Listener als Transportmittel, sobald die Authentifizierung stattgefunden hat.

Im unten stehenden Code-Schnipsel sehen Sie ein großartiges Beispiel dafür, wie überprüft wird, ob ein vorhandener HTTPS-Listener vorhanden ist. Wenn kein Listener mit dem oben erstellten Serverzertifikat gefunden wird, wird ein neuer erstellt.

## Finden Sie alle HTTPS-Listener
$httpsListeners = Get-ChildItem -Path WSMan:\localhost\Listener\ | where-object { $_.Keys -match 'Transport=HTTPS' }

## Wenn überhaupt keine Listener definiert sind oder kein Listener zum
## Arbeiten mit dem Serverzertifikat konfiguriert ist, erstellen Sie einen neuen mit einem Subject, das dem Computernamen entspricht
## und mit dem Serverzertifikat verknüpft ist.
if ((-not $httpsListeners) -or -not (@($httpsListeners).where( { $_.CertificateThumbprint -ne $serverCert.Thumbprint }))) {
    $newWsmanParams = @{
        ResourceUri = 'winrm/config/Listener'
        SelectorSet = @{ Transport = "HTTPS"; Address = "*" }
        ValueSet    = @{ Hostname = $hostName; CertificateThumbprint = $serverCert.Thumbprint }
        # UseSSL = $true
    }
    $null = New-WSManInstance @newWsmanParams
}

Ordnen Sie das Clientzertifikat dem lokalen Benutzerkonto zu

Der nächste Schritt besteht darin, sicherzustellen, dass wenn Ansible sich mit dem Windows-Host unter Verwendung des Serverzertifikats verbindet, dann alle Anweisungen als lokaler Benutzer ausgeführt werden. In diesem Fall verwendet WinRm für Ansible das lokale Benutzerkonto ansibletestuser.

$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testUserAccountName, $testUserAccountPassword

## Finden Sie den Zertifikat-Daumenabdruck für das Clientzertifikat, das auf dem Ansible-Host erstellt wurde
$ansibleCert = Get-ChildItem -Path 'Cert:\LocalMachine\Root' | Where-Object {$_.Subject -eq 'CN=ansibletestuser'}

$params = @{
	Path = 'WSMan:\localhost\ClientCertificate'
	Subject = "$testUserAccountName@localhost"
	URI = '*'
	Issuer = $ansibleCert.Thumbprint
  Credential = $credential
	Force = $true
}
New-Item @params

WinRm für Ansible mit Benutzerkontensteuerung (UAC) aktivieren

Wenn Sie ein lokales Konto verwenden, um ein Zertifikat zuzuordnen, müssen Sie auch die LocalAccountTokenFilterPolicy auf 1 setzen, um sicherzustellen, dass die UAC nicht im Weg steht. Die LocalAccountTokenFilterPolicy gilt für alle lokalen Konten (nicht für Domänenkonten) und bewirkt, dass Ihre Netzwerkanmeldung der eingeschränkte Teil Ihres Tokens ist. Dadurch wird verhindert, dass Windows es als Administrator einstuft, da WinRM standardmäßig verlangt, dass der Benutzer ein lokaler Administrator ist.

Durch das Setzen der LocalAccountTokenFilterPolicy teilen Sie Windows mit, dass es für Netzwerkanmeldungen über ein lokales Konto kein eingeschränktes Token erstellen und stattdessen das vollständige Token verwenden soll.

$newItemParams = @{
    Path         = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
    Name         = 'LocalAccountTokenFilterPolicy'
    Value        = 1
    PropertyType = 'DWORD'
    Force        = $true
}
$null = New-ItemProperty @newItemParams

Öffnen Sie Port 5986 in der Windows-Firewall

WinRm über HTTPS verwendet den Port 5986. Wenn die Windows-Firewall aktiviert ist, müssen Sie diesen Port öffnen. Sie können dies tun, indem Sie den folgenden PowerShell-Code ausführen. Dieser Codeausschnitt ist zu lax und ermöglicht allen Computern die Verwendung. Wenn Sie dies weiter einschränken möchten, stellen Sie sicher, dass Sie den Parameter LocalAddress verwenden und die IP-Adresse von Ansible angeben.

#region Stellen Sie sicher, dass WinRM 5986 in der Firewall geöffnet ist
 $ruleDisplayName = 'Windows Remote Management (HTTPS-In)'
 if (-not (Get-NetFirewallRule -DisplayName $ruleDisplayName -ErrorAction Ignore)) {
     $newRuleParams = @{
         DisplayName   = $ruleDisplayName
         Direction     = 'Inbound'
         LocalPort     = 5986
         RemoteAddress = 'Any'
         Protocol      = 'TCP'
         Action        = 'Allow'
         Enabled       = 'True'
         Group         = 'Windows Remote Management'
     }
     $null = New-NetFirewallRule @newRuleParams
 }
 #endregion

Fügen Sie den lokalen Benutzer zur Administratorengruppe hinzu

Sie fragen sich vielleicht, warum dieses Tutorial den lokalen Benutzer nicht früher zur Administratorengruppe hinzugefügt hat. Der Grund dafür ist, dass aus unbekannten Gründen, wenn Sie versuchen, das Client-Zertifikat dem Benutzer zuzuordnen, das Benutzerkonto kein lokaler Administrator sein darf.

Führen Sie den folgenden Code-Schnipsel aus, um das lokale Benutzerkonto ansibletestuser zur Administratorengruppe hinzuzufügen.

## Fügen Sie das lokale Benutzerkonto zur Administratorengruppe hinzu. Wenn dieser Schritt nicht ausgeführt wird, erhält Ansible einen "Zugriff verweigert"-Fehler.
Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group 'Administrators'

Conclusion

Wenn Sie jeden dieser Schritte wie gezeigt befolgt haben, sollten Sie jetzt in der Lage sein, Ansible-Befehle gegen einen Windows-Host auszuführen. Verwenden Sie das Modul win_shell, um Ihre Tests durchzuführen. Wenn dieses Modul erfolgreich ist, haben Sie WinRM für Ansible und die Zertifikat-basierte Authentifizierung erfolgreich konfiguriert!

Source:
https://adamtheautomator.com/winrm-for-ansible/