Terraform Provisioners: Smart Usage Guide

Terraform Provisioners offer a flexible method to execute scripts and commands during your infrastructure deployment lifecycle. Whether you’re automating configuration steps after resource creation or capturing data locally, provisioners can enhance your Terraform workflows when used wisely.

This comprehensive guide walks you through using provisioners in Terraform—what they are, how they work, and when to use them (or avoid them). It’s structured for everyone from beginners to experienced DevOps engineers.

What Are Terraform Provisioners?

Terraform Provisioners are tools that allow you to execute scripts or commands at specific stages of your infrastructure provisioning. They can operate on the resource itself (remote) or on the machine running Terraform (local).

Provisioners typically execute at two stages:

  • Create-time: After a resource is provisioned.
  • Destroy-time: Before a resource is deleted.

While provisioners can be powerful, Terraform recommends using them only when native provider features don’t suffice.

Using Remote Exec Provisioners

Executing Scripts on Remote Instances

The remote-exec provisioner lets you run commands on a virtual machine or server after Terraform creates it.

Here’s how it works:

  • Defined inside a resource block like aws_instance.
  • Uses inline scripts to define the actions to run.

Example:

provisioner "remote-exec" {
inline = [
"sudo apt update",
"sudo apt install nginx -y",
"sudo systemctl enable nginx",
"sudo systemctl start nginx"
]
}

These commands configure an Ubuntu EC2 instance to run an NGINX web server automatically.

SSH Connection Setup

To run these remote commands, Terraform needs access to the target machine. This is done using the connection block:

connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file("~/.ssh/web.pem")
}

This configuration uses SSH to connect to the server using the instance’s public IP and a private key. Without this, the remote-exec provisioner won’t work.

Using Local Exec Provisioners

Running Commands on Your Local Machine

The local-exec provisioner executes commands on the machine where you’re running Terraform—not the cloud resource.

Use cases include:

  • Logging information locally.
  • Sending notifications after deployments.
  • Running CLI tools post-apply.

Example:

provisioner "local-exec" {
command = "echo ${self.public_ip} > ~/instance_ip.txt"
}

This stores the instance’s public IP in a local file—useful for connecting later or logging.

Handling Provisioner Failures Gracefully

The on_failure Argument

Provisioners fail when their command exits with a non-zero status. By default, this will fail the entire terraform apply process and mark the resource as tainted.

To override this behavior, use:

on_failure = "continue"

This setting tells Terraform to continue deployment even if the provisioner fails.

Destroy-Time Provisioners

Cleaning Up Before Resource Deletion

Terraform also supports destroy-time provisioners. These execute just before a resource is deleted, allowing for cleanup tasks.

Example:

provisioner "local-exec" {
when = "destroy"
command = "echo Deleting ${self.public_ip} >> ~/destroy_log.txt"
}

These are helpful when you need to notify other systems or archive data before tearing down infrastructure.

Best Practices for Using Terraform Provisioners

While provisioners can be incredibly useful, here are some guidelines:

  • Use provider-native methods like user_data for AWS EC2 or custom_data in Azure when possible.
  • Avoid complex logic in provisioners. Use configuration management tools (e.g., Ansible, Chef) for advanced automation.
  • Isolate connection-sensitive logic and always secure your SSH or WINRM credentials.
  • Test incrementally, especially when adding remote-exec or destroy provisioners.

Over-relying on provisioners may lead to less predictable, harder-to-debug Terraform code.

Conclusion

Using Terraform Provisioners gives you the power to automate tasks before and after your infrastructure is deployed. From running shell scripts on remote servers to saving output locally, they add a layer of flexibility that can streamline your workflows—when used thoughtfully.

However, always prioritize using provider-specific attributes for configuration tasks. Treat provisioners as a helpful fallback, not the default method for setup.

By understanding how and when to use remote-exec, local-exec, and other provisioner options, you’ll create Terraform code that’s both powerful and maintainable.

Frequently Asked Questions (FAQs)

1. Should I always use provisioners in Terraform?

No. Use provisioners only when native provider features don’t support your use case. Prefer user_data or metadata where available.

2. What’s the difference between local and remote exec?

local-exec runs on your machine, while remote-exec runs on the created resource (like a cloud VM) after deployment.

3. Can I use provisioners during destroy operations?

Yes. Use the when = "destroy" option inside the provisioner block to define a destroy-time action.

4. What happens if a provisioner fails?

By default, the resource is marked as tainted, and the deployment fails. You can change this with on_failure = "continue".

5. Are provisioners secure?

They can expose secrets or credentials if not handled carefully. Use secure key handling practices and restrict access as needed.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top