Ansible/Linux: Windows Remote Management
There are a few different ways to handle Windows Remote Management (WinRM/Powershell)
Configure Windows Hosts
All of the configuration can be done via the "ConfigureRemotingForAnsible.ps1 script you can access from this page: https://docs.ansible.com/ansible/latest/os_guide/windows_setup.html
Instead, you should use a GPO that autoenrolls the computer with a certificate and assigns that to the https listener.
An article covering this will be released in the near future and linked here.
Powershell Version Number
Powershell version 5.1 is the minimum required with .NET 4.0. You need to upgrade these from Microsoft if you don't meet this requirement.
To check the version of powershell, open powershell and execute this: $PSVersionTable.PSVersion.ToString()
Enable WinRM and Powershell Remoting
Enable WinRM and Powershell Remoting on the destination Servers.
Enable-PSRemoting
Allow WinRM to get an elevated token
In order to get an elevated token, you have to tweak a UAC setting.
$token_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
$token_prop_name = "LocalAccountTokenFilterPolicy"
$token_key = Get-Item -Path $token_path
$token_value = $token_key.GetValue($token_prop_name, $null)
if ($token_value -ne 1) {
Write-Verbose "Setting LocalAccountTokenFilterPolicy to 1"
if ($null -ne $token_value) {
Remove-ItemProperty -Path $token_path -Name $token_prop_name
}
New-ItemProperty -Path $token_path -Name $token_prop_name -Value 1 -PropertyType DWORD > $null
}
Enable HTTPS Listener for WinRM
If you have a Windows Domain, you can use a GPO to enable this with a trusted root CA.
Ansible uses HTTPS for communication with the Windows Host which must be enabled separately
To do this, you need a certificate with the correct subject name. It is recommended to have it include the FQDN as well as just the hostname. Ansible in our examples will ignore validation errors.
If you have an Enterprise Certification Authority then get the certificate from there. You should place the certificate's thumbprint and subject into the variables $thumbprint and $subjectName
Otherwise, create a new self-signed cert and get those thumbprint and subjectNames. Please not that a self-signed cert is not trusted by your client automatically. You can create one like this:
Function New-LegacySelfSignedCert {
Param (
[string]$SubjectName,
[int]$ValidDays = 1095
)
$hostnonFQDN = $SubjectName
$hostFQDN = [System.Net.Dns]::GetHostByName(($env:computerName)).Hostname
$SignatureAlgorithm = "SHA256"
$name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$SubjectName", 0)
$key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft Enhanced RSA and AES Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 4096
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
$ekuoids.Add($serverauthoid)
$ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = (Get-Date).AddDays(-1)
$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
$SigOID = New-Object -ComObject X509Enrollment.CObjectId
$SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value)
[string[]] $AlternativeName += $hostnonFQDN
$AlternativeName += $hostFQDN
$IAlternativeNames = New-Object -ComObject X509Enrollment.CAlternativeNames
foreach ($AN in $AlternativeName) {
$AltName = New-Object -ComObject X509Enrollment.CAlternativeName
$AltName.InitializeFromString(0x3, $AN)
$IAlternativeNames.Add($AltName)
}
$SubjectAlternativeName = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
$SubjectAlternativeName.InitializeEncode($IAlternativeNames)
[String[]]$KeyUsage = ("DigitalSignature", "KeyEncipherment")
$KeyUsageObj = New-Object -ComObject X509Enrollment.CX509ExtensionKeyUsage
$KeyUsageObj.InitializeEncode([int][Security.Cryptography.X509Certificates.X509KeyUsageFlags]($KeyUsage))
$KeyUsageObj.Critical = $true
$cert.X509Extensions.Add($KeyUsageObj)
$cert.X509Extensions.Add($ekuext)
$cert.SignatureInformation.HashAlgorithm = $SigOID
$CERT.X509Extensions.Add($SubjectAlternativeName)
$cert.Encode()
$enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
# extract/return the thumbprint from the generated cert
$parsed_cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$parsed_cert.Import([System.Text.Encoding]::UTF8.GetBytes($certdata))
return $parsed_cert.Thumbprint
}
$SubjectName = $env:COMPUTERNAME
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays 1095
Now you can create the WSMan Instance for HTTPS:
# Create the hashtables of settings to be used.
$valueset = @{
Hostname = $SubjectName
CertificateThumbprint = $thumbprint
}
$selectorset = @{
Transport = "HTTPS"
Address = "*"
}
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
The Different Authentication Mechanisms of WSMan
WSMan has several authentication mechanisms. You can see which ones are enabled with this command:Get-ChildItem WSMan:\localhost\Service\Auth
You can enable/disable the different providers from powershell unless the "SourceOfValue" is GPO or anything other than blank. To do that you use this command:winrm set winrm/config/service/auth @{Negotiate="true"}
or in Powershell:Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true
Where "Negotiate" is the Name of the method you wish to modify and true/false to enable/disable.
1) Certificate Authentication (From an Enterprise CA)
2) Kerberos
3) Certificate Authentication (From a Self-signed Certificate)
4) NTLM
5) CredSSP (But might as well use Cert Auth)
6) The above options
9) Basic (This REALLY shouldn't EVER be used)
Basic
Basic Authentication is built into the HTTP Standard. In order to use basic authentication, the client generates an token in the format of "username:password" and encodes it in a Base64 string to pass in the HTTP header. This Base64 string is NOT encrypted and is easily decoded.
- Do NOT use Basic Authentication unless absolutely necessary.
- Do NOT use Basic Authentication over HTTP.
- Do NOT use Basic Authentication unless you have HTTPS configured to require trust of the server certificate.
- Do NOT use Basic Authentication unless you have full control of the network and can guarantee no transparent proxies will decode it.
- Just don't use Basic Authentication.
Kerberos
This is a Windows Domain authentication method.
I will link a more detailed Kerberos post when I can write it. Until then you can refer to here: https://www.freecodecamp.org/news/how-does-kerberos-work-authentication-protocol/
The short of it is that, with Kerberos, you get a ticket from the domain controller (usually) called a "ticket granting ticket" (TGT), and then your computer gets tickets using that to authenticate to remote services.
The password is sent only to a trusted domain controller and is encrypted prior to being placed in the https stream so if anything decrypts the https traffic then they will not have your password. After the TGT is granted, your password is not passed in the traffic at all.
This is the preferred authentication method for a Windows Domain and is resistant to Man in the Middle attacks.
Negotiate (NTLM)
Negotiate will automatically select between Kerberos and NTLM. Since we discussed Kerberos, I'll only discuss NTLM here.
NTLM uses synchronous encryption, and password hashing with random salting values to authenticate the password. The username is passed in plain text.
NTLM works outside of a Windows Domain.
Although the password is never sent, it is still possible for an attacker to use "Man in the Middle" attacks to receive your hash and use it for authentication. Because of this, make sure you configure HTTPS with trusted certificates.
Certificate
Certificate authentication only works over HTTPS and requires additional configuration if used without a Windows Domain.
The server must have a Certificate issued from a trusted source and the User must have a certificate from a trusted source. They don't HAVE to be the SAME source. The user must also have the private key for the certificate.
In this method, the client verifies the authenticity of the certificate provided by the server and then sends their own certificate along with information to show the client has the private key. The server maps the certificate to user (another topic entirely) and then provide authentication.
The private key is typically stored on a smartcard or in a password-protected file. Ansible uses a library which requires the private key to be stored unencrypted. Becuase of this, make sure your private key file has appropriate security like your ssh key files.
Also, certificates provide additional information such as expiration and can be revoked from the central authority.
CredSSP
CredSSP works very similar to NTML over SSL when trust of the server's certificate is required. This mechanism is used primarily by RDP but can be used by WinRM as well.
Please note, CredSSP is NOT NTLM.
CredSSP is beneficial as a mechanism for delegating credentials, that is authentication to a host and then jumping from that host to another host.