Powershelling to renew certificates on Windows servers
Updated at by ospiAs a total Powershell newbie I had the pleasure of scripting some case-insensitive commands to replace certificates on Windows servers running IISs and Java Wildfly application servers. In the deploy_cert() phase I build two pfx files for Windows hosts, one with the 20th century switches (-certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg SHA1) and one with defaults.
Replacing IIS certs
In preparation, unification of all binding configurations with proper port:hostname pairs was required (server { listen + server_name <name> } in nginx). First importing the certificate to "my".
$importedCert = Import-PfxCertificate -FilePath $certPath -CertStoreLocation "Cert:\LocalMachine\My" -Password $pfxPassword
$thumbprint = $importedCert.Thumbprint
Script has a parameter $bindingInformation which is used to pick one binding. If Where-Object filter comes up with non-one result all is lost.
Import-Module WebAdministration
$binding = Get-WebBinding -Protocol "https" | Where-Object { $_.bindingInformation -like "*:$bindingInformation" }
if ($binding.Count -eq 1) {
$binding.AddSslCertificate($thumbprint, "my") # Using certificate from "my" vOv
Write-Host "Certificate $thumbprint applied to binding: $($binding.bindingInformation)"
} else {
Write-Host "Ffs multiple or no binding found with bindingInformation : $bindingInformation"
}
New certificate is used for new connections immediately without reload/restarts, which is nice.
Replacing Java Wildfly certs
Never heard of Wildfly but ours have their configurations in XML files and they contain a security-realm with a specific name. Script is parametrized with xml path and realm name eg. c:\Program Files\configuration\standalone.xml:UndertowRealm.
[xml]$xml = Get-Content $wildFlyConfiguration
$securityRealm = $xml.server.management.'security-realms'.'security-realm' | Where-Object { $_.name -eq $wildFlySecurityRealm }
From the security realm, we can dig up further to find the keystore path, alias, passwords etc.
$keystore = $securityRealm.'server-identities'.ssl.keystore
$keystorePassword = $keystore.'keystore-password'
$keystoreKeyPassword = $keystore.'key-password'
$alias = $keystore.alias
$path = $keystore.path
Which in turn is used to parametrize java keytool
$arguments = @(
"-importkeystore",
"-srckeystore", "$certPath",
"-srcstoretype", "PKCS12",
"-srcstorepass", "$pfxPasswordPlain",
"-srcalias", "wildfly",
"-destkeystore", "$path",
"-deststoretype", "JKS",
"-deststorepass", "$keystorePassword",
"-destkeypass", "$keystoreKeyPassword",
"-destalias", "$alias",
"-noprompt"
)
Start-Process -FilePath "C:\Program Files\Java\jdk1.2\bin\keytool.exe" `
-ArgumentList $arguments `
-NoNewWindow -Wait `
-RedirectStandardOutput "keytool_stdout.txt" `
-RedirectStandardError "keytool_stderr.txt"
Keytool was a bit picky eg. source and destination aliases weren't equal or key passwords weren't set or something, but I couldn't be arsed to dig deeper. Afterwards, wildfly-cli can be used to reload the http component or just restart the service.
RDGateway certificate
Imported certificate to "my" storage like with IIS and identifier was stored into $thumbprint and script is parametrized with $connectionBroker which identifies the hostname.
Import-Module RemoteDesktop
Set-RDCertificate -Role RDGateway -Thumbprint $thumbprint -ConnectionBroker $connectionBroker -force
Summary
Dehydrated creates pfx files (aka. pkcs12) on the fly in the local hook and calls a powershell script with the machine and service.
pwsh distribute_cert.ps1 hurr.my.domain.tld "${SYNC_DIR}/${DOMAIN}.legacy.pfx" "jks:c:\Program Files\wildfly\standalone.xml:UndertowRealm"
pwsh distribute_cert.ps1 durr.my.domain.tld "${SYNC_DIR}/${DOMAIN}.pfx" "iis:8443:my.iis.server.domain.tld"
pwsh distribute_cert.ps1 derp.my.domain.tld "${SYNC_DIR}/${DOMAIN}.pfx" "rdg:rdgateway.my.domain.tld"
Happy dehydrating!