{"id":1795,"date":"2023-03-10T09:17:10","date_gmt":"2023-03-10T14:17:10","guid":{"rendered":"https:\/\/enterpriseadmins.org\/blog\/?p=1795"},"modified":"2023-03-10T09:34:43","modified_gmt":"2023-03-10T14:34:43","slug":"keep-it-secure-automate-vcenter-server-ssl-certificate-replacement","status":"publish","type":"post","link":"https:\/\/enterpriseadmins.org\/blog\/scripting\/keep-it-secure-automate-vcenter-server-ssl-certificate-replacement\/","title":{"rendered":"Keep it secure: Automate vCenter Server SSL Certificate replacement"},"content":{"rendered":"\n<p>Validity periods for SSL certificates keep shrinking, requiring more frequent certificate replacements.  Something that once only needed done every 3 or so years is now required every year.  With these increased demands it is common to want to automate this task.  This article will show how to request and replace a vCenter Server certificate using a vSphere API and PowerCLI.  <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Background<\/h3>\n\n\n\n<p>Before we start replacing certificates it is important to understand the various options available for managing vSphere certificates.  In this article I&#8217;ll be focusing on automating the steps for the Hybrid Mode, where we only replace the certificate used by vCenter Server, and we let the default configuration of VMCA handle all the ESXi hosts.  The various options are well documented here: <a href=\"https:\/\/blogs.vmware.com\/vsphere\/2020\/04\/vsphere-7-certificate-management.html\">https:\/\/blogs.vmware.com\/vsphere\/2020\/04\/vsphere-7-certificate-management.html<\/a>.  <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The GUI Way<\/h3>\n\n\n\n<p>Now that we know which certificate replacement method we want to use, we&#8217;ll first explore how to complete this certificate replacement in the HTML5 UI.  We&#8217;ll navigate to vSphere Client &gt; Administration &gt; Certificates &gt; Certificate Management.  From here we can see the existing Machine_Cert that is used, which expires in November 2023.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"329\" height=\"357\" src=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image.png\" alt=\"\" class=\"wp-image-1796\" srcset=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image.png 329w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-276x300.png 276w\" sizes=\"auto, (max-width: 329px) 100vw, 329px\" \/><\/a><figcaption class=\"wp-element-caption\">vCenter Server HTML5 UI Machine_Cert<\/figcaption><\/figure>\n\n\n\n<p>In this tile with our certificate detail, we see an Actions drop down, which contains choices to Renew, Import and Replace Certificate, and Generate Certificate Signing Request (CSR).  When I do this in the HTML5 UI, it is typically two steps.  First, I create a CSR, which prompts me to enter information about the certificate I&#8217;d like to request.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"876\" height=\"688\" src=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-1.png\" alt=\"\" class=\"wp-image-1797\" srcset=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-1.png 876w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-1-300x236.png 300w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-1-768x603.png 768w\" sizes=\"auto, (max-width: 876px) 100vw, 876px\" \/><\/a><figcaption class=\"wp-element-caption\">vCenter Server &#8211; Generate CSR form<\/figcaption><\/figure>\n\n\n\n<p>Once this is complete, I&#8217;m provided with a long string of text (the CSR) which I need to send to my certificate management \/ crypto folks for processing.  They will return a certificate to me.  You may have noticed I do not see the private key at any point during this process &#8212; this is because vCenter keeps this information private.  Once I have my certificate, I can go back to the tile and provide the certificate files &#8212; the private key is already there.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"230\" src=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-2-1024x230.png\" alt=\"\" class=\"wp-image-1802\" srcset=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-2-1024x230.png 1024w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-2-300x67.png 300w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-2-768x172.png 768w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-2.png 1160w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Replace certificate screen, showing private key is embedded<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"620\" src=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-3-1024x620.png\" alt=\"\" class=\"wp-image-1803\" srcset=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-3-1024x620.png 1024w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-3-300x182.png 300w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-3-768x465.png 768w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-3.png 1159w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Step 2, showing the Machine SSL Certificate and Trusted root certificates being provided.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"438\" height=\"292\" src=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-4.png\" alt=\"\" class=\"wp-image-1804\" srcset=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-4.png 438w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/03\/image-4-300x200.png 300w\" sizes=\"auto, (max-width: 438px) 100vw, 438px\" \/><\/a><figcaption class=\"wp-element-caption\">UI showing success and that vCenter server services are restarting<\/figcaption><\/figure>\n\n\n\n<p>It can take some time for services to restart, but I should have another year before I need to replace this certificate again.<\/p>\n\n\n\n<p>This was very straight forward in the UI, the next steps will cover doing the same process using the vSphere API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Automating the Certificate Signing Request<\/h3>\n\n\n\n<p>When browsing vSphere Client &gt; Developer Center &gt; API Explorer, I see two interesting headings under the <code>vcenter<\/code> API endpoint we can see an entry for <code>certificate_management\/vcenter\/tls_csr<\/code>.  The description states &#8220;Generates a CSR with the given Spec.&#8221;  If we connect to the vSphere Automation SDK server with <code>Connect-CisServer<\/code>, we can get this specific service and create the spec.  From there, we can populate all the fields and then create our new CSR.  Here is a code block showing all these steps with some dummy data.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Connect-CisServer vcenter.example.com\n$tlsCSR = Get-CisService -Name com.vmware.vcenter.certificate_management.vcenter.tls_csr\n$tlscsrSpec = $tlscsr.Help.create.spec.Create()\n\n$tlscsrSpec.key_size = 2048\n$tlscsrSpec.common_name = 'vcenter.example.com'\n$tlscsrSpec.organization = 'Example'\n$tlscsrSpec.organization_unit = 'Testing'\n$tlscsrSpec.locality = 'Greenfield'\n$tlscsrSpec.state_or_province = 'Indiana'\n$tlscsrSpec.country = 'US'\n$tlscsrSpec.email_address = 'vi-admin@example.com'\n$tlscsrSpec.subject_alt_name = \"vcenter\"\n\n$tlsCSR.create($tlscsrSpec).csr<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Requesting the Certificate<\/h3>\n\n\n\n<p>As in the section where we discussed using the GUI, we now need to provide our CSR to the certificate management folks \/ crypto team.  They are typically responsible for requesting\/creating certificates.  Depending on the Certificate Authority in use, this step could also be automated, but it is outside the scope of this article.  <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Replacing the Certificate<\/h3>\n\n\n\n<p>Once we have our certificate, in my case a pair of <code>cer<\/code> files (one for my vCenter Server and one for the root cert of the CA), we can return to our PowerCLI window.  I was able to quickly request\/approve a new certificate and my PowerCLI session was still open so I didn&#8217;t need to use <code>Connect-CisServer<\/code> again, however you may need to reconnect days later, thats no problem and will work fine.  I used <code>Get-Content<\/code> to read in the two <code>cer<\/code> files, but by default that reads line by line.  Therefore, I used <code>-join<\/code> to put each line into a single variable, and for good measure removed any leading\/trailing spaces with <code>.trim()<\/code> as I&#8217;ve seen that cause issues with certificates in the past.  I then used the <code>certificate_management\/vcenter\/tls<\/code> service and created the sample specification.  This results in a new object being created where <code>cert<\/code> is required and the other properties (<code>key<\/code> and <code>root_cert<\/code>) are optional.  For my case I specified just the <code>cert<\/code> and <code>root_cert<\/code> since my CSR was generated\/stored by the vCenter Server Appliance already.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$cert = ( (Get-Content .\\certnew-vcsa-api.cer)  -join \"`n\").trim()\n$rootcert = ( (Get-Content .\\certnew-ca.cer) -join \"`n\").trim()\n\n$tls = Get-CisService -Name com.vmware.vcenter.certificate_management.vcenter.tls\n$setTls = $tls.Help.set.spec.Create()\n\n$setTls.cert = $cert\n$setTls.root_cert = $rootcert\n\n$tls.set($setTls)<\/code><\/pre>\n\n\n\n<p>After running that <code>$tls.set<\/code> method on the last line of the code block above, vCenter services automatically restart, just like in the UI example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion<\/h3>\n\n\n\n<p>This article shows how similar the HTML5 UI is to these specific APIs for certificate replacement.  I hope this helps you automate this repeatable task.  <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Validity periods for SSL certificates keep shrinking, requiring more frequent certificate replacements. Something that once only needed done every 3 or so years is now required every year. With these increased demands it is common to want to automate this &hellip; <a href=\"https:\/\/enterpriseadmins.org\/blog\/scripting\/keep-it-secure-automate-vcenter-server-ssl-certificate-replacement\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3,4],"tags":[],"class_list":["post-1795","post","type-post","status-publish","format-standard","hentry","category-scripting","category-virtualization"],"_links":{"self":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/1795","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/comments?post=1795"}],"version-history":[{"count":6,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/1795\/revisions"}],"predecessor-version":[{"id":1806,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/1795\/revisions\/1806"}],"wp:attachment":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/media?parent=1795"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/categories?post=1795"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/tags?post=1795"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}