DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

LAB: Terraform Provisioners (EC2 + remote-exec + file)

Provision EC2 β†’ upload script β†’ execute script automatically


πŸ“ Project Structure

terraform-provisioners-lab/
β”‚
β”œβ”€β”€ main.tf
β”œβ”€β”€ variables.tf
β”œβ”€β”€ outputs.tf
β”œβ”€β”€ providers.tf
β”œβ”€β”€ terraform.tfvars
β”‚
β”œβ”€β”€ scripts/
β”‚   └── install_nginx.sh
β”‚
└── ssh/
    └── id_rsa.pub   # your public key
Enter fullscreen mode Exit fullscreen mode

1️⃣ providers.tf

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ variables.tf

variable "aws_region" {
  description = "AWS region"
  type        = string
}

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
}

variable "key_name" {
  description = "SSH key name"
  type        = string
}

variable "public_key_path" {
  description = "Path to public key"
  type        = string
}

variable "private_key_path" {
  description = "Path to private key"
  type        = string
}

variable "ami_owner" {
  description = "AMI owner"
  type        = string
  default     = "amazon"
}
Enter fullscreen mode Exit fullscreen mode

3️⃣ terraform.tfvars (NO hardcoding in code)

aws_region       = "us-east-2"
instance_type    = "t3.micro"
key_name         = "terraform-provisioner-key"
public_key_path  = "ssh/id_rsa.pub"
private_key_path = "ssh/id_rsa"
Enter fullscreen mode Exit fullscreen mode

4️⃣ main.tf

πŸ”Ή Key Pair

resource "aws_key_pair" "this" {
  key_name   = var.key_name
  public_key = file(var.public_key_path)
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή Get Latest AMI (NO hardcoding)

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = [var.ami_owner]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή Security Group

resource "aws_security_group" "this" {
  name = "terraform-provisioner-sg"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή EC2 + Provisioners

resource "aws_instance" "this" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type
  key_name      = aws_key_pair.this.key_name

  vpc_security_group_ids = [aws_security_group.this.id]

  tags = {
    Name = "provisioner-lab"
  }

  connection {
    type        = "ssh"
    user        = "ec2-user"
    private_key = file(var.private_key_path)
    host        = self.public_ip
  }

  # πŸ“ FILE provisioner
  provisioner "file" {
    source      = "scripts/install_nginx.sh"
    destination = "/home/ec2-user/install_nginx.sh"
  }

  # βš™οΈ REMOTE EXEC provisioner
  provisioner "remote-exec" {
    inline = [
      "chmod +x /home/ec2-user/install_nginx.sh",
      "sudo /home/ec2-user/install_nginx.sh"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

5️⃣ outputs.tf

output "public_ip" {
  value = aws_instance.this.public_ip
}

output "url" {
  value = "http://${aws_instance.this.public_ip}"
}
Enter fullscreen mode Exit fullscreen mode

6️⃣ scripts/install_nginx.sh

#!/bin/bash

sudo yum update -y
sudo yum install -y nginx

sudo systemctl start nginx
sudo systemctl enable nginx

echo "<h1>Provisioner Lab Success</h1>" | sudo tee /usr/share/nginx/html/index.html
Enter fullscreen mode Exit fullscreen mode

πŸš€ HOW TO RUN

terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

βœ… VERIFY

Open browser:

http://<PUBLIC_IP>
Enter fullscreen mode Exit fullscreen mode

You should see:

Provisioner Lab Success
Enter fullscreen mode Exit fullscreen mode

⚠️ IMPORTANT (INTERVIEW GOLD)

❗ Why provisioners are NOT recommended?

  • Not idempotent
  • Hard to debug
  • Break Terraform model

βœ… Better alternatives:

  • user_data
  • Packer (AMI baking)
  • Ansible

πŸ’¬ Interview Answer (SHORT)

β€œProvisioners in Terraform are used to execute scripts or commands on local or remote machines during resource creation. However, they are considered a last resort because they are not idempotent and can break declarative infrastructure principles. Preferred alternatives include user_data, configuration management tools, or pre-baked images.”

Top comments (0)