Terraform remote exec provisioner to run shell commands
If you are delving into using Terraform in your production or home lab environment, it is a great way to automate your infrastructure, either in a private cloud or public cloud environment. The Terraform provisioner block allows running commands on a remote system as part of your Terraform configuration. Let’s look at Terraform remote exec and see how you can use this in your script files to run commands.
Take a look at my YouTube video covering the topic of home server automation:
What are Terraform Provisioners?
Terraform provisioners are ways that Terraform can use to perform configuration management tasks on remote hosts to configure various operations and settings. Various Terraform provisioners can be used, including:
- local exec – The local-exec provisioner is used on the local Terraform host to apply and execute configurations to execute shell commands. You can also use it to read environment variables and other information used for applying configuration to the resource.
- remote exec – The remote exec provisioner performs tasks on the remote host and settings changes, as we will note below. These can be run in Linux and Windows hosts
- file provisioner – The file provisioner copies files and other resources from a host machine to the target remote machine so these can be applied or used in configuration activities. Data can then be used to configure your resources.
What is the terraform remote exec provisioner?
Terraform remote exec provisioners are not necessarily Terraform’s strong suit as it is not as well suited for configuration management tasks that another tool like Ansible would be better to perform tasks on a remote resource. Terraform mentions using the provisioner block should be a last resort to install software and make configuration changes.
The reason is that the terraform provisioners do not save the changes as part of the Terraform configuration state for the resource or when the changes were created on your server or other devices.
Below is an example of Terraform’s state data showing changes made in the environment.
However, I have used the remote exec provisioner as part of my home lab scripts for quite some time now, and they work well to perform various configurations on a remote host.
Executing scripts
You can use the Terraform remote exec provisioner to execute scripts and inline commands in your connection to the remote host. You can carry out basically any command as a remote execution operation like you can in a shell script.
This includes parameters used to invoke, generate, or enable various configurations.
Connection block
To successfully run the provisioner remote exec inline block on a remote host, you need to have a connection block that details how the Terraform configuration is applied to your remote instance.
SSH connection
The connection block will typically use an SSH connection for your Linux instance which can be established using an SSH key, key pair with a private key for SSH access. If you are using a root account to connect, it is preferable to use an SSH key pair for access instead of password authentication.
Below you can see that the Terraform script’s remote-exec portion has begun and connected with SSH access.
You will need to ensure the user you are using in your SSH connection is in the correct security group to install or run commands contained in the remote exec provisioners in your code process, or the process may fail.
Depending on your network location, you will need connectivity to your remote host via a public IP address or using a bastion host.
Terraform remote exec examples
Let’s take a look at Terraform remote exec examples and a few things you can do with the Terraform remote exec provisioner block in your Terraform code. I am using Terraform to configure an Ubuntu virtual machine in the example below. After creating the Ubuntu Server VM, we can use the provisioner remote exec to run things like sudo apt get update or return the public IP address as part of the Terraform code.
Use cases for Terraform remote exec provisioners
I have used the Terraform remote exec provisioner block for a few things: commands like sed to edit files, restart services, install software, set default variables, make sure commands are executed, connect to additional resources, call functions, and use various other arguments. You can also update your path statements, etc.
Below is an example of editing DNS values in the resolved.conf file of a remote system.
provisioner "remote-exec" {
inline = [
"sleep 60",
"sudo sed -i 's/#DNS=/DNS=10.1.149.10/g' /etc/systemd/resolved.conf",
"sleep 5",
"sudo sed -i 's/#Domains=/Domains=cloud.local/g' /etc/systemd/resolved.conf"
]
}
After connecting using the connection block, below, I am initiating the command to update and upgrade packages. You can pass in the noninteractive stanza to ensure the code doesn’t use the interactive screens to restart services, etc.
provisioner "remote-exec" {
inline = [
"sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y",
"sleep 5",
"sudo apt-get install unattended-upgrades",
"sudo dpkg-reconfigure -pmedium unattended-upgrades"
]
}
Below, the remote-exec provisioner is used to change the values in the SSH_config file to make sure SSH key pair authentication is enforced.
provisioner "remote-exec" {
inline = [
"sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config",
"sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config",
"sudo sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config",
"sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config"
]
}
After running the remote-exec portion of the Terraform script, we see the Terraform apply script completes successfully.
Terraform remote exec FAQs
What are Terraform provisioners? The terraform provisioners are constructs in Terraform that allow you to execute scripts and other commands, like shell commands, on either your local Terraform host or a remote resource.
What is Terraform remote-exec? The remote-exec command is a Terraform provisioner that runs shell scripts and other commands on a remote host. It is useful to install software, change settings, edit files, etc.
Is it best practice to use Terraform provisioners? According to Hashicorp, it is not. Terraform provisioners are meant to be a last resort to accomplish things in an automated way if you have no other means. This is because provisioner changes are not captured in your Terraform state data, making it difficult to track down or troubleshoot things if the commands do not execute correctly or as expected.
Wrapping Up
I use the Terraform remote exec construct in many Terraform scripts for the home lab to finish out provisioning my Ubuntu Servers for quick and easy provisioning. It makes life easy just by having everything in one process without including additional technologies, scripts, and processes.
More Terraform topics: