August 24, 2021

Deploy Puppet Enterprise With Terraform on Azure Virtual Machines

How to & Use Cases
Ecosystems & Integrations

Want to install the Puppet Enterprise agent on Microsoft Azure virtual machines (VMs) with HashiCorp Terraform? Get started by following the steps in this walkthrough.

Back to top

What Is HashiCorp Terraform?

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.

👉👉👉Skip the work and let Puppet pros guide your deployment. 

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.

Back to top

What Are Azure Virtual Machines on Terraform?

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.

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 cloud provisioning process.

Back to top

How To Install Puppet Enterprise on Azure Virtual Machines With Terraform

Puppet Enterprise provides a simple method for installing the Puppet Enterprise agent on Azure VMs 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
Back to top

How To Attach 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 make it far more difficult to run an inline command properly. So, instead of running an inline command, we will use the templatefile function to refer to a local PowerShell agent installation script in the same folder as our Terraform manifest. This will allow us to reference the script dynamically with the path.module named value and 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.

Linux

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

curl -k "https://${var.primary_server}:8140/packages/current/install.bash" | sudo bash -s agent:certname=$(hostname)

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

variable "primary_server" {
 type        = string
 description = "FQDN of the Primary Puppet Server"
 default     = "my-puppet-server.domain.com" # add your own default here
}
locals {
 command_to_execute = "curl -k https://${var.primary_server}:8140/packages/current/install.bash | sudo bash -s agent:certname=$(hostname)"
}

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.

resource "azurerm_virtual_machine_extension" "pe-agent-install-linux" {
 name                 = "myrg-pe-agent-install-linux" # feel free to replace myrg with your resource group name!
 virtual_machine_id   = azurerm_virtual_machine.vm01.id #replace vm01 with your VM name or variable!
 publisher            = "Microsoft.Azure.Extensions"
 type                 = "CustomScript"
 type_handler_version = "2.0"
 settings = local.command_to_execute
}

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!

Windows

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:

$primaryServer="${primary_server}"
$installURL="https://${primaryServer}:8140/packages/current/install.ps1"
$agentCertname="$Env:COMPUTERNAME.mydomain.com" # replace mydomain.com with your Active Directory/DNS domain
​
[System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};
$webClient = New-Object System.Net.WebClient;
$webClient.DownloadFile($installURL, "$Env:TEMP\install.ps1");
& $Env:TEMP\install.ps1 -v agent:certname=$agentCertname

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.

variable "primary_server" {
 type        = string
 description = "FQDN of the Primary Puppet Server"
 default     = "my-puppet-server.domain.com"
}
locals {
 script_name     = "agentInstall.ps1"
 # script_rendered = filebase64("${path.module}/${local.script_name}")
 script_template = base64encode(templatefile("${path.module}/${local.script_name}", {
   primary_server = var.primary_server
 }))
 command_to_execute = jsonencode({
   commandToExecute = "powershell -command \"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${local.script_template}')) | Out-File -filepath ${local.script_name}\" && powershell -ExecutionPolicy Unrestricted -File ${local.script_name}"
 })
}

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.

resource "azurerm_virtual_machine_extension" "pe-agent-install-windows" {
 name                 = "myrg-pe-agent-install-windows" # feel free to replace myrg with your resource group name!
 virtual_machine_id   = azurerm_virtual_machine.vm01.id #replace vm01 with your VM name or variable!
 publisher            = "Microsoft.Compute"
 type                 = "CustomScriptExtension"
 type_handler_version = "1.10"
 settings = local.command_to_execute
 }
}

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!

Get the best of the PowerShell gallery in your Puppet Enterprise console >>

Back to top

Puppet Enterprise and HashiCorp Terraform

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 automation over SSH and WinRM if that’s a better fit for your environment.

Ready to simplify the management of infrastructure and complex workflows with Puppet Enterprise?

Try Puppet Enterprise

Learn more

Back to top