Update ESX SSL Certs with your own Windows Domain CA Certificates using PowerCLI
Replacing ESX SSL is the easiest of all the vSphere components, in my opinion. Unlike vSphere 5.1, you can use Microsoft's Web Server SSL template, and there's no need to use the Java keytool or reregister the service with SSO.
Below is a script I use in conjunction with my vSphere/PowerShell Replace SSL script.
This is the first time I've actually used PowerCLI so I'm unsure if this script follows Best Practices, but hey, it worked for me in my lab environment ;)
"What it does.."
- Creates the certificate directory if it does not exist
- Logs into specified vSphere Server
- Automatically downloads Root64.cer from the CA's web service
- Downloads and extracts OpenSSL if the files do not exist in the specified path
- Generates all SSL certificates for each of the services on the server.
If $upsateesx is set to true..
- Downloads Putty SCP
- Checks to see if SSH is running on the esx host. If not, it temporarily enables it
- Prompts for and validates credentials
- Backs up all SSL Certs on the server
- Uploads the new certs
- Returns SSH to previous state
Once the new certs have been uploaded, you will have to restart the ESX host, or set it into maintenance mode and restart the Management services.
##############################################################################################
ESX Certificate Generation and Upload version 0.5
Tested on: ESX 5.1 / vCenter 5.1U1 / PowerCLI 5.1 Release 2
ESX 4.1 / vCenter 4.1U3
No guarantees, warranties, etc.
Blog post: https://goo.gl/OdIlF
##############################################################################################
vCenter Server FQDN
$vcserver = "vcenter41.base.local"
It is recommended that you place the certs on a network location
$basedir = "\\fileserver\share\Certs"
Enter your Windows Certificate Authority information
below. Make sure your $rootCA responds to certutil and web requests.
$rootCA = "dc.base.local" $rootCAName = "BASE-DC-CA" $email = "[email protected]" $org = "NetNerds" $city = "Kaplan" $state = "LA" $country = "US"
This can be WebServer or the VMware-SSL certificate
template found here: https://goo.gl/m98FE
$certTemplate = "CertificateTemplate:WebServer"
Enter the path of your openssl.exe (0.x and 1.x are supported).
If you don't have OpenSSL already, the script will download it for you.
$openssldir = "C:\OpenSSL-Win32"
Do you want the script to automatically backup the old ESX certs
and upload the new certs to each esx host?
$updateesx = $true
##############################################################################################
You shouldn't need to change anything below.
##############################################################################################
$openssl = $openssldir+"\bin\openssl.exe" $backuptime = (get-date -uformat "%m%d%Y%H%M%S") $backupdir = "$servicedir\backup-$backuptime" $null = (New-Item -Type Directory $backupdir) $esxhosts = @{}
if (!(Test-Path("$basedir"))) { $null = New-Item -Type Directory "$basedir" }
Write-Host -Foreground "Black" -Background "White" "Logging into $vcserver." if ($global:DefaultVIServers.Count -eq 0 -or ($global:DefaultVIServers).Name -ne $vcserver) {Connect-ViServer $vcserver}
Write-Host -Foreground "Black" -Background "White" "Getting list of esx servers." $esxServers = (Get-VMHost).Name foreach ($esxServer in $esxServers) { $esxdir = "$basedir\$esxServer-esx" $esxhosts.Add("$esxServer-esx", $esxServer) }
Write-Host -Foreground "Black" -Background "White" "Downloading root CA Cert.." $wc = New-Object System.Net.WebClient $url = "https://$rootCA/certsrv/certnew.cer?ReqID=CACert&Renewal=0&Enc=b64" $root64 = "$basedir\Root64.cer" $wc.UseDefaultCredentials = $true $wc.DownloadFile($url,$root64)
if (!(Test-Path($openssl))) { Write-Host -Foreground "Black" -Background "White" "Downloading OpenSSL.." $null = mkdir $openssldir $sslurl = "https://openssl-for-windows.googlecode.com/files/openssl-0.9.8k_WIN32.zip" $sslzip = "$env:temp\openssl.zip" $wc.DownloadFile($sslurl,$sslzip) $env:path = $env:path + ";$openssldir"
Write-Host -Foreground "Black" -Background "White" "Extracting OpenSSL.."
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($sslzip)
$destinationFolder = $shellApplication.NameSpace($openssldir)
$destinationFolder.CopyHere($zipPackage.Items())
Remove-Item $sslzip
}
if ($updateesx -eq $true) { Write-Host -Foreground "Black" -Background "White" "Downloading Putty SCP.." $scpurl = "https://tartarus.org/simon/20090227-kbdint-batch/x86/pscp.exe" # patched version for keyhost prompt issue $scp = "$env:temp\pscp.exe" $wc.DownloadFile($scpurl,$scp) }
######################################################################
Generate Certs
######################################################################
Write-Host -Foreground "Black" -Background "White" "Generating service certs.." foreach ($esxhost in $esxhosts.GetEnumerator()) { $service = $esxhost.Name $esxserverfqdn = $esxhost.Value $esxserver = $esxserverfqdn.Substring(0,$esxserverfqdn.IndexOf("."))
$servicedir = "$basedir\\$service"
$servicecfg = "$servicedir\\$service.cfg"
$tempkey = "$servicedir\\temp.key"
$ruikey = "$servicedir\\rui.key"
$ruicsr = "$servicedir\\rui.csr"
$ruicrt = "$servicedir\\rui.crt"
$keyalias = "rui"
if (Test-Path($servicedir)) { $null = Remove-Item "$servicedir\\\*.\*" } else {$null = mkdir $servicedir }
Set-Content $servicecfg "\[ req \]"
Add-Content $servicecfg " default\_md = sha512"
Add-Content $servicecfg " default\_bits = 2048"
Add-Content $servicecfg " default\_keyfile = rui.key"
Add-Content $servicecfg " distinguished\_name = req\_distinguished\_name"
Add-Content $servicecfg " encrypt\_key = no"
Add-Content $servicecfg " prompt = no"
Add-Content $servicecfg " string\_mask = nombstr"
Add-Content $servicecfg " req\_extensions = v3\_req"
Add-Content $servicecfg "\`n\[ v3\_req \]"
Add-Content $servicecfg " basicConstraints = CA:FALSE"
Add-Content $servicecfg " keyUsage = digitalSignature, keyEncipherment, dataEncipherment"
Add-Content $servicecfg " extendedKeyUsage = serverAuth"
Add-Content $servicecfg " subjectAltName = DNS:$esxserver, DNS:$esxserverfqdn"
Add-Content $servicecfg "\`n\[ req\_distinguished\_name \]"
Add-Content $servicecfg " countryName = $country"
Add-Content $servicecfg " stateOrProvinceName = $state"
Add-Content $servicecfg " localityName = $city"
Add-Content $servicecfg " 0.organizationName = $org"
Add-Content $servicecfg " organizationalUnitName = $service"
Add-Content $servicecfg " commonName = $esxserverfqdn"
&$openssl req -new -nodes -out $ruicsr -keyout $tempkey -config $servicecfg
&$openssl rsa -in $tempkey -out $ruikey
Remove-Item $tempkey
certreq -submit -config ""$rootCA\\$rootCAName"" -attrib $certTemplate $ruicsr $ruicrt
### Start ESX cert upload if updateesx is true and certificate generation is successful
if ($updateesx -eq $true -and (Test-Path($ruikey)) -and (Test-Path($ruicrt))) {
$disablessh = $null; $failedauth = 0
$sshservice = (Get-VMHostService -VMHost $esxserverfqdn -Server $vcserver | Where { $\_.Key -eq "TSM-SSH"})
if ($sshservice.Running -eq $false) {
Write-Host -Foreground "Black" -Background "White" "Temporarily enabling SSH on $esxserverfqdn" ; $disablessh = $true
$null = Start-VMHostService -HostService $sshservice -Confirm:$false
}
Write-Host -Foreground "Black" -Background "White" "Validating authentication."
Write-Host -Foreground "Black" -Background "White" "You can ignore any SSH keyhost prompts you may see.."
do {
$msg = "Enter the username and password for $esxserverfqdn";
$creds = $Host.UI.PromptForCredential($caption,$msg,"root",$domain)
$esxusername = $creds.username; $esxpassword = $creds.GetNetworkCredential().password
$esxsslpath = "$esxusername@$esxserverfqdn"+":/etc/vmware/ssl/"
$authenticated = $null
$checkauth = (Echo "Y" | &($scp) -scp -pw $esxpassword -ls $esxsslpath)
if ($checkauth -eq $null) {
$authenticated = $false
$failedauth++
}
} until ($authenticated -ne $false -or $failedauth -gt 4)
if ($failedauth -gt 4) { Write-Host -Foreground "Black" -Background "White" "Sorry, too many failed logins."; Break }
Write-Host -Foreground "Black" -Background "White" "\`rAuthentication accepted!"
Write-Host -Foreground "Black" -Background "White" "Backing up current certs.."
echo "Y" | &($scp) -scp -batch -pw $esxpassword "$esxsslpath/rui.key" $backupdir
echo "Y" | &($scp) -scp -batch -pw $esxpassword "$esxsslpath/rui.crt" $backupdir
Write-Host -Foreground "Black" -Background "White" "Uploading new certs.."
echo "Y" | &($scp) -scp -batch -pw $esxpassword "$ruikey" $esxsslpath
echo "Y" | &($scp) -scp -batch -pw $esxpassword "$ruicrt" $esxsslpath
if ($disablessh) {
Write-Host -Foreground "Black" -Background "White" "Returning SSH to disabled state on $esxserverfqdn"
$null = Stop-VMHostService -HostService $sshservice -Confirm:$false
}
Write-Host -Foreground "Black" -Background "White" "Finished uploading files on $esxserverfqdn. Reboot the ESX host to activate new certificates."
}
}
###############################################################################
Finish
###############################################################################
if ($updateesx -eq $true) { $null = Remove-Item $scp } Write-Host -Foreground "Black" -Background "White" "Done!"
Download ReplaceSSL-ESX.ps1
Note that you will have to re-add ESX to vCenter because the host's SSL thumbprint has changed. Regarding updating ESX's SSL, Derek Seaman suggests:
If your ESXi host is already managed by vCenter, the HA agent can get very confused by the new SSL certificate thumbprint. I would strongly suggest you first put your host in maintenance mode, remove it from the vCenter inventory, update the SSL certificate, reboot the ESXi host, then re-add it to the vCenter inventory.
All SSL Certificate Replacement Posts and Scripts in this Series
vSphere 4.1-5.0 SSL Generation and Replacement Post |