In this guide, we are going to look at how to use Terraform to provision virtual machines on AWS. The guide is for the new-bies who are getting started with both Terraform and AWS. I am going to explain all the basic steps needed to get you have your first virtual machine running in AWS provisioned using Terraform. Below are the steps we are going to focus on:

  • Explain what terraform is
  • Install Terraform on Linux
  • Set up AWS account
  • Initialize Terraform for AWS
  • Deploy AWS instance with Terraform

What is Terraform?

Terraform is a tool used to easily and efficiently built and manage infrastructure. It uses code to manage existing service providers as well as custom infrastructure. Terraform works with the existing public cloud providers including AWS, Google Cloud, Azure, DigitalOcean, among others. It uses a language written in HCL and files have a .tf extension. Terraform language is declarative, meaning that you specify your desired state and Terraform will figure out how to achieve it.

Installing Terrafom in Linux

To install Terraform on Linux, we need to download Terraform binary and add to a directory included in our system PATH for it to be executable. Run the commands below:

TRELEASE=0.14.7 
wget https://releases.hashicorp.com/terraform/${TRELEASE}/terraform_${TRELEASE}_linux_amd64.zip

Install unzip:

# CentOS / RHEL / Fedora
$ sudo yum -y install unzip

# Debian / Ubuntu
$ sudo apt update
$ sudo apt install unzip

Now unzip and move

unzip terraform_${TRELEASE}_linux_amd64.zip 
sudo mv terraform /usr/local/bin/

Set Up AWS account

Once you sign up for AWS, you are normally provided with a root user account that has all the permissions on your account. For security purposes, it is recommended to create non-root user and assign specific permissions. Navigate to IAM section and click on ‘users’ then click ‘Add user’.

Give the user a name and choose the type of access you want for the user. For this case, I am choosing programmatic access because I want to use the CLI. You can choose both options if you also require the user to have console access.

Click on Next:permissions to allow the user to perform some tasks. For the user to use terraform, I am going to grant the following permissions:

  • AmazonEC2FullAccess
  • AmazonS3FullAccess
  • AmazonDynamoDBFullAccess
  • AmazonRDSFullAccess
  • CloudWatchFullAccess
  • IAMFullAccess

I am going to create a group called Terraform, allow the above permissions for the group and add my new user to the group. You can also go ahead to attach existing policies directly without necessarily adding the user to a group.

You can proceed to add tags (optional). Finally, click on create user. You should see that the user is successfully created, and you are provided with access key and access secret. Save them properly as you will always need them whenever you need to access your AWS account from the CLI.

Configure Terraform for AWS

First we need to configure the AWS credentials for the created user. You can choose to include the credentials as part of terafform .tf files (not recommended) but for security purposes I would recommend you pass the credentials as variables with the below commands.

$ aws configure

Provide:

  • AWS Access Key ID
  • AWS Secret Access Key
  • Default region

Sample output is shown below:

AWS Access Key ID [****************M5YB]:
AWS Secret Access Key [****************I5C1]:
Default region name [us-east-2]:
Default output format [json]:

Next, we need to configure provider, AWS in this case, for terraform. Create a file called main.tf. I have created a working directory called AWS-Terraform to have all work here. Inside this directory I am going to create all the needed files.

$ mkdir aws-terraform
$ cd aws-terraform
$ vim main.tf

Add the below content, you can change the region if you like. AWS has various regions around the world and each region has a number of availability zones (data centers). You can read more on this on the AWS website.

provider "aws" {
region = "us-east-2"
shared_credentials_file = "~/.aws/credentials"
}

Deploying single instance

To deploy an instance, we need to specify the provider, resource and the name that we want to give to our deployment. In case of a virtual machine in AWS (EC2), the resource will be ‘instance’. There are other resources which we can deploy including elastic load balancers, RDS and so on. Add the below content to the main.tf file:

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}
  • aws_instance – AWS is our provider and we are deploying an EC2 instance
  • ami – Amazon Machine Image – Here we are using already available image to deploy our instance. AWS marketplace has various AMIs, some free to use.
  • instance_type – instances resources are grouped in instance types. In this case t2.micro has one vCPU and 1GB RAM It is also part of the free tier

Initialize Terraform for AWS

terraform init

When Terraform is installed, it only supports the basic functionality for Terraform but no configurations for any provider. Running terraform init command tells terraform to figure out the provider you are using and accordingly download the necessary code. Inside AWS-Terraform working directory, run the init command as below:

$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.34.0...
- Installed hashicorp/aws v3.34.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

terraform plan

The plan command shows you what your terraform code will execute before the actual execution.

$ terraform plan

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                          = "ami-0c55b159cbfafe1f0"
      + arn                          = (known after apply)
      + associate_public_ip_address  = (known after apply)
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
      + key_name                     = (known after apply)
      + outpost_arn                  = (known after apply)
      + password_data                = (known after apply)
      + placement_group              = (known after apply)
      + primary_network_interface_id = (known after apply)
      + private_dns                  = (known after apply)
      + private_ip                   = (known after apply)
      + public_dns                   = (known after apply)
      + public_ip                    = (known after apply)
      + secondary_private_ips        = (known after apply)
      + security_groups              = (known after apply)
      + source_dest_check            = true
      + subnet_id                    = (known after apply)
      + tenancy                      = (known after apply)
-----
Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

terraform apply

The apply command actually creates resource in AWS.

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                          = "ami-0c55b159cbfafe1f0"
      + arn                          = (known after apply)
      + associate_public_ip_address  = (known after apply)
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
---
Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes
aws_instance.example: Creating...
aws_instance.example: Still creating... [10s elapsed]
aws_instance.example: Still creating... [20s elapsed]
aws_instance.example: Still creating... [30s elapsed]
aws_instance.example: Creation complete after 33s [id=i-03afb6ef4a692eca8]

When you refresh your AWS console, US-East region, you should see your instance running.

As you can see, your instance does not have a name. You can use ‘tag’ to give a name as below:

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  tags = {
    Name = "terraform-example"
  }
}

And run ‘terraform apply’ again. When you refresh your AWS console, you should notice the new instance name.

This was just to get you started with AWS and Terraform. In our coming guides, we will see how to deploy other resources like load balancers and even to scale our deployments to enable us create more than one resource at a time. Stay tuned. Check below related guides: