Terraform provisioners allow command execution on local or remote resources for configuration tasks after resource creation.
Terraform provisioners enable you to execute commands or scripts either locally or on remote resources. They are especially useful for post-creation configuration tasks such as installing packages or starting services. In this guide, we’ll explore both the remote-exec and local-exec provisioners, their configurations, and best practices for use.
The remote-exec provisioner allows you to run commands on a remote resource, such as a web server instance. For example, after creating a web server, you might want to update the package list, install NGINX, enable it at startup, and then start the service. The configuration below demonstrates how to use the remote-exec provisioner:
Ensure that network connectivity exists between the machine running Terraform and the remote instance. For Linux, this typically involves SSH, whereas Windows instances require WinRM connectivity.
In the example below, a security group and an SSH key pair resource are also created to manage connectivity and authentication:
To facilitate secure authentication, define a connection block inside your resource configuration. The connection block below enables SSH access by setting the host to the instance’s public IP, the user to “ubuntu,” and retrieves the private key from a local file:
When you run terraform apply, Terraform connects to the instance via SSH as specified in the connection block and executes the inline script. An example output is shown below:
Copy
Ask AI
$ terraform applyaws_key_pair.web: Creating...aws_security_group.ssh-access: Creating...aws_key_pair.web: Creation complete after 0s [id=terraform-202201015013048590100000001]aws_security_group.ssh-access: Creation complete after 1s [id=sg-0]aws_instance.webserver: Creating...aws_instance.webserver: Still creating... [10s elapsed]aws_instance.webserver: Still creating... [20s elapsed]aws_instance.webserver: Still creating... [30s elapsed]aws_instance.webserver (remote-exec): Connecting to remote host via SSH...aws_instance.webserver (remote-exec): Host: 3.96.136.157aws_instance.webserver (remote-exec): User: ubuntuaws_instance.webserver (remote-exec): Password: falseaws_instance.webserver (remote-exec): Private key: trueaws_instance.webserver (remote-exec): Certificate: falseaws_instance.webserver (remote-exec): SSH Agent: falseaws_instance.webserver (remote-exec): Connected!aws_instance.webserver: Still creating... [40s elapsed]aws_instance.webserver: Creating...aws_instance.webserver: Creation complete after 50s [id=i-0e10fd3a5b1a4f16c]
The local-exec provisioner runs commands on the local machine where Terraform is executed. It’s useful for tasks like logging or writing data to a file. For example, to save the public IP address of an EC2 instance to /tmp/ips.txt, you can configure the local-exec provisioner as follows:
After running terraform apply, the instance’s public IP will be appended to the file on your local system.Provisioners run by default after resource creation (create-time provisioners), but you can also execute them before resource destruction. In the example below, one local-exec provisioner runs post-creation and another runs pre-destruction:
By default, if a provisioner command fails, Terraform will error out and mark any created resources as tainted. You can customize this behavior using the on_failure argument:
Terraform advises using provisioners only as a last resort. When possible, utilize the inherent features of your resource type to perform configuration actions. For example, rather than using remote-exec provisioner to install software on an AWS EC2 instance, consider using the user_data attribute to initiate scripts during instance launch. Here’s an improved approach using the user_data attribute to install and start NGINX on an EC2 instance:
With this configuration, the initialization script runs automatically during boot, reducing dependency on provisioners for post-creation configuration.
Terraform provisioners, both remote-exec and local-exec, offer flexible options for performing configuration tasks after resource creation or before destruction. However, for improved efficiency and reliability, consider native configuration options like user_data or metadata provided by cloud providers.Now, please head over to the multiple-choice quiz for this section.