TeKanAid

Dark

Table of Contents
HashiCorp Vault 101 - Certified Vault Associate
Get started with HashiCorp Vault and prepare for your Vault Associate Exam
Terraform 101 - Certified Terraform Associate
Learn all you need to know to ace the Terraform Associate Exam and go beyond the certification

Terraform vSphere Windows Example to Join an AD Domain


Stop using outdated methods to create Windows virtual machines in vSphere. Instead, consider using Infrastructure as Code with Terraform to automate the process. In this blog post, you will learn how to do this and also how to join the Windows virtual machine to an active directory domain.

IaCHashiCorpTerraformPackerVMwareWindows
Created: December 14, 2021 | Updated: January 27, 2023

Video

Below is a video explanation and demo.

Terraform vSphere Windows Example to Join an AD Domain

Video Chapters

You can skip to the relevant chapters below:

  • 00:00 - Introduction
  • 01:26 - Whiteboard Setup
  • 04:32 - vSphere UI
  • 05:49 - Terraform Cloud UI
  • 07:39 - Variable Sets New to TFC
  • 09:06 - Windows Server AD Domain Joined
  • 10:55 - Terraform Main.tf File Walk-through
  • 13:15 - Packer Used for the Template
  • 14:20 - Closing

Overview

In previous blog posts, we've worked with the VMware vSphere provider. I'm still of the opinion that there is a lot of infrastructure automation efficiencies to be realized in on-premises environments running VMware. The appeal of Terraform is that it is cloud/platform agnostic. Once you understand how the logic works, in theory, it should be a relatively painless transition to working with a different provider. If you're not familiar with what a provider is, think of it as a plugin into the Terraform core that allows you to talk to the API of the cloud/platform you're provisioning on. These providers don't necessarily need to be cloud-related. Some examples of these providers are for: Azure, GCP, AWS, VMware vSphere, Datadog, F5 networks, and so on. Many vendors build these providers to facilitate access to their APIs via Terraform.

I did some research and found that there aren't too many terraform vSphere Windows examples out there. So I decided to create one and demonstrate it. Our aim here is to build a terraform vSphere Windows server 2019 virtual machine and add it to the few terraform vsphere provider examples available. We will also show how to join this VM to an active directory domain during the build process. So let's get started.

Code

Get FREE access to the source code by subscribing to my newsletter
You only need to subscribe once. Already subscribed? Enter your email to get instant access to the code.

Pre-requisites

The following is required to follow along:


Setup

Below is our setup diagram. It is fairly straightforward. We are running Terraform on Terraform Cloud (TFC). GitLab is our version control system (VCS). We are using the VCS workflow in TFC. This allows us to commit and push code into GitLab which will automatically trigger a terraform init, plan, and apply. TFC also can provide cost estimates and run some policy checks. Since we're provisioning on-prem, cost estimation doesn't apply. Also, we are not creating policies in this example.

We are running a cloud agent internally in the form of a docker container. This agent polls TFC regularly asking if there is a job ready to provision. Cloud agents are a TFC business tier feature that allows us to provision on-prem without having to open a firewall inbound. You could sign up for a trial or use TFC with local execution in this example.

Setup Diagram

Terraform vSphere Windows Example Configuration

In this section, we will explore the main points in the Terraform configuration. You can get access to the full code here.

Terraform Folder Structure

Below is a screenshot of our folder structure. It's flat, one folder with a few files.

Folder Structure

Terraform Initialization

In the main.tf file, we will need vSphere admin user credentials to be defined in the vsphere provider block. Basically a name and password of a vSphere user with access to vCenter to create VMs by cloning templates. These credentials are defined as variables and need to be stored securely in Terraform Cloud (TFC) encrypted at rest. If you are not using TFC and using Terraform CLI open-source or TFC local execution, then you could use a terraform.tfvars file, but make sure you don't check that into git. My personal recommendation is to use TFC as it stores both the credentials and the state file securely in a central location.

The very first step to using Terraform is to initialize things. So if you are using the CLI, you first need to run the command terraform init to download terraform vsphere provider. If you are using TFC with the VCS workflow, upon a commit and a push, TFC will run terraform init in TFC's own infrastructure. It will then proceed with the terraform plan and other steps shown in the video demo above.

Terraform Variables

Take a close look at the variables.tf file. You will see all the necessary Terraform variables there. These variables are referenced in the main.tf file. One example of a variable I'm using is a Terraform dns_server_list example and is found in the dns_server_list variable. Notice that we declare the variables in the variables.tf file and assign them in the values.auto.tfvars file. TFC doesn't allow you to use a terraform.tfvars file. So you need to use a filename with this format: *.auto.tfvars.

Terraform Data Blocks

In addition to variables, we are also making use of the data blocks in Terraform. A data block allows you to retrieve data, whereas a resource block allows you to provision a resource. A couple of examples of data blocks are found in the main.tf file:

  1. Datacenter block
data "vsphere_datacenter" "dc" {
  name = "Datacenter"
}

Notice the first argument vsphere_datacenter is a reserved keyword used by the vSphere provider. The second one dc is an arbitrary name you can give it and will be referenced in other blocks in your Terraform configuration.

  1. Datastore block
data "vsphere_datastore" "datastore" {
  name          = "Datastore2_NonSSD"
  datacenter_id = data.vsphere_datacenter.dc.id
}

Notice in this datastore block we are referencing the datacenter block's IP like this: data.vsphere_datacenter.dc.id

Terraform vSphere Virtual Machine Resource Block

The vsphere_virtual_machine resource block is what actually provisions the Windows Server 2019 VM. The configuration is straightforward and most parameters are referencing variables already defined. We also have the ability to provision multiple VMs in parallel with the count parameter. Terraform saves us time by doing so. This count parameter is referencing the vm-count variable. In my example, I'm only using a vm-count of 1, but you could change this to however many VMs you need to create at the same time. Now let's take a look at the customization block that allows us to define a few parameters for our VM.

Terraform Customization Block

You can find the entire code here, but let's focus our attention on the customize block for the Windows VM.

resource "vsphere_virtual_machine" "vm" {
...truncated
customize {
      windows_options {
        computer_name = "${var.vm-name}-${count.index + 1}"
        # workgroup     = "test"
        join_domain           = var.domain
        domain_admin_user     = var.domain_admin_user
        domain_admin_password = var.domain_admin_password
        admin_password        = var.local_adminpass
        # product_key           = var.productkey
        # organization_name     = var.orgname
        # run_once_command_list = var.run_once
        # auto_logon            = var.auto_logon
        # auto_logon_count      = var.auto_logon_count
        # time_zone             = var.time_zone
        # product_key           = var.productkey
        # full_name             = var.full_name
      }
      network_interface {
        ipv4_address    = var.ipv4_addresses[count.index]
        ipv4_netmask    = var.ipv4_netmasks[count.index]
        dns_server_list = var.dns_server_list
        dns_domain      = var.domain
      }
      ipv4_gateway = var.vmgateway
      timeout = 30

    }
...truncated

Notice the 3 parameters below which are essential in joining this VM to the Windows domain:

  1. join_domain - Domain used for DNS and Active Directory
  2. domain_admin_user - Domain username with necessary privileges to join a computer to the domain
  3. domain_admin_password - Domain password with necessary privileges to join a computer to the domain

There are other parameters that you can define such as the product_key to activate Windows. You could also use a workgroup instead of a domain if that's what you need.

Terraform Clones a Packer Generated vSphere Template

Terraform can be used to clone an existing vSphere template image. We had already created a vSphere template image with another HashiCorp tool called Packer. Packer is a great tool to speed up the creation of VM images. Similar to Terraform, Packer is cloud/platform agnostic and can be used with other clouds such as AWS, Azure, and GCP. Here is a link to learn how to use Packer to Create a Windows Server 2019 image.

Below we use a data block to call on the image already created, then we use a clone block inside the resource block to reference this template and use it to build our VM.

...truncated
data "vsphere_virtual_machine" "template" {
  name          = var.windows_template
  datacenter_id = data.vsphere_datacenter.dc.id
}
...truncated
resource "vsphere_virtual_machine" "vm" {
...truncated
clone {
    template_uuid = data.vsphere_virtual_machine.template.id
...truncated
}

Logging in as an Active Directory User

Once Terraform finishes provisioning our VM, we can move on to the next step of testing. Let's test by logging into the new Windows Server 2019 VM using an already existing active directory (AD) user. Below is a screenshot from my domain controller showing the user sam in the domain adhome.

Active Directory User Profile

After logging into the domain with the following username: adhome\sam let's take a look at the new Windows 2019 server information:

Computer Information Showing the AD Domain

As you can see in the screenshot above, our VM is successfully joined to the domain. Congratulations, you did it!

Conclusion

In this post, we learned how to build a Terraform vSphere Windows Server 2019 VM and join it to an AD Domain. We saw the benefits of using Terraform for infrastructure as code and how the process is well documented in code and repeatable. We were able to customize our VM by configuring the Computer Name, IP address, the Windows domain to join and a few other parameters.

We also used a Windows Server 2019 image that was built with another HashiCorp tool called Packer. Here is the link to learn how to use Packer to Create a Windows Server 2019 image.

If you would like to see a Linux example in VMware vSphere, we also created a post on building a Ubuntu 20.04 image in vSphere. Then another post to use this image to Build a Kubernetes k3s Cluster in vSphere with Terraform and Packer.

References


Other Posts
Terraform for Beginners - A Beginner's Guide to Automating Cloud Infrastructure
Terraform vs Ansible - Demo the Differences - Part 2
Terraform vs Ansible - Learn the Differences - Part 1
HashiCorp Vault Backup and Restore Raft Snapshots from Kubernetes to AWS S3
AWS Lambda - Terraform Configuration Example with API Gateway
Securing the Future - DevSecOps Trends for 2023
36 Top DevOps Questions to Get You Started in 2023
Terraform to Create a Ubuntu 22.04 VM in VMware vSphere ESXi
HashiCorp Packer to Build a Ubuntu 22.04 Image Template in VMware vSphere
Migrate Secrets from AWS Secrets Manager to HashiCorp Vault with Python, Docker, and GitLab
Migrate Secrets from AWS Secrets Manager to HashiCorp Vault with Terraform
env0 - A Terraform Cloud Alternative
Terraform Import Example - AWS EC2 Instance
DevOps Engineer NOT on Linux? You're MISSING OUT!
HashiCorp Vault API Tutorial and Pro Tips
HashiCorp Vault Tutorial for Beginners
Create a Pihole Docker Ad Blocker with Ansible and Terraform
Terraform vSphere Windows Example to Join an AD Domain
Build a Kubernetes k3s Cluster in vSphere with Terraform and Packer
HashiCorp Packer to Build a Ubuntu 20.04 Image Template in VMware
Consul-Template to Automate Certificate Management for HashiCorp Vault PKI
HashiCorp Vault PKI Secrets Engine Demo for Certificate Management
Jenkins, Vault, Terraform, Ansible, and Consul Delivering an End-to-End CI/CD Pipeline
Secret Zero Problem Solved for HashiCorp Vault
Hashicorp Packer, Terraform, and Ansible to Set Up Jenkins
Hashicorp Vault Azure Secrets Engine - Secure Your Azure Resources
HashiCorp Waypoint - Will it Replace Your CI/CD?
HashiCorp Boundary - Make Sure Your Human To Machine Access Is Secure
HashiCorp Packer for VMware Ubuntu Templates and Terraform for building VMs
HashiCorp Packer VMware Windows Templates and Terraform for VMs
Webblog App Part 4 – HashiStack – Nomad Consul Vault Terraform
Webblog App Part 3 - Consul Connect Service Mesh
Webblog App Part 2 - Secrets Development Phases with Vault
Webblog App Part 1 - Infrastructure as Code with Terraform
Microservices Applications'​ Life Cycle
HashiCorp Vault 201 - Vault for Apps in Kubernetes
Learn how to use HashiCorp Vault for your applications in Kubernetes