Skip to main content

Terraform - AWS: Launch an EC2 Instance, Deploy and Run a Bash Script, Terraform Configuration

836 words·
Terraform AWS AWS CLI EC2 Bash Docker
Table of Contents
Terraform - This article is part of a series.
Part 1: This Article

The following Terraform configuration creates an EC2 instance in the default VPC, copys a bash script via SSH to the EC2 instance, changes the permission of the script and executes the script.

The script install-docker.sh and a SSH key pair must be located in the Terraform project folder.


AWS Prerequisites
#

IAM User & Add Permissions
#

Create an IAM user and attach the following policies directly:

  • AmazonEC2FullAccess For EC2 deployments

  • AmazonS3FullAccess For S3 Bucket deployments

Create access keys for the IAM user


Install AWS CLI
#

Linux
#

# Update packages
sudo apt update

# Unstall zip tool
sudo apt install unzip -y

# Download AWS CLI zip file
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# Unzip
unzip awscliv2.zip

# Install
sudo ./aws/install
# Verify installation / check version
/usr/local/bin/aws --version

Windows
#

# Download the AWS CLI installation package
Invoke-WebRequest -Uri https://awscli.amazonaws.com/AWSCLIV2.msi -OutFile AWSCLIV2.msi

# Install AWS CLI
Start-Process msiexec.exe -ArgumentList '/i AWSCLIV2.msi /qn' -Wait
# Start new shell & verify installation
aws --version

AWS Configure
#

Add the IAM user access keys:

# Start AWS CLI configuration
aws configure



Terraform EC2 Stack
#

File and Folder Structure
#

The file and folder structure of the Terraform project looks like this:

aws-ec2-stack
├── aws-terraform  # Private SSH key
├── aws-terraform.pub  # Public SSH key
├── compute.tf
├── install-docker.sh  # Bash script
├── outputs.tf
├── security-group.tf
├── terraform.tf
└── variables.tf

Project Folder
#

# Create project folder
TF_PROJECT_NAME=aws-ec2-stack
mkdir $TF_PROJECT_NAME && cd $TF_PROJECT_NAME

SSH Key Pair
#

# Create a SSH key pair
ssh-keygen -t rsa -b 4096 -f ~/.ssh/aws-terraform
# Copy the public SSH key into the Terraform project folder
cp ~/.ssh/aws-terraform.pub ~/$TF_PROJECT_NAME/

# Copy the private SSH key into the Terraform project folder
cp ~/.ssh/aws-terraform ~/$TF_PROJECT_NAME/

Bash Script
#

  • install-docker.sh
#!/bin/bash

# Install Docker and Docker Compose on Ubuntu

sudo apt-get update

sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release -y

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

Terraform Configuration Files
#

Terraform Provider
#

  • terraform.tf
# Terraform Provider
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# Provider AWS Region
provider "aws" {
  alias  = "aws_region"
  region = var.aws_region
}

Variables
#

  • variables.tf
# AWS Region
variable "aws_region" {
  description = "AWS Region"
  type        = string
  default     = "us-east-1"
}

# EC2 Image ID
variable "ami_id" {
  default = "ami-0e2c8caa4b6378d8c" # Define EC2 AMI ID
}

EC2 Instance
#

compute.tf

# EC2 Instance 
resource "aws_instance" "ec2" {
  provider = aws.aws_region
  ami                    = var.ami_id
  instance_type          = "t2.micro"
  key_name               = aws_key_pair.ssh_key_public.key_name
  vpc_security_group_ids = [aws_security_group.vpc_sg.id]

  tags = {
    Name = "EC2 instance"
    Env  = "Production"
  }

  # SSH connection
  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file("aws-terraform") # Private SSH key name / must be in project folder
    host        = aws_instance.ec2.public_ip
  }

  # Copy script into EC2 instance 
  provisioner "file" {
    source      = "install-docker.sh"
    destination = "/home/ubuntu/install-docker.sh"
  }

  # Change script permission, run script
  provisioner "remote-exec" {
    inline = [
      "chmod +x /home/ubuntu/install-docker.sh",
      "sudo /home/ubuntu/install-docker.sh",
    ]
  }
}


# SSH Key
resource "aws_key_pair" "ssh_key_public" {
    key_name = "ssh-key-public"
    public_key = file("aws-terraform.pub")  # Public SSH key name
}

Security Group
#

  • security-group.tf
resource "aws_security_group" "vpc_sg" {
  provider = aws.aws_region
  name        = "SG"
  description = "Security group webserver"

  # Inbound: allow SSH from Anywhere
  ingress { 
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Inbound: allow HTTP from Anywhere
  ingress { 
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Inbound: allow HTTPS from Anywhere
  ingress { 
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Outbound: allow all traffic
  egress { 
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = "SG"
    Env  = "Production"
  }
}

Outputs
#

  • outputs.tf
# EC2 Instance public IP
output "VM_Public_IP" {
  value       = aws_instance.ec2.public_ip
}

# EC2 Instance private IP
output "VM_Private_IP" {
  value       = aws_instance.ec2.private_ip
}



Deploy Configuration
#

Initialize Terraform Project
#

This will download and install the AWS Terraform provider.

# Initialize the Terraform project
terraform init

Validate Configuration Files
#

# Validates the syntax and structure of Terraform configuration files
terraform validate

# Shell output:
Success! The configuration is valid.

Plan the Deployment
#

# Dry run / preview changes before applying them
terraform plan

Apply the Configuration
#

# Create network stack
terraform apply -auto-approve

# Shell output:
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

VM_Private_IP = "172.31.18.125"
VM_Public_IP = "98.80.77.215"



Verify Setup
#

SSH into EC2 Instance
#

# SSH into the EC2 instance
ssh -i ~/.ssh/aws-terraform ubuntu@98.80.77.215

Verify Docker Installation
#

# Switch to root user
sudo su

# Verify the Docker installation
sudo docker ps

# Shell output:
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
Terraform - This article is part of a series.
Part 1: This Article