Beveilig WinRM voor Ansible met Certificaten in 10 Stappen

Ansible wordt steeds meer een van de meest, zo niet de meest gebruikte configuratiebeheertool van vandaag. Ansible is een handige (en in de meeste gevallen gratis) tool waarmee DevOps-engineers en systeemengineers/beheerders infrastructuur kunnen opbouwen en onderhouden in een idempotente, infrastructuur-als-code -benadering. Maar het configureren ervan om met Windows te praten via WinRM voor Ansible kan een uitdaging zijn.

Net als veel andere infrastructuurcomponenten kan Ansible configuratiestatussen implementeren en onderhouden op Windows-hosts. Ansible maakt verbinding met deze Windows-hosts via WinRM, hoewel ze experimenteren met SSH.

Wanneer je WinRM configureert voor Ansible, heb je verschillende opties, variërend van eenvoudige installatie tot beveiligingsimplicaties. Veel mensen kiezen voor de eenvoudige aanpak; basisauthenticatie via HTTP. Hoewel je extra werk met certificaten vermijdt, is het nooit een goed idee om onversleutelde gegevens over een netwerk te verzenden, tenzij dat noodzakelijk is.

In dit artikel ga je leren hoe je WinRm instelt voor Ansible met behulp van certificaat-gebaseerde authenticatie met zelfondertekende certificaten, zodat Ansible met hen kan communiceren.

De configuratie die je leert in deze tutorial is niet beperkt tot Ansible als de client. Deze op certificaten gebaseerde authenticatie kan net zo goed van toepassing zijn op andere WinRm-clients zoals andere Windows hosts.

Aannames

Dit artikel zal een op tutorials gebaseerde walkthrough zijn. Als je van plan bent de hier gepresenteerde stappen te volgen om WinRm voor Ansible te configureren, gaat de tutorial ervan uit:

  • Je hebt al Ansible geïnstalleerd op een Linux-host.
  • Je hebt een Ansible-inventaris opgezet op basis van je Windows-hosts.
  • Je hebt een Windows Server 2016 of nieuwer om te beheren. Sommige cmdlets die in deze tutorial worden gebruikt, werken niet met oudere versies van Windows.
  • De Windows-host bevindt zich niet in een domein. Hoewel de voorbeelden zijn uitgevoerd op een host die niet is aangesloten op een domein, zou deze configuratie moeten werken op hosts die zijn aangesloten op een domein.
  • Je hebt RDP- of console-toegang tot de Windows-host en bent ingelogd als een lokale beheerder.
  • Je bent bekend met PowerShell. Bijna alle voorbeelden zullen PowerShell-code gebruiken om wijzigingen aan te brengen op de Windows-host.

Iedere sectie zal een codefragment gebruiken dat afhankelijk is van het vorige. Sommige fragmenten verwijzen naar eerder gedefinieerde variabelen. Zorg ervoor dat je je console open houdt terwijl je deze code kopieert/plakt als je van plan bent om het precies te volgen.

Als je alleen de code wilt zonder de uitleg, kun je gerust deze GitHub-gist downloaden.

Activeer PowerShell Remoting voor WinRm voor Ansible

Hoewel alle servers met Windows Server 2016 of later PowerShell Remoting hebben ingeschakeld, is het altijd een goed idee om dit te bevestigen.

Op de Windows-host die je wilt beheren, open je een PowerShell-console als administrator en voer je het volgende codefragment uit. Dit codefragment zorgt ervoor dat de WinRm-service wordt gestart en automatisch wordt gestart bij het opstarten van het systeem.

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

Vervolgens zorg je ervoor dat PowerShell Remoting is ingeschakeld door eerst te controleren of er actieve sessieconfiguraties zijn. Zo niet, controleer dan of er geen luisteraars beschikbaar zijn. WinRm voor Ansible moet ten minste één luisteraar hebben. Als een van deze voorwaarden niets oplevert, voer dan Enable-PSRemoting uit.

if (-not (Get-PSSessionConfiguration) -or (-not (Get-ChildItem WSMan:\localhost\Listener))) {
    ## Gebruik SkipNetworkProfileCheck om beschikbaar te zijn, zelfs op Windows Firewall openbare profielen
    ## Gebruik Force om niet gevraagd te worden als we zeker zijn of niet.
    Enable-PSRemoting -SkipNetworkProfileCheck -Force
}
Configuring WinRM for Ansible (a listener) via the winrm command

Activeer Certificaatgebaseerde Authenticatie

Standaard is WinRM niet geconfigureerd voor certificaatgebaseerde authenticatie. U moet dit inschakelen door WSMan te configureren zoals hieronder wordt weergegeven.

#regio Certificaatgebaseerde authenticatie inschakelen
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
#endregion

Maak een lokaal gebruikersaccount aan

Om certificaatgebaseerde WinRM voor Ansible-authenticatie te gebruiken, moet u een lokaal gebruikersaccount aan een certificaat “koppelen”. U kunt het lokale beheerdersaccount hiervoor gebruiken, maar het is altijd een goed idee om een specifiek account aan te maken om het beheer te vergemakkelijken.

De volgende codefragment maakt een lokaal gebruikersaccount aan voor WinRM voor Ansible met de naam ansibletestuser en een wachtwoord van p@$$w0rd12 als het niet bestaat. Om ervoor te zorgen dat het altijd actief blijft, zal het wachtwoord van dat account nooit verlopen.

$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
}

Maak het clientcertificaat aan

WinRM voor Ansible moet (veilig) twee certificaten hebben; een clientcertificaat en een servercertificaat.

U kunt hetzelfde certificaat gebruiken voor zowel de client als de server, maar ik liep tegen problemen aan met deze aanpak. In de Ansible-documentatie en veel andere bronnen vindt u instructies voor het genereren van het clientcertificaat via de New-SelfSignedCert-cmdlet van PowerShell. Hoewel deze methode zou kunnen werken, lukte het me niet om dit eenvoudig aan de praat te krijgen.

Om het clientcertificaat voor WinRM voor Ansible te maken, moet je een privé- en een openbare sleutel maken. Begin met SSH naar de Ansible-host te gaan en voer het volgende openssl-commando uit. Dit commando maakt een privésleutel in een bestand genaamd cert_key.pem en een openbare sleutel genaamd cert.pem. Het sleutelgebruik zal clientauthenticatie zijn (1.3.6.1.4.1.311.20.2.3) “toegewezen” aan de lokale gebruikersaccount die je eerder hebt aangemaakt genaamd ansibletestuser.

## Dit is de openbare sleutel gegenereerd vanaf de Ansible-server met behulp van:
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 

Nog een stap dichter bij de authenticatie van Ansible WinRM!

Importeer het Clientcertificaat

Zodra je het clientcertificaat voor WinRM voor Ansible hebt gemaakt, moet je het importeren in twee certificaatstores op de Windows-host voor WinRM op Ansible om te kunnen werken. Om dat te doen, breng eerst de openbare sleutel cert.pem over naar de Windows-host. Het voorbeeld hieronder gaat ervan uit dat de sleutel bestaat op C:\cert.pem.

Zodra je het openbare certificaat op de Windows-host hebt, importeer het in de certificaatstores Vertrouwde Root-certificeringsinstanties en Vertrouwde personen met behulp van Import-Certificate zoals hieronder weergegeven.

$pubKeyFilePath = 'C:\cert.pem'

## Importeer de openbare sleutel in Vertrouwde Root-certificeringsinstanties en Vertrouwde Personen
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\Root'
$null = Import-Certificate -FilePath $pubKeyFilePath -CertStoreLocation 'Cert:\LocalMachine\TrustedPeople'

Maak het Servercertificaat

WinRM voor Ansible heeft een certificaat nodig dat is gedefinieerd met een sleutelgebruik voor serverauthenticatie. Dit certificaat wordt opgeslagen in de certificaatstore LocalMachine\My van de Windows-host. Maak het zelfondertekende certificaat met behulp van het onderstaande codesnippet.

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

Maak de Ansible WinRm Luisteraar

Nadat je beide certificaten hebt aangemaakt, moet je nu een WinRm luisteraar maken op de Windows host. Deze luisteraar begint met het luisteren op poort 5986 voor inkomende verbindingen. Eenmaal gemaakt, accepteert deze luisteraar inkomende verbindingen en zal proberen gegevens te versleutelen met het hierboven gemaakte servercertificaat.

PowerShell Remoting gebruikt deze WinRM-luisteraar als transport zodra de authenticatie heeft plaatsgevonden.

In het onderstaande codefragment zie je een goed voorbeeld van het controleren op een bestaande HTTPS-luisteraar. Als er geen luisteraar wordt gevonden met het hierboven gemaakte servercertificaat, zal het een nieuwe maken.

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

## Als er helemaal geen luisteraars zijn gedefinieerd of als er geen luisteraar is geconfigureerd om mee te werken
## het servercertificaat gemaakt, maak dan een nieuwe met een Onderwerp van de computernaam
## en gekoppeld aan het servercertificaat.
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
}

“Koppel” het Clientcertificaat aan het Lokale Gebruikersaccount

De volgende stap is om ervoor te zorgen dat wanneer Ansible verbinding maakt met de Windows host met behulp van het servercertificaat, het vervolgens alle instructies uitvoert als een lokale gebruiker. In dit geval zal alle activiteit uitgevoerd door WinRm voor Ansible het lokale gebruikersaccount, ansibletestuser, gebruiken.

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

## Zoek de certificaatduimafdruk voor het clientcertificaat gemaakt op de Ansible host
$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 toestaan voor Ansible met Gebruikersaccountbeheer (UAC)

Als u een lokaal account gebruikt om een certificaat aan te maken, moet u ook de LocalAccountTokenFilterPolicy instellen op 1 om ervoor te zorgen dat UAC niet in de weg staat. De LocalAccountTokenFilterPolicy is van toepassing op alle lokale accounts (niet op domeinaccounts) en zorgt ervoor dat uw netwerkaanmelding het beperkte deel van uw token wordt. Hierdoor kan het niet worden aangemeld omdat Windows het niet als een beheerder ziet en WinRM standaard vereist dat de gebruiker een lokale beheerder is.

Door de LocalAccountTokenFilterPolicy in te stellen, vertelt u Windows om geen beperkt token te maken voor netwerkaanmeldingen door een lokaal account en om zijn volledige token te gebruiken.

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

Open Poort 5986 op de Windows Firewall

WinRm via HTTPS gebruikt poort 5986. Als de Windows Firewall is ingeschakeld, moet u deze poort openen. U kunt dit doen door de volgende PowerShell-codefragment uit te voeren. Dit codefragment is overdreven losjes en staat alle computers toe om het te gebruiken. Als u dit verder wilt beveiligen, zorg er dan voor dat u de parameter LocalAddress gebruikt en geef het IP-adres van Ansible op.

# Regio Zorg ervoor dat WinRM 5986 open is in de firewall
 $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

Voeg de lokale gebruiker toe aan de groep Beheerders

Je vraagt je misschien af waarom deze tutorial de lokale gebruiker niet gewoon eerder aan de Administrators-groep heeft toegevoegd. De reden hiervoor is dat om een onbekende reden, wanneer je probeert het clientcertificaat aan de gebruiker te koppelen, het gebruikersaccount geen lokale beheerder mag zijn.

Voer de volgende codefragment uit om het lokale gebruikersaccount ansibletestuser aan de groep administrators toe te voegen.

## Voeg de lokale gebruiker toe aan de administratorsgroep. Als deze stap niet wordt uitgevoerd, ziet Ansible een "AccessDenied" fout
Get-LocalUser -Name $testUserAccountName | Add-LocalGroupMember -Group 'Administrators'

Conclusie

Als je elk van deze stappen zoals getoond hebt gevolgd, zou je nu in staat moeten zijn om Ansible-commando’s uit te voeren tegen een Windows-host. Gebruik de module win_shell om je testen uit te voeren. Als deze module slaagt, heb je WinRM met certificaatgebaseerde authenticatie succesvol geconfigureerd!

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