For the longest time the configuring of vCloud Director’s SSL certificate keystore has been the thing that makes vCD admins shudder. There are lots of posts on the process…some good…some not so good. I even have a post from way back in 2012 about fronting vCD with a Citrix NetScaler and if I am honest, I cheated in having HTTPS at the load balancer deal with the SSL certificate while leaving vCD configured with the self signed cert. With the changes to the way the HTML5 Tenant Portal deals with certs and DNS I’m not sure that method would even work today.
I wanted to try and update the self signed certs in both my lab environments to assist in resolving the No Datacenters are available issue that cropped up in vCD 9.1. Instead of generating and using self signed certs I decided to try use Let’s Encrypt signed certs. Most of the process below is curtesy of blog posts from Luca Dell’Oca and it’s worth looking at this blog post from Tom Fojta who has a PowerShell script to automate Let’s Encrypt SSL certs for us on NSX Edge load balancers.
In my case, I wanted to install the cert directly into the vCD Cell Keystore. The manual end to end the process is listed below. I intend to try and automate this process so as to overcome the one constraint with using Let’s Encrypt…that is the 90 day lifespan of the certs. I think that is acceptable and it ensures validity of the SSL cert and a fair caveat given the main use case for this is in lab environments.
Generating the Signed SSL Cert from Let’s Encrypt:
To complete this process you need the ACMESharp PowerShell module. There are a couple of steps to follow which include registering the domain you want to create the SSL cert against, triggering a verification challenge that can be done by creating a domain TXT record as shown in the output of the challenge command. Once submitted, you need to look out for a Valid Status response.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 | PS C:\ProgramData\ACMESharp\sysVault> New-ACMEIdentifier -Dns vcloud.aperaturelabs.biz -Alias aplabs2IdentifierPart : ACMESharp.Messages.IdentifierPartIdentifierType : dnsIdentifier : vcloud.aperaturelabs.bizUri : https://acme-v01.api.letsencrypt.org/acme/authz/********xH92Xzm8ggC5ctaIrmEgQKyAjXeb6tFgVT8Status : pendingExpires : 7/4/2018 1:38:28 PMChallenges : {, }Combinations : {1, 0}PS C:\ProgramData\ACMESharp\sysVault> Complete-ACMEChallenge aplabs2 -ChallengeType dns-01 -Handler manualIdentifierPart : ACMESharp.Messages.IdentifierPartIdentifierType : dnsIdentifier : vcloud.aperaturelabs.bizUri : https://acme-v01.api.letsencrypt.org/acme/authz/********H92Xzm8ggC5ctaIrmEgQKyAjXeb6tFgVT8Status : pendingExpires : 7/4/2018 1:38:28 PMChallenges : {, manual}Combinations : {1, 0}PS C:\ProgramData\ACMESharp\sysVault> (Get-ACMEIdentifier aplabs2).ChallengesChallengePart : ACMESharp.Messages.ChallengePartChallenge :Type : http-01Uri : https://acme-v01.api.letsencrypt.org/acme/challenge/********xH92Xzm8ggC5ctaIrmEgQKyAjXeb6tFgVT8/5331328098Token :********g5cYoQcUaUhHiAA2qIMAvq_CTpMV-X5AEStatus : pendingOldChallengeAnswer : [, ]ChallengeAnswerMessage :HandlerName :HandlerHandleDate :HandlerHandleMessage :HandlerCleanUpDate :HandlerCleanUpMessage :SubmitDate :SubmitResponse :ChallengePart : ACMESharp.Messages.ChallengePartChallenge : ACMESharp.ACME.DnsChallengeType : dns-01Uri : https://acme-v01.api.letsencrypt.org/acme/challenge/********xH92Xzm8ggC5ctaIrmEgQKyAjXeb6tFgVT8/5331328099Token :********ko5kw1tjZ6NIlOrkY0KNDCx6zp0FUD4WMStatus : pendingOldChallengeAnswer : [, ]ChallengeAnswerMessage :HandlerName : manualHandlerHandleDate : 6/27/2018 9:38:42 AMHandlerHandleMessage : == Manual Challenge Handler – DNS == * Handle Time: [6/27/2018 9:38:42 AM] * Challenge Token: [********_Zko5kw1tjZ6NIlOrkY0KNDCx6zp0FUD4WM] To complete this Challenge please create a new Resource Record (RR) with the following characteristics: * RR Type: [TXT] * RR Name: [_acme-challenge.vcloud.aperaturelabs.biz] * RR Value: [********uK6sTtuXdYOZ87IZr1KF0Z_3NTtgfg8AH8] ————————————HandlerCleanUpDate :HandlerCleanUpMessage :SubmitDate :SubmitResponse :PS C:\ProgramData\ACMESharp\sysVault> Submit-ACMEChallenge aplabs2 -ChallengeType dns-01IdentifierPart : ACMESharp.Messages.IdentifierPartIdentifierType : dnsIdentifier : vcloud.aperaturelabs.bizUri : https://acme-v01.api.letsencrypt.org/acme/authz/********xH92Xzm8ggC5ctaIrmEgQKyAjXeb6tFgVT8Status : pendingExpires : 7/4/2018 1:38:28 PMChallenges : {, manual}Combinations : {1, 0}PS C:\ProgramData\ACMESharp\sysVault> (Update-ACMEIdentifier aplabs2 -ChallengeType dns-01).Challenges | Where-Object {$_.Type -eq “dns-01”}ChallengePart : ACMESharp.Messages.ChallengePartChallenge : ACMESharp.ACME.DnsChallengeType : dns-01Uri : https://acme-v01.api.letsencrypt.org/acme/challenge/********xH92Xzm8ggC5ctaIrmEgQKyAjXeb6tFgVT8/5331328099Token :********_Zko5kw1tjZ6NIlOrkY0KNDCx6zp0FUD4WMStatus : validOldChallengeAnswer : [, ]ChallengeAnswerMessage :HandlerName : manualHandlerHandleDate : 6/27/2018 9:38:42 AMHandlerHandleMessage : == Manual Challenge Handler – DNS == * Handle Time: [6/27/2018 9:38:42 AM] * Challenge Token: [********_Zko5kw1tjZ6NIlOrkY0KNDCx6zp0FUD4WM] To complete this Challenge please create a new Resource Record (RR) with the following characteristics: * RR Type: [TXT] * RR Name: [_acme-challenge.vcloud.aperaturelabs.biz] * RR Value: [********uK6sTtuXdYOZ87IZr1KF0Z_3NTtgfg8AH8] ————————————HandlerCleanUpDate :HandlerCleanUpMessage :SubmitDate : 6/27/2018 9:53:22 AMSubmitResponse : {StatusCode, Headers, Links, RawContent…} |
Once complete, there is a script that can be run as show on Luca’s Blog. I’ve added to the script to automatically import the newly created SSL cert into the Local Computer certificate store.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 | PS C:\ProgramData\ACMESharp\sysVault> C:\Users\anthonyspiteri\Documents\PowerCLI\ssl_gen_le.ps1Press Enter to continue…:Id : 10c6b280-88fa-49d0-bead-9f98046aca74Alias : aplabs2-2018-06-27-09-56Label :Memo :IdentifierRef : 78828140-16c2-40e5-9932-c37b065cf291IdentifierDns : vcloud.aperaturelabs.bizAlternativeIdentifierDns :KeyPemFile : ********-88fa-49d0-bead-9f98046aca74-key.pemCsrPemFile : ********-88fa-49d0-bead-9f98046aca74-csr.pemGenerateDetailsFile : ********-88fa-49d0-bead-9f98046aca74-gen.jsonCertificateRequest : ACMESharp.CertificateRequestCrtPemFile : ********-88fa-49d0-bead-9f98046aca74-crt.pemCrtDerFile : ********-88fa-49d0-bead-9f98046aca74-crt.derIssuerSerialNumber : ********0000015385736A0B85ECA708SerialNumber : ********4DE77F1E372768C5B307DC3B1B87Thumbprint : ********799A2E754C08EE3569B667F470AF61E71Signature : ********99A2E754C08EE3569B667F470AF61E71SignatureAlgorithm : sha256RSARevokedAt :PSPath : Microsoft.PowerShell.Security\Certificate::LocalMachine\my\9D9B264799A2E754C08EE3569B667F470AF61E71PSParentPath : Microsoft.PowerShell.Security\Certificate::LocalMachine\myPSChildName : 9D9B264799A2E754C08EE3569B667F470AF61E71PSIsContainer : FalseArchived : FalseExtensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid…}FriendlyName : CN=vcloud.aperaturelabs.bizIssuerName : System.Security.Cryptography.X509Certificates.X500DistinguishedNameNotAfter : 9/25/2018 8:56:55 AMNotBefore : 6/27/2018 8:56:55 AMHasPrivateKey : TruePrivateKey :PublicKey : System.Security.Cryptography.X509Certificates.PublicKeyRawData : {48, 130, 6, 27…}SerialNumber : ********77F1E372768C5B307DC3B1B87SubjectName : System.Security.Cryptography.X509Certificates.X500DistinguishedNameSignatureAlgorithm : System.Security.Cryptography.OidThumbprint : ********99A2E754C08EE3569B667F470AF61E71Version : 3Handle : 2048481365152Issuer : CN=Let’s Encrypt Authority X3, O=Let’s Encrypt, C=USSubject : CN=vcloud.aperaturelabs.bizEnhancedKeyUsageList : {Server Authentication (1.3.6.1.5.5.7.3.1), Client Authentication (1.3.6.1.5.5.7.3.2)}DnsNameList : {vcloud.aperaturelabs.biz}SendAsTrustedIssuer : FalseEnrollmentPolicyEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointPropertyEnrollmentServerEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointPropertyPolicyId : |
From here, I exported the certificate with the private key so that you are left with a PFX file. I also saved to Base-64 X.509 format the Root and Intermediate certs that form the whole chain. This is required to help resolve the No Datacenters are available error mentioned above. Upload the three files to the vCD cell and continue as shown below.
Importing Signed SSL from Let’s Encrypt into vCD Keystore:
Next, the steps to take on the vCD Cell can be the most complex steps to follow and this is where I have seen different posts do different things. Below shows the commands from start to finish that worked for me…see inline for comments on what each command is doing.
123456789101112131415161718192021222324252627282930313233 | # Convert PFX to PEMopenssl pkcs12 -in vcloud.aperaturelabs.biz.pfx -out certificate.cer -nodes# Get Private Key from filevi certificate.cer# Create new file with Private Keyvi certificate.key# Recreate PFX and create Alias for http and consoleproxyopenssl pkcs12 -export -in certificate.cer -inkey certificate.key -name http -passout pass:password -out http.pfxopenssl pkcs12 -export -in certificate.cer -inkey certificate.key -name consoleproxy -passout pass:password -out consoleproxy.pfx # Import the http and consoleproxy PFXs into the new KeyStore/opt/vmware/vcloud-director/jre/bin/keytool -importkeystore -srckeystore http.pfx -srcstoretype PKCS12 -destkeystore CERTIFICATES.ks -deststoretype JCEKS -deststorepass password -srcalias http -destalias http -srcstorepass password/opt/vmware/vcloud-director/jre/bin/keytool -importkeystore -srckeystore consoleproxy.pfx -srcstoretype PKCS12 -destkeystore CERTIFICATES.ks -deststoretype JCEKS -deststorepass password -srcalias consoleproxy -destalias consoleproxy -src storepass password# Import the Intermediate and root files that form the chain/opt/vmware/vcloud-director/jre/bin/keytool -importcert -alias intermediate -file le-int.cer -storetype JCEKS -keystore CERTIFICATES.ks -storepass password/opt/vmware/vcloud-director/jre/bin/keytool -importcert -alias root -file le-root.cer -storetype JCEKS -keystore CERTIFICATES.ks -storepass password# List the KeyStore certificates to ensure everything is there/opt/vmware/vcloud-director/jre/bin/keytool -list -keystore CERTIFICATES.ks -storetype JCEKS -storepass password# Save existing Keystore and overwrite with newcp certificates.ks certificates.ks.oldcp ~root/CERTIFICATES.ks /opt/keystore/certificates.ks# Assign ownership of the new KeyStore to vCloud user and groupchown vcloud:vcloud certificates.ks# Run the vCD Configuration again to import the new KeyStore/opt/vmware/vcloud-director/bin/configure |
Once that has been done and the vCD services has restarted, the SSL cert has been applied and we are all green and the Let’s Encrypt SSL cert is in play.