Automate Let’s Encrypt Certificates – Part 2

Some time ago I blogged about how I automate acquisition of Let’s Encrypt Certificates for my lab (NSX + vCloud Director) with PowerShell. The old script no longer works due to some changes on Let’s Encrypt side therefore the need for part 2.

To quickly summarize my situation. My lab consists of vCloud Director with multiple cells fronted by NSX-V Load Balancer. I need public certificate for vCloud Director which is uploaded to the NSX-V Load Balancer (that does L7 SSL termination) and to vCloud Director public addresses.


  • Web server on the domain your are getting the certificate for. It is necessary for the DNS challenge that proves you own the domain you are requesting the certificate for. I am using IIS on the machine I trigger the script from and supply the root folder where the challenge file needs to be placed.
  • NSX-V API access information – needed to replace the certificate on the NSX-Edge
  • Details about the load balancer (on which Edge it is running and what is the LB application profile of vCloud Director)
  • vCloud Director API access information – needed to upload new certificate and the full chain to vCloud Director public addresses.
  • PowerShell modules: POSH-ACME and PowerCLI

$Username = "admin"
$Password = "default"
$NSXManager = ""
$LBEdge = 'edge-1'
$ApplicationProfile = 'applicationProfile-1'
$Email = ""
$Domain = ""
$Vcd = ""
$VcdAdmin = "administrator"
$VcdPassword = "vcloud"
$IisAcmeRoot = "C:\inetpub\wwwroot\.well-known\acme-challenge"

$RootCert = "-----BEGIN CERTIFICATE-----

#Set-PAServer LE_STAGE
Set-PAServer LE_PROD

## Read

New-PAAccount -AcceptTOS -Contact $Email
New-PAOrder $Domain

$auths = Get-PAOrder | Get-PAAuthorizations
$token = $auths[0].HTTP01Token
$toPublish = Get-KeyAuthorization $token

## Upload challenge file to the IIS web server
New-Item -Path $IisAcmeRoot -Name $token -Value $toPublish

$auths.HTTP01Url | Send-ChallengeAck
New-PACertificate $Domain
$cert = Get-PACertificate

$IssuerCert = [IO.File]::ReadAllText($cert.ChainFile)
$PrivateKey = [IO.File]::ReadAllText($cert.KeyFile)
$LBCertificate = [IO.File]::ReadAllText($cert.CertFile)

## Create authorization string and store in $head
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Username + ":" + $Password))
$head = @{"Authorization"="Basic $auth"}

##Upload certificate
$Uri = "https://$NSXManager/api/2.0/services/truststore/certificate/" + $LBEdge
$Body = "
<pemEncoding>" + $LBCertificate + $IssuerCert + $RootCert + "</pemEncoding>
<privateKey>" + $PrivateKey + "</privateKey>
<description>vCloud Certificate</description>
$r = Invoke-WebRequest -URI $Uri -Method Post -Headers $head -ContentType "application/xml" -Body $Body -ErrorAction:Stop
$NewCertificateId = ([xml]$r).certificates.certificate.objectId

##Delete Root and intermediate certificate from the Edge as they are not needed
$Uri = "https://$NSXManager/api/2.0/services/truststore/certificate/" + $NewCertificateId[0]
$r = Invoke-WebRequest -URI $Uri -Method Delete -Headers $head -ContentType "application/xml" -ErrorAction:Stop
$Uri = "https://$NSXManager/api/2.0/services/truststore/certificate/" + $NewCertificateId[1]
$r = Invoke-WebRequest -URI $Uri -Method Delete -Headers $head -ContentType "application/xml" -ErrorAction:Stop

##Replace certificate in the application profile
$Uri = "https://$NSXManager/api/4.0/edges/" + $LBEdge + "/loadbalancer/config/applicationprofiles/" + $ApplicationProfile
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ContentType "application/xml" -ErrorAction:Stop
[xml]$sxml = $r.Content
$OldCertificateId = $sxml.applicationProfile.clientSsl.serviceCertificate
$sxml.applicationProfile.clientSsl.serviceCertificate = $NewCertificateId[2]
$r = Invoke-WebRequest -Uri $Uri -Method Put -Headers $head -ContentType "application/xml" -Body $sxml.OuterXML -ErrorAction:Stop

##Delete old certificate from the Edge
$Uri = "https://$NSXManager/api/2.0/services/truststore/certificate/" + $OldCertificateId
$r = Invoke-WebRequest -URI $Uri -Method Delete -Headers $head -ContentType "application/xml" -ErrorAction:Stop

##Update vCloud Director with new certificates

$VcdSession = Connect-CIServer $Vcd -User $VcdAdmin -Password $VcdPassword

$Uri = "https://"+$Vcd+"/api/admin/extension/settings/general"
$head = @{"x-vcloud-authorization"=$VcdSession.SessionSecret} + @{"Accept"="application/*;version=33.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

$sxml.GeneralSettings.RestApiBaseUriPublicCertChain = $LBCertificate + $IssuerCert + $RootCert
$sxml.GeneralSettings.SystemExternalAddressPublicCertChain = $LBCertificate + $IssuerCert + $RootCert

$r = Invoke-WebRequest -URI $Uri -Method Put -Headers $head -ContentType "application/vnd.vmware.admin.generalSettings+xml" -Body $sxml.OuterXML -ErrorAction:Stop

vCloud Director with TLS-only Connection with External Database

Very brief blog post to document how to install vCloud Director with external database that does not support plain text connections.

In general the process is to do the initial set up with plain text DB connection and then switch to TLS – see the official docs here. That will however not work if the external database supports only TLS connection.

Instead this process must be used:

  1. Import DB certificate (unless it is publicly signed) to cell default JRE keystore.
  2. Use unattended configuration.


# /opt/vmware/vcloud-director/jre/bin/keytool --import -trustcacerts -keystore /opt/vmware/vcloud-director/jre/lib/security/cacerts -alias psql -file /opt/vmware/vcloud-director/etc/psql.crt


Enter keystore password: changeit


Owner: CN=

Issuer: CN=

Serial number: cb64ae0954184182

Valid from: Fri Nov 22 14:10:39 GMT 2019 until: Sat Nov 21 14:10:39 GMT 2020 Certificate fingerprints:

MD5:  04:4F:8F:C5:9C:CC:D5:E8:F1:50:C1:85:51:D4:FB:AD

SHA1: 22:53:FF:71:A7:EC:9B:D1:74:79:D5:95:46:71:F6:38:A7:E7:F8:4E

SHA256: 08:7C:27:B4:FB:32:04:DE:AF:BB:FE:9D:47:1D:38:46:C8:F4:7C:69:73:DE:8D:CB:BD:2A:A5:B2:11:12:68:DD

Signature algorithm name: SHA256withRSA

Subject Public Key Algorithm: 2048-bit RSA key

Version: 3




#1: ObjectId: Criticality=false AuthorityKeyIdentifier [ KeyIdentifier [

0000: 15 EA 78 3F 71 DD 34 D4   15 F0 C8 03 F7 76 1A 0B  ..x?q.4......v..

0010: 64 B2 A6 6E                                        d..n




#2: ObjectId: Criticality=false BasicConstraints:[





#3: ObjectId: Criticality=false SubjectKeyIdentifier [ KeyIdentifier [

0000: 15 EA 78 3F 71 DD 34 D4   15 F0 C8 03 F7 76 1A 0B  ..x?q.4......v..

0010: 64 B2 A6 6E                                        d..n




Trust this certificate? [no]:  yes

Certificate was added to keystore



# /opt/vmware/vcloud-director/bin/configure --unattended -dbhost <DB IP address> -dbname vcloud -dbpassword vcloud -dbtype postgres -dbuser vcloud --database-ssl true –dbport 5423 -ip <cell-ip> --primary-port-http 80 --primary-port-https 443 -cons <cell-ip> --console-proxy-port-https 8443 -k /opt/vmware/vcloud-director/etc/certificates.ks -w <keystore password> -g


Database configuration complete.


# /opt/vmware/vcloud-director/bin/cell-management-tool system-setup --email --full-name 'System Admin' --installation-id 33 --password 'VMware1!' -system-name vcd --unattended --user administrator

Creating admin user.

Setting system details.

Completing system setup.

System setup is complete.

vCloud Director H5 UI Error: 431 Request Header Fields Too Large

This is just a short blog post to describe an issue you might get with the tenant or portal HTML UI in vCloud Director where you will see errors in the browser related to request header fields too large.

You will see it more likely with Chrome browser and if your cloud domain is shared with other services. The root cause is that the browser API calls will stop working once the request header gets larger than 8 KBs. While 8 KBs seems like big enough size especially as the request headers vCloud Director uses contain only session ID, JWT token and possibly load balancers headers it also includes all the browser cookies applicable to the vCloud Director domain stored by other web services.

The temporary fix is for the end-user to delete her browser cookies. But is there something the provider could do?

In our case we saw the situation where the vCloud Director instance was on * domain and the browser contained lots of large OAM cookies related to VMware Single Sign-On solution. While those cookies are essential for multiple VMware internal applications, there is no reason for vCloud Director to receive them in every API request. One way how to block the cookies and thus decrease the request header size is to remove them at the load balancer. With NSX-V load balancer this can be accomplished by utilizing SSL L7 termination and an application rule (see my older blog post how to configure NSX-V Edge Load balancer).

In my case the application rule I use is:

Update 2019/10/24: The initial rule would remove all Cookies. I have now amended it with another rule that removes all but vcloud_session_id and vcloud_jwt cookies if they are present.

reqirep ^Cookie:\s.*(vcloud_session_id=[^;]*)|(vcloud_jwt=[^;]*) Cookie:\ \1;\ \2
reqidel ^Cookie:.*OAM*

which deletes all cookies from the request header starting with OAM string


vCloud Director 10: NSX-T Integration


vCloud Director relies on NSX network virtualization platform to provide on-demand creation and management of networks and networking services. NSX for vSphere has been supported for long time and vCloud Director allows most of its feature to be used by its tenants. However as VMware slowly shifts away from NSX for vSphere and pushes forward modern, fully rewritten NSX-T networking platform, I want to focus in this article on its integration with vCloud Director.


Let me start with highlighting that NSX-T is evolving very quickly. It means each release (now at version 2.5) adds major new functionality. Contrast that with NSX-V which is essentially feature complete in a sense that no major functionality change is happening there. The fast pace of NSX-T development is a challenge for any cloud management platforms as they have to play the catch up game.

The first release of vCloud Director that supported NSX-T was 9.5. It supported only NSX-T version 2.3 and the integration was very basic. All vCloud Director could do was to import NSX-T overlay logical segments (virtual networks) created manually by system administrator. These networks were imported into a specific tenant Org VDC as Org VDC networks.

The next version of vCloud Director – 9.7 supported only NSX-T 2.4 and from the feature perspective not much had changed. You could still only import networks. Under the hood the integration however used completely new set of NSX-T policy based APIs and there were some minor UI improvements in registering NSX-T Manager.

The current vCloud Director version 10 for the first time brings on-demand creation of NSX-T based networks and network services. NSX-T version 2.5 is required.

NSX-T Primer

While I do not want to go too deep into the actual NSX-T architecture I fully expect that not all readers of this blog are fully familiar with NSX-T and how it differs from NSX-V. Let me quickly highlight major points that are relevant for topic of this blog post.

  • NSX-T is vCenter Server independent, which means it scales independently from vCenter domain. NSX-T essentially communicates with ESXi hosts directly (they are called host transport nodes). The hosts must be prepared with NSX-T vibs that are incompatible with NSX-V which means a particular host cannot be used by NSX-V and NSX-T at the same time.
  • Overlay virtual networks use Geneve encapsulation protocol which is incompatible with VXLAN. The concept of Controller cluster that keeps state and transport zone is very similar to NSX-V. The independence from VC mentioned in the previous point means vSphere distributed switch cannot be used, instead NSX-T brings its own N-VDS switch. It also means that there is concept of underlay (VLAN) networks managed by NSX-T. All overlay and underlay networks managed by NSX-T are called logical segments.
  • Networking services (such as routing, NATing, firewalling, DNS, DHCP, VPN, load balancing) are provided by Tier-0 or Tier-1 Gateways that are functionally similar to NSX-V ESGs but are not instantiated in dedicated VMs. Instead they are services running on shared Edge Cluster. The meaning of Edge Cluster is very different from the usage in NSX-V context. Edge Cluster is not a vSphere cluster, instead it is cluster of Edge Transport Nodes where each Edge Node is VM or bare metal host.
  • While T0 and T1 Gateways are similar they are not identical, and each has specific purpose or set of services it can offer. Distributed routing is implicitly provided by the platform unless a stateful networking service requires routing through single point. T1 GWs are usually connected to single T0 GW and that connection is managed automatically by NSX-T.
  • Typically you would have one or small number of T0 GWs in ECMP mode providing North-south routing (concept of Provider Edge) and large number of T1 GWs connected to T0 GW, each for a different tenant to provide tenant networking (concept of Tenant Edge).

vCloud Director Integration

As mentioned above since NSX-T is not vCenter Server dependent, it is attached to vCloud Director independently from VC.

(Geneve) network pool creation is the same as with VXLAN – you provide mapping to an existing NSX-T overlay transport zone.

Now you can create Provider VDC (PVDC) which is as usual mapped to a vSphere cluster or resource pool. A particular cluster used by PVDC must be prepared for NSX-V or NSX-T and all clusters must share the same NSX flavor. It means you cannot mix NSX-V clusters with NSX-T in the same PVDC. However you can easily share NSX-V and NSX-T in the same vCenter Server, you will then just have to create multiple PVDCs. Although NSX-T can span VCs, PVDC cannot – that limitation still remains. When creating NSX-T backed PVDC you will have to specify the Geneve Network Pool created in the previous step.

Within PVDC you can start creating Org VDCs for your tenants – no difference there.

Org VDCs without routable networks are not very useful. To remedy this we must create external networks and Org VDC Edge Gateways. Here the concept quite differs from NSX-V. Although you could deploy provider ECMP Edges with NSX-V as well (and I described here how to do so), it is mandatory with NSX-T. You will have to pre-create T0 GW in NSX-T Manager (ECMP active – active is recommended). This T0 GW will provide external networking access for your tenants and should be routable from the internet. Instead of just importing external network port group how you would do with NSX-V you will import the whole T0 GW in vCloud Director.

During the import you will also have to specify IP subnets and pools that the T0 GW can use for IP sub-allocation to tenants.

Once the external network exist you can create tenant Org VDC Edge Gateways. These will be T1 GWs instantiations into the same NSX-T Edge Cluster as the T0 GW they connect to. Currently you cannot chose different NSX-T Edge Cluster for their placement. T1 GWs are always deployed in Active x Standby configuration, the placement of active node is automated by NSX-T. The router interlink between T0 and T1 GWs is also created automatically by NSX-T.

During the Org VDC Edge Gateway the service providers also sub-allocates range of IPs from the external network. Whereas with NSX-V these would actually be assigned to the Org VDC Edge Gateway uplink, this is not the case with NSX-T. Once they are actually used in a specific T1 NAT rule, NSX-T will automatically create static route on the T0 GW and start routing to the correct T1 GW.

Tenant Networks

There are four types of NSX-T based Org VDC networks and three of them are available to be created via UI:

  • Isolated: Layer 2 segment not connected to T1 GW. DHCP service is not available on this network (contrary to NSX-V implementation).
  • Routed: Network that is connected to T1 GW. Note however that its subnet is not announced to upstream T0 GW which means only way to route to it is to use NAT.
  • Imported: Existing NSX-T overlay logical segment can be imported (same as in VCD 9.7 or 9.5). Its routing/external connectivity must be managed outside of vCloud Director.
  • In OpenAPI (POST /1.0.0/OrgVdcNetwork) you will find one more network type:  DIRECT_UPLINK. This is for a specific NFV use case. Such network is connected directly to T0 GW with external interface. Note this feature is not officially supported!

Note that only Isolated and NAT-routed networks can be created by tenants.

As you can see it is not possible today to create routed advertised Org VDC network (for example for direct connect use case when tenant wants to route from on-prem networks to the cloud without using NAT). These routed networks would require dedicated T0 GW for each tenant which would not scale well but might be possible in the future with VRF support on T0 GWs.

Tenant Networking Services

Currently the following T1 GW networking services are available to tenants:

  • Firewall
  • NAT
  • DHCP (without binding and relay)
  • DNS forwarding
  • IPSec VPN: No UI, OpenAPI only. Policy and route based with pre share key is supported. (Thanks Abhi for the correction).

All other services are currently not supported. This might be due to NSX-T not having them implemented yet, or vCloud Director not catching up yet. Expect big progress here with each new vCloud Director and NSX-T release.

Networking API

All NSX-T related features are available in the vCloud Director OpenAPI (CloudAPI). The pass through API approach that you might be familiar with from the Advanced Networking NSX-V implementation is not used!

Feature Comparison

I have summarized all vCloud Director networking features in the following table for quick comparison between NSX-V and NSX-T.

Update 2019/10/09: Added two entries related to external network metering and rate limiting.

What’s New in vCloud Director 10

With clockwork efficiency after less than 6 months there a is new major release of vCloud Director – version 10. As usual, I will try to summarize all the new functionality compared to the previous release 9.7. I have similar posts about 9.7, 9.5 and 9.1 so you can get quickly up to speed if you are not familiar with them as well.

User Interface

From the tenant UI perspective the HTML5 UI (/tenant) has been evolving to add missing legacy (Flex) UI functionality. You can now customize VM network adapter during VM creation, change user password and user settings.

The top ribbon bar now provides more information and new search option.

New universal tenant login page (/login) was added:

Tenant UI also provides new functionality such as NSX-T network management.

The provider HTML5 UI now contains all the actions the cloud service provider needs to do (various Settings screens, tenant migration, …), so the legacy Flex UI is actually disabled by default. There are still however some missing features like direct VM import from vCenter Server, Org VDC template creation or edit of VM guest properties.

If necessary, you can enable Flex UI with this command (run on any cell and reboot them all):

cell-management-tool manage-config -n flex.ui.enabled -v true

Among some of the new Provider UI features are:

  • compute policy management (VM Sizing Policies and Provider VDC specific VM Placement Policies).

  • NSX-T provider actions such as Geneve network pool creation, import of T0 for external networks and Org VDC Edge Gateway management including quite useful quick external IP addresses sub-allocation (available for NSX-V Edge Gateways in API as well).
  • SDDC Proxy and token management (CPOM feature)

NSX-T Support

As hinted above, NSX-T integration has been improved massively. I am going to deep dive into the topic in a separate article, so let me cover it here very quickly.

In the previous vCloud Director releases the system administrator could only import NSX-T based networks (overlay logical segments) as tenant Org VDC networks and that was it. In the current release the tenants now can create NAT-routed and isolated networks with firewalling, DHCP and DNS forwarding services provided by NSX-T T1 Gateways. The vCloud Director networking objects did not change much which means there should not be major difference between NSX-V backed and NSX-T backed Org VDC from the usability perspective. However, there is not full feature parity between NSX-V and NSX-T functionality; sometimes it is due to NSX-T not providing these features (SSL VPN), sometimes due to vCloud Director not yet caught up. Expect more in the future as this is a journey.

Note: Only NSX-T version 2.5 is supported by vCloud Director 10.0.


  • API version has been bumped up to 33.0, while versions 27.0-32.0 are still supported but 27.0 and 28.0 are marked for deprecation.
  • There is a new API authentication mechanism. The OpenAPI provides two different authentication endpoints (one for provider: /cloudapi/1.0.0/sessions/provider the other for tenants /cloudapi/1.0.0/sessions). You can disable for API version 33.0 the old authentication mechanism (/api/sessions) with the following command:cell-management-tool manage-config -n vcloud.api.legacy.nonprovideronly -v trueThis means it is now quite easy with Web Application Firewall to protect the provider API authentication from the internet.
  • OpenAPI provides new (faster) way to collect audit events from vCloud Director via AuditTrail API call. Note that vCloud Director now stores audit events only for limited time in order to keep the database size and query speed manageable.
  • The NSX-T related networking APIs are not pass-through as was the case with NSX-V and instead use the OpenAPI calls.
  • vCloud Director Appliance API: each appliance node now provides its own appliance API to get database state provide by replication manager. It is also possible to remotely execute database standby node promotion  and thus automate database failover with external tooling or load balance to the active database node for 3rd party database usage.
    GET https://<appliance IP>:5480/api/1.0.0/is_primary
    GET https://<appliance IP>:5480/api/1.0.0/nodes

    POST https://<appliance IP>:5480/api/1.0.0/nodes/<node name>/promote

Other Features

  • Improved vRealize Orchestrator (vRO) integration. Two more custom properties vcd_sessionToken and _vcd_apiEndpoint can be passed from vCloud Director to vRO workflow so the workflow during its execution can connect in the particular user context via the vCloud Director Plugin to vCloud Director and provide access only to those objects the user has access to.
    The spelling of two other custom properties was fixed from _vdc_userName and _vdc_isAdmin to _vcd_userName and _vcd_isAdmin (but is still backwards compatible).
    The new vRO vCloud Director Plugin now also supports vRO Clustering so the vCloud Director connection is automatically shared across vRO nodes.
  • RBAC support for NSX-V Edge ECMP and DNS features. The former was asked by many providers in order to keep NSX-V licensing at Advanced edition and not to get accidentally bumped to Enterprise edition if tenant enabled ECMP on its Org VDC Edge Gateway.
  • Legacy Org VDC allocation models can now be changed to flex allocation model which allows for switching allocation models of existing Org VDCs.
  • When system administrator enables Distributed Firewall via UI it is possible to choose if the new tenant firewall section should be created at the bottom (and not on top by default). This was before possible only via API.

  • MS SQL is no longer supported as vCloud Director database. To use vCloud Director version 10.0 you must either use the appliance form factor with its embedded PostgreSQL database or an external PostgreSQL. Migration is supported.
  • Compatible VCD-CLI version 22.0 and pycloud 21.0 SDK were released as well.