Deploy Puppet Enterprise agents with HashiCorp Terraform on Azure VMs

HashiCorp Terraform is an open source Infrastructure as Code (IaC) tool that is widely used to deploy cloud infrastructure in the public cloud, such as AWS and Azure, along with on-premises VMware vSphere environments. One of the challenges is developing a method for bootstrapping the instances with configuration management agents such as the Puppet Enterprise agent. In this blog post we cover a simple and easy way to install the Puppet Enterprise agent on Azure virtual machines — both Linux and Windows — provisioned with HashiCorp Terraform. We’re assuming for this blog that you’ve already got Terraform manifest blocks for the virtual machines you want to create (for example, one for a Windows 2016 Server, and one for an Ubuntu Linux 18.04 LTS server). If you haven’t got these, or don’t know how to do them, check out Hashicorp’s excellent documentation here.

Azure virtual machine extensions

Microsoft Azure supports what are known as virtual machine extensions which are small applications that provide post-deployment configuration and automation on Azure VMs. There are a number of extensions available from companies such as DataDog, New Relic, and others. These extensions have been created to wrap the installation and configuration of their respective agents.

Custom Script Extension

In addition to extensions created by vendors, Microsoft Azure has created a Custom Script Extension that allows arbitrary commands or scripts to be executed during the post-provisioning stage. The HashiCorp Terraform Azure provider includes a resource for custom script extensions and can be used to quickly install the Puppet Enterprise agent on a virtual machine during the provisioning process.

Puppet Enterprise agent installation

Puppet Enterprise provides a simple method for installing the Puppet Enterprise agent using the PE agent install script. Using this script enables us to easily provide additional agent configuration information, such as trusted facts that are embedded in the CSR or a pre-shared key used for automatically signing the agent SSL certificate. This method assumes that a certificate autosigning process is in place to allow the certificate to be automatically signed during the bootstrap process. If sensitive information such as the pre-shared key is passed as part of the provisioning code, it should be properly secured. There are several options to properly secure that information:

  • Create a custom wrapper script that dynamically fetches the sensitive information from Azure Key Vault
  • Create a custom wrapper script that dynamically fetches the sensitive information from a HashiCorp Vault deployment
  • Embed the sensitive information in a custom wrapper script that is securely stored in an Azure Blob

Attaching an installation script to a Terraform manifest

There are a number of different ways to give Azure access to a script to use with the Custom Script Extension. For our purposes, the simplest approach is to run the command inline, which works perfectly for Linux. Windows, however, has some security elements around PowerShell that makes it far more difficult to run an inline command properly — so instead, we will use the templatefile function to refer to a local PowerShell agent installation script in the same folder as our Terraform manifest, and reference that script dynamically with the path.module named value. This tells Terraform to look in the same folder as the current manifest for the templatefile script we are referencing. By doing this, for both Linux and Windows, we can create a parameterized installation command that will be passed the correct parameters from the Terraform manifest.


The Puppet Enterprise agent installation script for Linux uses Bash, and can be expressed as a single-line shell command. An example, using a Terraform variable called primary_server to specify the Puppet Primary Server, is shown below:

Once we’ve got our installation command, we need to make it available for use in a Terraform manifest using a locals block.

Now we can specify an azurerm_virtual_machine_extension block in the Terraform manifest to run the agent installation, and attach this to an azurerm_virtual_machine block to deploy it.

As long as you have declared an azurerm_virtual_machine resource named the same as your virtual_machine_id in the Custom Script Extension, the next time the virtual machine is deployed with the Terraform manifest, the Puppet Agent will be installed!


The approach for the Windows agent installation is similar to Linux but, as mentioned above, for Windows we will create a local PowerShell script as a Terraform templatefile with all the information it needs to run the agent install. The first thing we will do is create a PowerShell script called agentInstall.ps1 in the same directory as our Terraform manifest. The contents of this file are as follows:

Note that the first line defines the $primaryServer PowerShell variable from the primary_server Terraform variable supplied to the templatefile (see below). As we did for the Linux install, we will define both a primary_server variable and a locals block in our Terraform manifest. This time, however, our command_to_execute local will have some extra bits to accommodate Windows PowerShell and the switches it needs to execute a script successfully.

This locals block will read in our agentInstall.ps1 script and encode it so that it can be successfully executed on a Windows Server. Once we’ve done this, similarly to the Linux approach, we will declare a Custom Script Extension. It is important to note though that Microsoft has two different Custom Script Extensions — one for Windows, and one for Linux. Make sure that you specify the correct Publisher, Type and Type_Handler_Version as it is different depending on the operating system.

Again, as long as you have declared an azurerm_virtual_machine resource named the same as your virtual_machine_id in the Custom Script Extension, the next time the virtual machine is deployed with the Terraform manifest, the Puppet Agent will be installed!

The great thing about Puppet Enterprise with Hashicorp Terraform is the huge amount of flexibility and programmability to suit just about any scenario that presents itself. We’ve shown one method here to bootstrap the Puppet Agent, but there are lots of ways to achieve your automation outcomes. As well, don’t forget that Puppet Enterprise isn’t just agent-based — we also support agentless management over SSH and WinRM if that’s a better fit for your environment.

This post was co-authored by David Alexander, Senior Manager of Sales Engineering, and Daniel Ring, Sales Engineer, and is based on a previous post by Martez Reed, former Principal Field Solutions Developer at Puppet.

Learn more

Puppet sites use proprietary and third-party cookies. By using our sites, you agree to our cookie policy.