=========================
== Eduardo Robles Site ==
=========================
Hola Mundo 🌮

Ansible for Cybersecurity Work - Part 1

Is it DevSecOp, SecDevOps, OpsSecDev?

The infosec field is full of buzzword now more so with the explosion of automation and AI. Luckily, I am not easily fooled by the buzzword and look for the real meat and bones. So when I was tasked with automating some tasks at work I jumped into an interesting technology called Ansible. Ansible is a tool for automation that is cross platform. It relies on setting up a secure connection to an endpoint and then Ansible handle executing tasks on the system.

In a Software/Hardware diverse environment a tool like Ansible is refreshing. But why would someone who work in Cybersecurity care about Ansible. Well technologies and environments change and having a tool that is cross-platform helps reduce complexity. I can use Ansible to manage Windows workstation and patch Linux servers. Deploy software to MacOS and manage Firewall settings. I’d like to take you along my journey of learning and implementing concepts like: Infrastructure as Code, DevSecOps, and Orchestration as a Cybersecurity Analyst.

Learning to Communicate

This series will be a quick and dirty view into how Ansible works. Let’s start with how Ansible communicates with endpoints. If you’re on a Unix based system that’s easy you will be using SSH. Simply setup SSH key based authentication and you are good to go. If you are on Windows based systems this gets a bit more interesting (or complicated). Yes, OpenSSH exists on Windows Servers and Workstations but it is not as robust as it is on Unix. Plus Microsoft has other tools for this type of automation. WinRM is the go tool technology on Windows system when using Ansible.

WinRM is not easy to configure or too understand. Most people get WinRM configurations wrong because Microsoft is not very good at explaining this tool. It took me about 3 months to fully understand the basics of WinRM. So I’d like to save you some time and explain the basics of WinRM. Let’s start with setting up a “Listener”.

WinRM Communication

WinRM communicates via an HTTP SOAP api. This means we can send WinRM communications via HTTP or HTTPS. Setting this is done with the winrm listener commands in Windows. The method of achieving HTTPS communication is multifaceted. You can employ a reverse proxy, use Active Directory Certificate Services to deploy certificates, or use OpenSSL to create certificates. The use of self-signed certificates is also possible.

Ansbile Variable

Setting the following variable will let Ansible know which communication method to use. ansible_winrm_scheme: ex. ansible_winrm_scheme: https

Setting Up HTTPS Certificate Validation with OpenSSL

Generate Certificates with OpenSSL

  • Generate the CA Private Key

    openssl genpkey -algorithm RSA -out ca-key.pem
    
  • Generate the CA certificate

    openssl req -x509 -new -nodes -key ca-key.pem -sha256 3650 -out ca-cert.pem -subj "/C=US/ST=DC/L=Washington/O=ORG/OU=MyORG/CN=CA"
    
  • Generate the private key for the Windows host

    openssl genpkey -algorithm RSA -out windows-host-key.pem
    
  • Create a certificate signing request (CSR)

    openssl req -new -key windows-host-key.pem -out windows-host.csr -subj "/C=US/ST=DC/L=Washington/O=ORG/OU=MyORG/CN=hostname.domain.com"
    
  • Create a configuration file for the certificate exentensions

    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, noRepudiation, keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1 = hostname.domain.com
    
  • Generate the certificate signed by the CA

    openssl x509 -req -in windows-host.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out windows-host-cert.pem -days 365 -sha256 -extfile windows-host-ext.cnf
    
  • Create the PFX file for Windows Host

    openssl pkcs12 -export -out windows-host-cert.pfx -inkey windows-host-key.pem -in windows-host-cert.pem -certfile ca-cert.pem -password pass:password
    

Import Certificates into the Windows Machine

  • Import the PFX Certificate into Windows Host

    Use Powershell as an Administrator

    $password = ConvertTo-SecureString -String "password" -Force -AsPlainText
    Import-PfxCertificate -FilePath "C:\path\to\windows-cert.pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $password
    
  • Import the CA certificate into Windows Host

    Import-Certificate -FilePath "C:\path\to\ca-cert.pem" -CertStoreLocation Cert:\LocalMachine\Root
    

Configure WinRM on the Windows Machine

  • Enable WinRM

    winrm quickconfig -force
    
  • Create an HTTPS listener using the certificate

    $cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Subject -eq "CN=hostname.domain.com"}
    $thumbprint = $cert.Thumbprint
    
  • Create the HTTPS Listener

    winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="hostname.domain.com"; CertificateThumbprint="$thumbprint"}
    
  • Enable Certificate Authentication

    winrm set winrm/config/service/auth @{Certificate="true"}
    
  • Set Trusted Hosts

    This adds extra security by only allowing one control machine(node) to communicate with the endpoints. This is a winrm configuration. The value ansible-controlnode is the hostname for whatever you are using as the Ansible control node.

    Set-Item wsman:\localhost\Client\TrustedHosts -Value "ansible-controlnode"
    

Configure Ansible to Use the Certificates

  • Place the CA Certificate and Client key/cert on the Ansible Control Node

    openssl pkcs12 -in windows-host-cert.pfx -clcerts -nokeys -out client-cert.pem -password pass:password
    openssl pkcs12 -in windows-host-cert.pfx -nocerts -nodes -out client-key.pem -password pass:password
    

Setting Up HTTPS with Self-Signed Certificate with Powershell

Generate the Self-signed certificate

In this example -DnsName is set the Hostname of the machine (FQDN).

New-SelfSignedCertificate -DnsName "MyMachine01.local" -CertStoreLocation Cert:\LocalMachine\My

Configure WinRM Listener

In this example Hostname is the the hostname of the machine, and CertificateThumbprint is get the Thumbprint from the Self-signed certificate.

winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname="MyMachine01.local"; CertificateThumbprint="thumbprintondevice"}'

Configure Firewall to Allow TCP 5986 aka WinRM over HTTPS

New-NetFirewallRule -DisplayName "WinRM over HTTPS" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow -Profile Domain

Configure TrustedHosts for WinRM

In this example I am setting the Trusted Hosts value to MyNode00.local. Ideally this will be the ansible control node.

Set-Item WSMan:\localhost\Client\TrustedHosts -Value "MyNode00.local"
  • Remove TrustedHosts Value

    If needed you can remove the trusted host value.

    Remove-Item WSMan:\localhost\Client\Trustedhosts
    
  • Get TrustedHosts Value

    Get-Item WSMan:\localhost\Client\Trustedhosts
    

Powershell Script to Enable WinRM Listener and Configure Firewall for HTTPS with Self-signed Certificate communication for WinRM

# Get Variables
# Hostname
$fqdn = $env:computername +'.'+ $env:userdnsdomain

# Create Variables
# Trusted Host
$trusthost = "MyNode00.local"
# Certificate Store "My"
$mystore = "Cert:\LocalMachine\My"
# Certificate Store "Root"
$rootstore = "Cert:\LocalMachine\root"

# Create new Self-signed certificate
Write-Verbose "Creating Self-Signed Certificate"
New-SelfSignedCertificate -DnsName "$fqdn" -CertStoreLocation Cert:\LocalMachine\My
# Create new Self-signed certificate and expire in 6 months
#New-SelfSignedCertificate -DnsName "$fqdn" -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddMonths(6)

# Get thumbrprint from Self-signed certificate
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Subject -eq "CN=$fqdn"}
$thumbprint = $cert.Thumbprint

# Find and start the WinRM service.
Write-Verbose "Verifying WinRM service."
If (!(Get-Service "WinRM")) {
  Write-ProgressLog "Unable to find the WinRM service."
  Throw "Unable to find the WinRM service."
}
ElseIf ((Get-Service "WinRM").Status -ne "Running") {
  Write-Verbose "Setting WinRM service to start automatically on boot."
  Set-Service -Name "WinRM" -StartupType Automatic
  Write-ProgressLog "Set WinRM service to start automatically on boot."
  Write-Verbose "Starting WinRM service."
  Start-Service -Name "WinRM" -ErrorAction Stop
  Write-ProgressLog "Started WinRM service."

}

# Configure WinRM Listener
Write-Verbose "Configure HTTPS Listener"
winrm create winrm/config/Listener?Address*+Transport=HTTPS '@{Hostname="$fqdn";CertificateThumbprint="$thumbprint"}'

#Configure Kerberos authentication for WinRM
Write-Verbose "Configure Kerberos Auth for WinRM"
winrm set WinRM/Config/Client/Auth '@{Basic="false";Digest="false";Kerberos="true";Negotiate="false";Certificate="true";CredSSP="false"}'

# Delete HTTP Listener
Write-Verbose "Deleting HTTP Listner"
winrm delete WinRM/Config/Listener?Address=*+Transport=HTTP

# Configure Firewall Rule
Write-Verbose "Configure Firewall Rule"
New-NetFirewallRule -DisplayName "WinRM over HTTPS" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow -Profile Domain

# Configure TrustedHosts
# This is how you prevent lateral movement!
Write-Verbose "Set WinRM Trusted Hosts"
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "$trusthost"

WinRM is NOT Powershell Remoting

This trips people up, don’t make the same mistake.

Conclusion

This is months of research and hacking together scripts. I haven’t gotten this work to a point were I feel it is production ready. Though I feel confident that is is a great starting point. I learned a lot about Certificate management, Windows Automation, Ansible Configurations, and Powershell. This is a fun project because it really pushed the boundaries of my knowledge of Linux and Windows systems. I am so grateful I have the opportunity to work in this field because I get to work on cool stuff like this.

Thank You

If you enjoyed or found any of the content on my site helpful, you can buy me a cup of coffee or send some bitcoin âš¡ so I can continue to bring you amazing content for free!

You can Buy Me A Coffee

Tip with some Sats

Tip Some Sats âš¡

Setup

  • Keyboard: Keyboardio Atreus (JWICk Ultimate Black Linear)
  • Mouse: MX Master (Original)
  • Emacs (WSL term)