Executing Commands in an EC2 Instance

There could be situations where we might have to execute commands in a provisioned EC2 instance or upload various files to such an instance. Terrarom has support for such use cases.

In this section I will provision an EC2 instance and then connect to it to upload a script. Then execute that script on the newly provisioned EC2 instance.

Prerequisites,

  • Generate public and private keys. In here I assume their names as mykey and mykey.pub.

Create a simple shell script with the name script.sh,

#!/bin/bash

# install nginx
apt-get update
apt-get -y install nginx

# make sure nginx is started
service nginx start

Create a file with name terraform.tfvars,

AWS_ACCESS_KEY="<AWS_ACCESS_KEY>"
AWS_SECRET_KEY="<AWS_SECRET_KEY>"

Create a file with name vars.tf,

variable "AWS_ACCESS_KEY" {
}

variable "AWS_SECRET_KEY" {
}

variable "AWS_REGION" {
  default = "eu-west-1"
}

variable "AMIS" {
  type = map(string)
  default = {
    us-east-1 = "ami-13be557e"
    us-west-2 = "ami-06b94666"
    eu-west-1 = "ami-844e0bf7"
  }
}

variable "PATH_TO_PRIVATE_KEY" {
  default = "mykey"
}

variable "PATH_TO_PUBLIC_KEY" {
  default = "mykey.pub"
}

variable "INSTANCE_USERNAME" {
  default = "ubuntu"
}

Notice that we have specified paths to our key files here.

Create a file with name provider.tf,

provider "aws" {
  access_key = var.AWS_ACCESS_KEY
  secret_key = var.AWS_SECRET_KEY
  region     = var.AWS_REGION
}

This file simply initializes the AWS Terraform provider with the credentials and specify the region to be used.

Create a file with the name instance.tf,

resource "aws_key_pair" "mykey" {
  key_name   = "mykey"
  public_key = file(var.PATH_TO_PUBLIC_KEY)
}

resource "aws_instance" "example" {
  ami           = var.AMIS[var.AWS_REGION]
  instance_type = "t2.micro"
  key_name      = aws_key_pair.mykey.key_name

  provisioner "file" {
    source      = "script.sh"
    destination = "/tmp/script.sh"
  }
  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/script.sh",
      "sudo sed -i -e 's/\r$//' /tmp/script.sh",  # Remove the spurious CR characters.
      "sudo /tmp/script.sh",
    ]
  }
  connection {
    host        = coalesce(self.public_ip, self.private_ip)
    type        = "ssh"
    user        = var.INSTANCE_USERNAME
    private_key = file(var.PATH_TO_PRIVATE_KEY)
  }
}

In the above file you can noticed that I have used file() method to load the file. It accepts the path of the file to be loaded. In here I've passed the public key path taken from a variable to it.

Next I've specified a file to be copied into the new instance. Which is script.sh and it will be copied into the file path /tmp/script.sh file location.

Next I've speicified a set of commands to be executed after the provisioning. Basically this command will execute the script file that we are uploading into the newly provisioned instance.

Finally, it is required to have a connection to do all these. The connection code block define the connection to the new instance.

Last updated