How To Use Terraform With AWS

January 16, 2020

What is Terraform

Have you ever got tired of typing in all those CLI commands into your terminal just for it to throw back an error? Terraform is an offering by HashiCorp that allows you to manage infrastructure as code. That idea is pretty powerful because it enables you to develop your infrastructure like any other code you have. It can be checked into version control, edited in a text editor and managed using one command. It automates the provisioning of hardware.

Terraform has numerous plugins, terraform speak for code that calls cloud APIs for you, such as AWS, Azure, and GCP and even for Dominos!

Downloading and Installing Terraform

Terraform can be downloaded from the official Terraform website, and then added to your PATH. Mac OS users can install Terraform using Homebrew or by downloading the file. This is applicable to Mac OS and Linux users.

  1. Make sure unzip is installed
  2. wget <url_above>
  3. unzip terraform_0.12.19_linux_amd64.zip
  4. chmod +x terraform
  5. mv terraform ~/bin/
  6. echo "PATH=$PATH:~/bin
  7. terraform --version

Configuring Permissions

AWS encourages you to not use your root account and instead create an IAM user:

Create a user by going to IAM – you can search for it in the management console.

How to create an IAM user in the management console

We want programmatic access so leave that option ticked and AWS Management Console access unchecked.

Selecting the correct IAM user

Name it whatever, the actual name doesn’t matter.

AWS’s security teams recommend ‘the principle of least privilege’, you should give your user just enough access to do its job but not anymore. Because we are creating an EC2 instance we just need EC2 permissions. Go to ‘Attach a Policy’ and select ‘Amazon EC2 Full Access’.

Attach the correct policy to IAM user

Add three tags (or consult your organizations tagging policy) such as Name, User and Description.

Run aws configure and input the output of IAM user creation:

$ aws configure --profile terraform
AWS Access Key ID [None]: <access_key>
AWS Secret Access Key [None]: <secret_key>
Default region name [None]: us-east-1
Default output format [None]:

Creating an EC2 instance

The cost of this step is free for free-tier users and around $0.01 for normal users.

First you need to tell Terraform what plugin you are using, in this case, it’s AWS.

provider "aws" {
    profile = "terraform"
    region = "eu-west-1"
}

This is called a block. You told Terraform you’re using AWS, the profile you want to use and the default region if it isn’t present in ~/.aws/credentials.

Now let’s create the EC2 instance. To save on cost we are going to create a basic T2 instance. Terraform has the concepts of blocks, and we are going to create a resource block. A block has the resource type and the local name of the block, it’s like int i = 1 in C. The type is int and the i is the name that refers to that int.

resource "aws_instance" "test" {
    instance_type = "t2.micro"
    ami           = "ami-0be057a22c63962cb"
    key_name      = "lewis-keypair"
    vpc_security_group_ids = ["${aws_security_group.web.id}"]
    
}

A VPC if you don’t know is Amazon’s cloud networking product. It enables you to define your own internal network inside AWS – Think VLANs. Here we are giving Terraform the ID of the security groups we are going to create later on. Terraform figures out the real ID when it creates the resources.

resource "aws_security_group" "web" {
  name = "web"
  description = "basic terraform security group allowing SSH, HTTP, HTTPS"
  ingress {
      from_port = 22
      to_port   = 22
      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"]
  }
}

The next resource is the security group mentioned above. It simply allows SSH to connect to the instance. The -1 in the egress specifies we do not care about the protocol.

Better security practice would be to lock down the access to certain IPs, like your company’s subnet. AWS accepts CIDR notation like 189.32.22.0/24.

You can also upload your SSH public key to access the instance with the aws_key_pair resource.

## create ec2-instance

provider "aws" {
    profile = "default"
    region = "eu-west-2"
}

resource "aws_instance" "test" {
    instance_type = "t2.micro"
    ami           = "ami-0be057a22c63962cb"
    key_name      = "lewis-keypair"
    vpc_security_group_ids = ["${aws_security_group.web.id}"]
    
}

resource "aws_security_group" "web" {
  name = "web"
  description = "basic terraform security group allowing SSH, HTTP, HTTPS"
  ingress {
      from_port = 22
      to_port   = 22
      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"]
  }
}

resource "aws_key_pair" "deploy" {
    key_name = "lewis-keypair"
    public_key = "<your_pub_key>"
}
Back to top