Deploying a VMware Cloud Director Tenant with Terraform

I have been using Terraform for many years to turn a VMware Cloud Director tenant build into something repeatable: create the tenant, create the Org VDC, add the edge and routed network, then deploy enough application-shaped infrastructure to prove the tenant is actually usable. I’ve finally got around to cleaning it up and publishing it. A second post to build out a new Tenant in VMware Cloud Foundation Automation will be published shortly for the same Demo tenant!

The example code is here:

GitHub: wynner/scripts/vcd/terraform/tenant-demo

Safety Warning

Use these Terraform files with care. They create, change, and destroy infrastructure objects. Treat them as example code and test them only in non-production environments unless you have reviewed and adapted the configuration for your own VMware Cloud Director platform.

What The Demo Builds

The demo builds a tenant from the provider side and then adds application-facing objects inside it. In the current version it creates:

  • a tenant organization and Flex organization VDC
  • an NSX-T edge gateway and routed organization network
  • an initial tenant organization administrator
  • a tenant catalog library
  • a shared VCD Named Disk
  • two empty database VMs, db01 and db02
  • per-VM 10 GB NVMe internal disks on the Performance storage profile
  • a demo VM security group and security tag
  • SSH DNAT rules and outbound SNAT
  • tenant IP sets for admin sources, DNS, and NTP services
  • tenant-scoped application port profiles for DNS, NTP, and HTTPS
  • an ordered NSX-T edge firewall policy
  • optional LDAP-backed tenant user imports

The VMs are deliberately empty dummy machines. This keeps the example focused on VCD tenant and application infrastructure rather than on operating system customization or guest configuration. You can of course simply clone a template with the right edits.

No Hard-Coded Environment IDs

One of the cleanup goals was to make the code useful outside my lab. The example asks for textual display names such as the Provider VDC, network pool, Provider Gateway, IP Space, edge cluster, storage policy, and VM sizing policy. It does not expect users to paste UUIDs or URNs into the Terraform files. That was my biggest blocker in releasing the code before now.

The Terraform code uses data sources to look up provider-side objects at plan and apply time. The variables also validate that those inputs are not UUIDs or URNs, so a user gets an early error if they paste an internal identifier instead of a VCD display name.

Files In The Example

  • main.tf configures the VCD provider.
  • variables.tf keeps environment values out of the resource code.
  • data.tf looks up existing provider-side objects.
  • tenant.tf builds the tenant foundation.
  • application.tf builds the catalog, shared disk, VM pair, NAT, firewall, IP sets, application port profiles, security group, and firewall policy.
  • terraform.tfvars.example shows the values to supply for a lab without including secrets.

Shared Disk Ordering

The two VM resources are intentionally split into a primary VM and a secondary VM. The secondary VM depends on the primary VM, so the shared Named Disk is attached to one VM first and then the other. That keeps the VCD shared-disk operation serialized while allowing unrelated resources to use Terraform’s normal parallelism.

That dependency matters. Without it, a high-parallelism apply can make both VMs try to attach the same Named Disk at the same time, and VCD can reject the operation as busy and not complete the build.

Apply And Teardown Notes

The normal workflow is straightforward:

terraform init
terraform fmt
terraform validate
terraform plan -out tfplan
terraform apply tfplan

In my lab, the VCD and vCenter combination would not hot-add the NVMe internal disks to already powered-on empty VMs. The clean approach was to create the VMs powered off, add the NVMe disks, then set application.power_on=true and apply again to power on db01 and db02.

For teardown against VCD 39.1, there is a deliberate safety feature in that you have to explicitly disable the Org VDC with Terraform before destroying the tenant. VCD rejects deletion while the VDC is enabled, but the provider can remove a disabled VDC cleanly.

terraform apply -target=vcd_org_vdc.tenant -var tenant_vdc_enabled=false
terraform destroy

Why This Is Useful

This is not just a “create a VM” example. It demonstrates how Terraform can describe the tenant boundary, the edge, the network, the storage policy, reusable firewall objects, NAT, security grouping, and a small application topology in one repeatable graph.

That is the interesting part for me: the same code can build the tenant foundation and the first application-shaped objects inside that tenant. It gives a provider or lab operator a clean way to show how a Cloud Director tenant can be delivered from code instead of from a long sequence of UI clicks.

I’m still using similar code with customers in managing their VCD environments. There’s even some customers who use Terragrunt to manage their tenants at scale! Impressive to see in action!