Infrastructure as a Code using Terraform: AWS, vSphere

Terraform AWS vSphere

I got introduced to Terraform a few months back when trying to solve a problem in the AWS cloud. Since then I have had discussions with multiple other Automation and DevOps professionals in other companies, and the common problem everyone seems to have is Infrastructure Provisioning and Management. This task especially becomes exceedingly cumbersome to tackle with other Enterprise priorities. There are a number of popular solutions out there, but Terraform seems to be very popular and gaining adoption quite rapidly.

Though it's still very new, it is quite powerful. As a personal experience, using Terraform with AWS was very easy, but I cannot say the same thing about using its vSphere provider, which is maybe also because of the fact that AWS has many defaults configured, which vSphere does not. Plus, AWS also has its own AWS CloudFormation, which is awesome! vSphere, unfortunately, does not seem to have any of their own service or tool which allows users to manage their Infrastructure as a Code.

In this post, I will go over the basic configuration, and share my opinions of what I perceive of Terraform. If you would like to, you are welcome to download the code/configuration files from my GitHub repo. They should help you get started.

There is a variety of cool stuff you can do with Terraform: define inputs/outputs, specify resource dependencies, push redundant configurations to modules, etc. I will only go over the very basic stuff here.

What is Terraform?

Terraform Install:

Build Infrastructure:


  • terraform.tfvars: This file is used to store all the variables of the configuration. The values set in this file override the settings for variables with the same name in the .tf files. This file is usually used to store protected information like provider credentials, server information, etc., and not checked in the version control. Say, if you are using git, your .gitignore file should have ‘terraform.tfvars’
  • * .tf : This is the file that actually contains all the resources. You may have one or more files, which allows you to break down sections of infrastructure(e.g. containing all server VM resources, containing VM resources for client machines, Linux/Windows client configuration, etc.), and maintain each in a separate file. You can define/configure your provider, variables, data, resources, etc. in these files.

There are two main sets of configuration:

Configuring the provider to use:

This is usually done by specifying which Cloud you want to deploy on, and the credentials to authenticate for the same. Note in the example below, that the configuration is provider specific.
As an example, for AWS:

provider "aws" {
access_key = "${var.AWS_ACCESS_KEY}"
secret_key = "${var.AWS_SECRET_KEY}"
region = "${var.AWS_REGION}"

To authenticate with vSphere, it would be like:

provider "vsphere" {
vsphere_server = "${var.vsphere_vcenter}"
user = "${var.vsphere_user}"
password = "${var.vsphere_password}"
allow_unverified_ssl = "${var.vsphere_unverified_ssl}"

Configuring what resources you want to deploy:

I have seen a lot of people mention on multiple occasions that Terraform is ‘Cloud Agnostic’, but I don’t quite agree with that. I think this statement is false because you need an understanding of how the cloud provider works, its pre-requisites, etc when you are using Terraform. Note that Terraform only provides a common interface to deploy resources.

Let's consider a simple example of deploying a VM.

AWS: When you are deploying an EC2 instance from an AMI in your account, by default it goes in the default VPC, default subnet, uses the default NACL, default SG, gets its IP and Hostname assigned automatically. Since there are a lot of defaults, deploying a VM that can connect to the internet requires very little custom configuration. The resource for such an instance will look like this in Terraform HCL:

resource "amol_aws_instance" "test-ec2-instance" {
ami = "${data.ami_id}"
instance_type = "${data.instance_type}"
# Note that here the values for confuguration are getting pulled from data objects/blocks

vSphere: In vSphere environment, there are very few defaults, and you have to provide appropriate values to configure your VM. There is nothing like a default network, default host, etc. You may be able to build that for yourself by implementing a modular design, but I will not go through that here. The resource for a VM in vSphere will look like this in Terraform HCL:

resource "vsphere_virtual_machine" "amol-vm" {
# VM placement #
name = "${data.vm_name}"
resource_pool_id = "${}"
datastore_id = "${}"

# Guest OS #
guest_id = "${data.vsphere_virtual_machine.template.guest_id}"

# VM storage #
disk {
label = "${data.vm_name}.vmdk"
size = "${data.vsphere_virtual_machine.template.disks.0.size}"
thin_provisioned = "${data.vsphere_virtual_machine.template.disks.0.thin_provisioned}"
eagerly_scrub = "${data.vsphere_virtual_machine.template.disks.0.eagerly_scrub}"

# VM networking #
network_interface {
network_id = "${}"
adapter_type = "${data.vsphere_virtual_machine.template.network_interface_types[0]}"

# Customization of the VM #
clone {
template_uuid = ${}"

# Customization is required to set hostname, IP.
customize {
linux_options {
host_name = "${data.vm_name}"
time_zone = "${var.vsphere_time_zone}"
domain = "${var.vsphere_domain}"

network_interface {
ipv4_address = "${var.vsphere_ipv4_address}"

# this will to allow to specify multiple values for dns servers
dns_server_list = "${split("-", var.vsphere_dns_servers)}"
dns_suffix_list = ["${var.vsphere_domain}"]

# Note that here the values for confuguration are getting pulled from data objects/blocks


The ‘init’ command will automatically download and install any provider binary for the providers in use within the configuration.

terraform init

If your provider configuration is for AWS (provider “aws”), then it will download the plugin and authenticate with AWS. It will do the same thing, if it's a different provider, say vSphere (provider “vsphere”).

Apply Changes:

terraform plan

To apply the changes to your infrastructure, use the ‘apply’ command. This will create the infrastructure you have specified in your configuration files. If there are changes made to existing infrastructure in your configuration files, ‘apply’ will update your infrastructure accordingly.

terraform apply 

Once deployed, you can see your deployment using the ‘show’ command:

terraform show 

Once the deployment is done, a .tfstate file is created. This is a state file is extremely important; it keeps track of the IDs of created resources so that Terraform knows what it is managing.

Break Down:

terraform destroy

Learning Terraform has been a great experience! I can definitely see a lot of benefits to moving to Infrastructure as Code model. In this post, I have only talked about an example of using a pre-existing VM template, but Terraform can also be coupled with Packer (another tool developed by HashiCorp)to create VM images/templates that you can use to deploy from.

In case you wish to access the original source code files, please refer to my GitHub repo. I hope you enjoyed the post and were able to find the information you were looking for! :-)

Look forward to waking up every day to an interesting challenge!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store