A step-by-step guide for AWS EC2 provisioning using Terraform: remote-exec Provisioner & user data — Part 6

Joel Wembo
6 min readJun 21, 2024

--

This guide outlines the process of using Terraform to create an EC2 instance on AWS, complete with connection, file, and remote-exec provisioners. By placing the private key file in the root directory and configuring Terraform to use this key, the setup includes defining an AWS key pair, uploading a script to the instance, and executing it remotely. This automated approach ensures efficient provisioning and configuration of the EC2 instance, facilitating tasks such as installing and starting NGINX through a simple script.

A step-by-step guide for AWS EC2 provisioning using Terraform

To enhance readability, this handbook is divided into chapters and split into parts. The first, part, “A step-by-step guide for AWS EC2 provisioning using Terraform: HA, ALB, VPC, and Route53 — Part 1”, and the second part “A step-by-step guide for AWS EC2 provisioning using Terraform: HA, CloudFront, WAF, and SSL Certificate — Part 2”, and “A step-by-step guide for AWS EC2 provisioning using Terraform: Cloud Cost Optimization, AWS EC2 Spot Instances — Part 3”, was covered in a separate article to keep the reading time manageable and ensure focused content. The next part or chapter will be published in the next post, upcoming in a few days, “A step-by-step guide for AWS EC2 provisioning using Terraform: VPC peering, VPN, Site-to-site Connection, tunnels ( multi-Cloud ) — Part 12“ and so much more !!

Table of Contents

· Table of Contents
· Why Use User Data?
remote-exec Provisioner & user data using terraform
Explanation
· Notes:
· About me
· References

User data in the context of AWS EC2 instances allows you to automatically run scripts or commands during the instance’s launch. This is useful for initial setup and configuration tasks, such as installing software, applying patches, or configuring services, ensuring that the instance is ready for use immediately after creation without manual intervention.

Why Use User Data?

  1. Automation: Automates the initial configuration of the instance, reducing manual setup time.
  2. Consistency: Ensures all instances are configured identically, which is crucial for scaling and maintaining uniformity.
  3. Efficiency: Speeds up the provisioning process by handling configuration tasks at boot time.
  4. Simplicity: Simplifies the Terraform configuration by moving some setup tasks into the user data script, making the Terraform files cleaner.

remote-exec Provisioner & user data using terraform

Step 1: Prepare your user data.sh

#!/bin/bash
sudo apt-get update
sudo apt-get install -y nginx
sudo systemctl start nginx
sudo systemctl enable nginx
echo '<!doctype html>
<html lang="en"><h1>EC2 running website</h1></br>
<h3>First Instance</h3>
</html>' | sudo tee /var/www/html/index.html
exit

Step 2: Prepare your Key Pair file (.pem file)

This should be among your first steps before creating an ec2 instance

or you simply create an AWS key pair using the AWS CLI with RSA encryption, you can use the aws ec2 create-key-pair command. Here's how you can do it:

aws ec2 create-key-pair --key-name MyKeyPair --query 'KeyMaterial' --output text > MyKeyPair.pem

Step 3: Update your Terraform main file with the following solution

# Terraform provision AWS EC2 instance with S3 State Management
# AWS EC2 Instance A
resource "aws_instance" "prodxcloud-lab-1" {
ami = var.instance_ami
instance_type = var.instance_type
# subnet_id = var.instance_subnet_id # Custom using subnet id using variable.tf
subnet_id = element(aws_subnet.public_subnets.*.id, 1) # dynamic via terraform vpc.tf
associate_public_ip_address = var.publicip
key_name = var.instance_keyName
# user_data = file("./scripts/user_data.sh")

# Remote Provisioner execution using bash scipt file
# Establishes connection to be used by all

provisioner "file" {
source = "user_data.sh"
destination = "/tmp/user_data.sh"

# SSH Connection via terraform
connection {
type = "ssh"
user = "ubuntu"
host = self.public_ip
private_key = file("${path.module}/prodxcloud-ec2-keypair-1.pem")
}

}

# Remote Provisioner for User Data
provisioner "remote-exec" {
# inline = [
# "sudo apt-get update",
# "sudo apt-get install -y nginx",
# "sudo systemctl start nginx",
# "sudo systemctl enable nginx",
# "sudo chmod -R 777 /var/www/html",
# "sudo echo “User Data Installed by Terraform $(hostname -f)” >> /var/www/html/index.html"
# ]
# generic remote provisioners (i.e. file/remote-exec)
inline = [
"chmod +x /tmp/user_data.sh",
"/tmp/user_data.sh",
]
# SSH connection via terraform
connection {
type = "ssh"
user = "ubuntu"
host = self.public_ip
private_key = file("${path.module}/prodxcloud-ec2-keypair-1.pem")

}
}
# remote exec end here

# Attaching security group
vpc_security_group_ids = [
aws_security_group.prodxcloud-SG.id
]
root_block_device {
delete_on_termination = true
volume_size = 50
volume_type = "gp2"
}
tags = {
Name = "prodxcloud-lab-1"
Environment = "DEV"
OS = "UBUNTU"
Managed = "PRODXCLOUD"
}

depends_on = [aws_security_group.prodxcloud-SG, aws_vpc.prodxcloud-vpc, aws_subnet.public_subnets]

//end
}
Terraform Log with provisioned file

Explanation:

  • Provider Configuration: Specifies the AWS provider and region.
  • Key Pair Resource: Creates an AWS key pair using an existing public key.
  • EC2 Instance Resource: Defines the EC2 instance, including the AMI, instance type, key name, and tags.
  • File Provisioner: Uploads the install_nginx.sh script to the EC2 instance.
  • Remote Exec Provisioner: Executes the uploaded script on the EC2 instance.
  • Outputs: Prints the public IP of the EC2 instance after creation.

Notes:

  • Replace the ami value with a valid AMI ID for your region.
  • Ensure your SSH key pair exists and the paths in the main.tf file is correct.
  • This example assumes you have SSH access to the EC2 instance. Adjust the connection parameters as needed based on your setup.

Update: Once you are done with this tutorial, you might to check up a follow-up tutorial on the next part, A step-by-step guide for AWS EC2 provisioning using Terraform: AWS EC2 Pricing — Part 7

About me

I am Joel Wembo, AWS certified cloud Solutions architect, Back-end developer, and AWS Community Builder, I‘m based in the Philippines 🇵🇭; and currently working at prodxcloud as a DevOps & Cloud Architect. I bring a powerful combination of expertise in cloud architecture, DevOps practices, and a deep understanding of high availability (HA) principles. I leverage my knowledge to create robust, scalable cloud applications using open-source tools for efficient enterprise deployments.

I’m looking to collaborate on AWS CDK, AWS SAM, DevOps CI/CD, Serverless Framework, CloudFormation, Terraform, Kubernetes, TypeScript, GitHub Actions, PostgreSQL, and Django.”

To enhance readability, this handbook is divided into chapters and split into parts. The first, part, “A step-by-step guide for AWS EC2 provisioning using Terraform: HA, ALB, VPC, and Route53 — Part 1”, and the second part “A step-by-step guide for AWS EC2 provisioning using Terraform: HA, CloudFront, WAF, and SSL Certificate — Part 2”, and “A step-by-step guide for AWS EC2 provisioning using Terraform: Cloud Cost Optimization, AWS EC2 Spot Instances — Part 3”, was covered in a separate article to keep the reading time manageable and ensure focused content. The next part or chapter will be published in the next post, upcoming in a few days, “A step-by-step guide for AWS EC2 provisioning using Terraform: VPC peering, VPN, Site-to-site Connection, tunnels ( multi-Cloud ) — Part 12“ and so much more !!

Thank you for Reading !! 🙌🏻, don’t forget to subscribe and give it a CLAP 👏, and if you found this article useful contact me or feel free to sponsor me to produce more public content. see me in the next article.🤘

For more information about the author ( Joel O. Wembo ) visit:

Links:

References

Ansible for your application on AWS EC2: Development, Infrastructure Provisioning and Configuration

Technical Guide: End-to-End CI/CD DevOps with Jenkins, Terraform, Docker, Kubernetes, SonarQube, ArgoCD, AWS EC2, EKS, and GitHub Actions (Django Deployment)

Quickstart guide: How to deploy a full-stack cloud-native app with Secure HTTPS to CloudFront, API Gateway, and Route53 with an external Custom Domain registrar using AWS SAM CLI & Cloud9 (manual deployment)

--

--

Joel Wembo

I am a Cloud Solutions Architect at prodxcloud. Expert in AWS, AWS CDK, EKS, Serverless Computing and Terraform. https://www.linkedin.com/in/joelotepawembo