Create vCenter Role for Packer using Terraform

In this blog post I would like to demonstrate how to create dedicated role for HashiCorp Packer and assign permissions on vCenter objects using Terraform.

Custom Packer Role

Most posts that demonstrate Packer use Administrator vCenter role to provision your Packer Images. This is good for demo or home lab usage, but not necessarily for production. In production you want to have just limited permission for account that provision your Packer Templates. In old times where Packer vSphere-iso provisioner was delivered and maintained by JetBrains group, a few people asked that question. What is minimum access rights that needs to be assigned to make Packer to provision VM images? The answer was create role named Packer and assign fallowing permissions to that role:

  • Datastore
    • Allocate space
    • Browse datastore
    • Low level file operations
  • Host
    • Configuration -> System Management
  • Network
    • Assign Network
  • Resource
    • Assign virtual machine to resource pool
  • Virtual Machine
    • All

Next assign vSphere account to that role as fallowing:

ObjectRolePropagation
DatacenterRead-OnlyNo
HostpackerNo
NetworkpackerYes
DatastorepackerYes
FolderpackerYes

I've decided to automate that process as much as possible using Terraform. Probably it would be easier to do it with PowerCLI but my goal is to learn Terraform as much as possible.

For this reason I've used Terrafrom vSphere Provider version 1.26

Unfortunately at time of writing this article Terraform vSphere Provider does not allowed me to create local vSphere accounts so you have to do it manually in vCenter Inventory. You can also use PowerCLI for that. In my example I've created local account named Packer@vsphere.local. Hopefully that's the only manual step you need to do, rest will be done by Terraform.

First, install Terraform. I use Windows so used Chocolatey to install Terraform binary. Once you have it, clone my GitHub repo. Under "01 - Terraform vCenter Role" you will find three files: main.tf file and two variable files. The one you are interested with is terrafrom.tfvars where you need to specify your vSphere objects values. In my case file looks like this:

 1username       = "administrator@vsphere.local"
 2password       = "VMware1!"
 3vcenter        = "vcsa01.lab.local"
 4datacenter     = "DC01"
 5cluster        = ["CL01"]
 6esxihost       = ["esx01.lab.local"]
 7datastore      = ["datastore1"]
 8network        = ["VM Network"]
 9folder         = ["/DC01/vm/Packer"]
10vsphereaccount = "vsphere.local\\Packer"

Square Brackets Values

You may wonder what the square brackets are and what they are for? Square brackets in variable file means those are treated as lists of values. Your Datacenter object may contain multiple clusters and those contain multiple ESXi hosts. Additionally different clusters usually contain different datastores, networks and folder structures. Normally you want to assign extended rights to be assigned on single ESXi object. This script supports it so means you can put multiple clusters, ESXihosts, datastores, networks and folders. The condition is that those must belong to same Datacenter object. So considering single DC that contain multiple clusters you put fallowing values:

 1username       = "administrator@vsphere.local"
 2password       = "VMware1!"
 3vcenter        = "vcsa01.lab.local"
 4datacenter     = "DC01"
 5cluster        = ["CL01", "CL02"]
 6esxihost       = ["esx01.lab.local", "esx02.lab.local"]
 7datastore      = ["datastore1", "datrastore2"]
 8network        = ["VM Network", "DPortGroup"]
 9folder         = ["/DC01/vm/Packer", "/DC01/vm/Packer1"]
10vsphereaccount = "vsphere.local\\Packer"

Apply configuration

Open folder where your Terraform configuration is stored and run terraform init command:

 1PS C:\Terraform\Role1\Packer vSphere Role> terraform init
 2
 3Initializing the backend...
 4
 5Initializing provider plugins...
 6- Checking for available provider plugins...
 7- Downloading plugin for provider "vsphere" (hashicorp/vsphere) 1.26.0...
 8
 9The following providers do not have any version constraints in configuration,
10so the latest version was installed.
11
12To prevent automatic upgrades to new major versions that may contain breaking
13changes, it is recommended to add version = "..." constraints to the
14corresponding provider blocks in configuration, with the constraint strings
15suggested below.
16
17* provider.vsphere: version = "~> 1.26"
18
19
20Warning: registry.terraform.io: This version of Terraform has an outdated GPG key and is unable to verify new provider releases. Please upgrade Terraform to at least 0.12.31 to receive new provider updates. For details see: https://discuss.hashicorp.com/t/hcsec-2021-12-codecov-security-event-and-hashicorp-gpg-key-exposure/23512
21
22
23
24Warning: Interpolation-only expressions are deprecated
25
26  on main.tf line 3, in provider "vsphere":
27   3:   password       = "${var.password}"
28
29Terraform 0.11 and earlier required all non-constant expressions to be
30provided via interpolation syntax, but this pattern is now deprecated. To
31silence this warning, remove the "${ sequence from the start and the }"
32sequence from the end of this expression, leaving just the inner expression.
33
34Template interpolation syntax is still used to construct strings from
35expressions when the template includes multiple interpolation sequences or a
36mixture of literal strings and interpolations. This deprecation applies only
37to templates that consist entirely of a single interpolation sequence.
38
39(and 7 more similar warnings elsewhere)
40
41Terraform has been successfully initialized!
42
43You may now begin working with Terraform. Try running "terraform plan" to see
44any changes that are required for your infrastructure. All Terraform commands
45should now work.
46
47If you ever set or change modules or backend configuration for Terraform,
48rerun this command to reinitialize your working directory. If you forget, other
49commands will detect it and remind you to do so if necessary.

Once done, Terraform vSphere provider should be downloaded and placed in same directory as your terraform configuration files.

Next run terraform plan command. The output will tell you what and how it will be generated.

 1PS C:\Terraform\Role1\Packer vSphere Role> terraform plan
 2Refreshing Terraform state in-memory prior to plan...
 3The refreshed state will be used to calculate this plan, but will not be
 4persisted to local or remote state storage.
 5
 6data.vsphere_folder.folder["/DC01/vm/Packer"]: Refreshing state...
 7data.vsphere_role.readonly: Refreshing state...
 8data.vsphere_datacenter.dc: Refreshing state...
 9data.vsphere_datastore.datastore["datastore1"]: Refreshing state...
10data.vsphere_host.host["esx01.lab.local"]: Refreshing state...
11data.vsphere_network.net["VM Network"]: Refreshing state...
12data.vsphere_compute_cluster.cluster["CL01"]: Refreshing state...
13
14------------------------------------------------------------------------
15
16An execution plan has been generated and is shown below.
17Resource actions are indicated with the following symbols:
18  + create
19
20Terraform will perform the following actions:
21
22  # vsphere_entity_permissions.p1 will be created
23  + resource "vsphere_entity_permissions" "p1" {
24      + entity_id   = "datacenter-2"
25      + entity_type = "Datacenter"
26      + id          = (known after apply)
27
28      + permissions {
29          + is_group      = false
30          + propagate     = false

Finally run terraform apply --auto-approve command and this will apply configuration on your vCenter server:

 1PS C:\Terraform\Role1\Packer vSphere Role> terraform apply --auto-approve
 2data.vsphere_datacenter.dc: Refreshing state...
 3data.vsphere_folder.folder["/DC01/vm/Packer"]: Refreshing state...
 4data.vsphere_role.readonly: Refreshing state...
 5data.vsphere_host.host["esx01.lab.local"]: Refreshing state...
 6data.vsphere_network.net["VM Network"]: Refreshing state...
 7data.vsphere_datastore.datastore["datastore1"]: Refreshing state...
 8data.vsphere_compute_cluster.cluster["CL01"]: Refreshing state...
 9vsphere_entity_permissions.p1: Creating...
10vsphere_role.role2: Creating...
11vsphere_entity_permissions.p1: Creation complete after 1s [id=datacenter-2]
12vsphere_role.role2: Creation complete after 1s [id=-1879812451]
13vsphere_entity_permissions.p4["datastore1"]: Creating...
14vsphere_entity_permissions.p6["/DC01/vm/Packer"]: Creating...
15vsphere_entity_permissions.p3["esx01.lab.local"]: Creating...
16vsphere_entity_permissions.p2["CL01"]: Creating...
17vsphere_entity_permissions.p5["VM Network"]: Creating...
18vsphere_entity_permissions.p6["/DC01/vm/Packer"]: Creation complete after 0s [id=group-v82]
19vsphere_entity_permissions.p4["datastore1"]: Creation complete after 0s [id=datastore-54]
20vsphere_entity_permissions.p2["CL01"]: Creation complete after 0s [id=domain-c7]
21vsphere_entity_permissions.p3["esx01.lab.local"]: Creation complete after 0s [id=host-12]
22vsphere_entity_permissions.p5["VM Network"]: Creation complete after 0s [id=network-17]
23
24Warning: Interpolation-only expressions are deprecated
25
26  on main.tf line 3, in provider "vsphere":
27   3:   password       = "${var.password}"
28
29Terraform 0.11 and earlier required all non-constant expressions to be
30provided via interpolation syntax, but this pattern is now deprecated. To
31silence this warning, remove the "${ sequence from the start and the }"
32sequence from the end of this expression, leaving just the inner expression.
33
34Template interpolation syntax is still used to construct strings from
35expressions when the template includes multiple interpolation sequences or a
36mixture of literal strings and interpolations. This deprecation applies only
37to templates that consist entirely of a single interpolation sequence.
38
39(and 7 more similar warnings elsewhere)
40
41
42Apply complete! Resources: 7 added, 0 changed, 0 destroyed.

Results

As you can see Terraform has successfully created 7 resources and you can verify those under vCenter that Packer role has been created and Packer@vsphere.local account has that role assigned on lister vSphere objects.

Multiple datacenters

You may manage multiple datacenter objects under single vCenter server. My Terraform configuration allow you to specify only single datacenter objects and does not allow you to specify multiple datacenter objects.. So what to when you want to assign Packer role on multiple datacenter objects? Simply delete .tfstate file and re-run configuration specify new datacenter values in terrafrom.tfvars.

Thanks,