Terraform

Terraform for Absolute Beginners

Terraform for Absolute Beginners
In: Terraform, NetDevOps

Are you a beginner looking to learn Terraform? Don't worry, you've come to the right place! In this blog post, we will discuss how Terraform is easier than you might think to learn, even if you have just a basic understanding of AWS or any other Cloud Provider.

Overview

Firstly, let's start with what Terraform is. Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp. It allows you to write, plan, and create infrastructure as code using a declarative language called HashiCorp Configuration Language (HCL). Terraform works with multiple cloud providers, including AWS, Azure, and Google Cloud Platform.

Now, you might be thinking that learning a new tool can be challenging, especially if you are new to the world of cloud computing. However, Terraform is designed to be easy to learn and use, even for beginners.

One reason for this is the simple and intuitive syntax of HCL (HashiCorp Configuration Language) which is designed to be easy to read and write, making it accessible to users with no prior programming experience. Additionally, Terraform's documentation is comprehensive and user-friendly, with plenty of examples and tutorials to help you get started.

Why Terraform?

Before we jump into Terraform, let's discuss how would you create resources in AWS without any IaC tools. A simplified version of creating an EC2 instance via the GUI is shown below.

  • Login to AWS Web Console
  • Create the following resources by navigating to various web pages and clicking various resources.
    • VPC
    • Subnets
    • Route Table
    • Internet Gateway
    • NAT Gateway
    • Routes
    • EC2
  • Test Connectivity

The above works well if all you have to create is a single instance. Now imagine that you need to repeat this process across multiple accounts multiple times.

Firstly, using the web GUI can be error-prone as it relies on manual input and clicking through multiple screens. Secondly, using the web GUI is not efficient when it comes to repeating the same process across multiple accounts.

Terraform, on the other hand, uses declarative syntax, making it less prone to human error. Terraform allows for the creation of reusable code and modules, making it easy to replicate the same infrastructure across multiple accounts. Additionally, Terraform enables the tracking of changes (via git) made to the infrastructure, providing better visibility and control over the cloud environment.

In a nutshell, you define what do you want to create in a text file using the HCL syntax. Terraform will go and create the resources you defined in that file.

Prerequisites

Now that we've learnt the basics, let's go through some of the prerequisites. You must install both aws-cli and terraform on your local machine. You also need to create an AWS IAM user and add the credentials to your machine.

1. Install AWS CLI

Please refer to this guide on how to install AWS CLI across various OS. The following example shows how to install it on MacOS.

Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to AWSCLIV2.pkg in the current folder.

curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"

Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for which drive to install the package to. The files are installed to /usr/local/aws-cli, and a symlink is automatically created in /usr/local/bin. You must include sudo on the command to grant write permissions to those folders.

sudo installer -pkg ./AWSCLIV2.pkg -target /

You can verify the installation by using the following commands.

suresh@mac:~/Documents|⇒  which aws
/usr/local/bin/aws
suresh@mac:~/Documents|⇒  aws --version
aws-cli/2.11.1 Python/3.11.2 Darwin/22.3.0 exe/x86_64 prompt/off

2. Install Terraform

Please refer to this guide on how to install Terraform across various OS. The following example shows how to install Terraform on MacOS.

To install Terraform, find the appropriate package for your system and download it as a zip archive.

After downloading Terraform, unzip the package. Terraform runs as a single binary named terraform. Any other files in the package can be safely removed and Terraform will still function.

Finally, make sure that the terraform binary is available on your PATH.

Move the Terraform binary to one of the listed locations. This command assumes that the binary is currently in your downloads folder and that your PATH includes /usr/local/bin, but you can customize it if your locations are different.

$ mv ~/Downloads/terraform /usr/local/bin/

You can verify the installation by running one of the Terraform commands as shown below.

suresh@mac:~/Documents|⇒  terraform --version
Terraform v1.4.0
on darwin_amd64

3. Create an IAM user in AWS

For Terraform to access your AWS account, you need to provide Terraform with the credentials to use. Unlike web console login where you would use Username and Password, AWS-CLI/Terraform uses a concept call secret-key and secret-id. Once you created a new user account in AWS IAM, you can generate the ID and Key and add them to your local machine.

Navigate to IAM > Users and select Add Users and create a new user with 'AdministratorAccess'. Once a new user is created, click on the user and navigate to Security Credentials and create a new Access Key/ID.

💡
Please note that I've provided the new user account with a full Administrator Access which means the account can pretty much create/remove any resources in AWS. You have the option to fine-tune the access if required.

As you can see below, I already created a user and provide full admin access. Copy the Access key ID and Secret access key under Security Credentials which will enable Terraform to make changes in AWS.

You can run aws configure command on the CLI to add the credentials.

$ aws configure
AWS Access Key ID [None]: <YOUR-KEY-ID>
AWS Secret Access Key [None]: <YOUR-ACCESS-KEY>
Default region name [None]: eu-west-1
Default output format [None]: json

You can alternatively provide your credentials via the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, representing your AWS Access Key and AWS Secret Key.

$ export AWS_ACCESS_KEY_ID="accesskey"
$ export AWS_SECRET_ACCESS_KEY="secretkey"

Terraform Example

Now that we have installed Terraform, let's look at a simple example of how to deploy an EC2 instance within a new VPC.

  • Go to your terminal, and create a new directory (I created one called Terraform) and go inside the directory.
  • Create a file called main.tf and add the following contents to it.
Suresh-MacBook:Terraform suresh$  ls
main.tf

Provider and Region

provider "aws" {
  region  = "eu-west-2"
}
  • provider - we are using AWS, if you want to use another cloud provider you need to change this to the appropriate provider.
  • region - we will deploy the resources into eu-west-2 region (London)

VPC

resource "aws_vpc" "test-vpc" {
  cidr_block       = "10.0.0.0/16"
  tags = {
    Name = "terraform-test"

  }
}
  • A resource block declares a resource of a given type. In our case, we are creating a VPC
  • Name (test-vpc) - The name is an identifier that we can use throughout the Terraform code to refer to this resource
  • cidrblock - The CIDR block for the VPC
  • tags - A mapping of tags to assign to the resource.
  • Name - Name of the tag

Subnet

resource "aws_subnet" "test-public-subnet" {
    vpc_id = aws_vpc.test-vpc.id
    cidr_block = "10.0.1.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-2a"
    tags = {
        Name = "public-subnet"
    }
}
  • vpcid - We don't know the VPC ID yet, so we are telling Terraform to go and pick up the vpc_id from the previous step once created.
  • map_public_ip_onlaunch - Assign a public IP to the instances launched in this subnet
  • availability_zone - Launch the subnet into eu-west-2a AZ

Route table

Creating a new route table

resource "aws_route_table" "public-route" {
 vpc_id = aws_vpc.test-vpc.id
 tags = {
   Name = "public-route"
  }
} 

Internet Gateway

Creating a new Internet Gateway in the new VPC.

resource "aws_internet_gateway" "test-igw" {
 vpc_id = aws_vpc.test-vpc.id
 tags = {
        Name = "test-igw"
  }
} 

Modify the Routing table

resource "aws_route" "internet-access" {
  route_table_id         = aws_route_table.public-route.id
  destination_cidr_block = "0.0.0.0/0" 
  gateway_id             = aws_internet_gateway.test-igw.id

} 
  • Adding a default route with a next-hop as the IGW created in the previous step.

Route table association

resource "aws_route_table_association" "subnet-association" {
  subnet_id      = aws_subnet.test-public-subnet.id
  route_table_id = aws_route_table.public-route.id
} 
  • Associate the route-table with the public-subnet we created in the previous steps.

Launch the EC2 instance

resource "aws_instance" "test-ubuntu" {
  ami                    = "ami-006a0174c6c25ac06"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-public-subnet.id
  key_name               = "test-key"

  tags = {
    Name = "Test-Ubuntu"
    }
}
  • ami - AMI id for Ubuntu 18.04
  • instancetype - We are using t2.micro instance
  • subnetid - Launching the instance into the public-subnet
  • keyname - key pair we will be using to log in to the instance. (I have already created a key pair called "test-key" manually)

Your complete main.tf file would look like the following.

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

resource "aws_vpc" "test-vpc" {
  cidr_block       = "10.0.0.0/16"
  tags = {
    Name = "terraform-test"

  }
}

resource "aws_subnet" "test-public-subnet" {
    vpc_id = aws_vpc.test-vpc.id
    cidr_block = "10.0.1.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-2a"
    tags = {
        Name = "public-subnet"
    }
}

resource "aws_route_table" "public-route" {
 vpc_id = aws_vpc.test-vpc.id
 tags = {
   Name = "public-route"
  }
} 

resource "aws_internet_gateway" "test-igw" {
 vpc_id = aws_vpc.test-vpc.id
 tags = {
        Name = "test-igw"
  }
} 

resource "aws_route" "internet-access" {
  route_table_id         = aws_route_table.public-route.id
  destination_cidr_block = "0.0.0.0/0" 
  gateway_id             = aws_internet_gateway.test-igw.id

} 

resource "aws_route_table_association" "subnet-association" {
  subnet_id      = aws_subnet.test-public-subnet.id
  route_table_id = aws_route_table.public-route.id
} 

resource "aws_instance" "test-ubuntu" {
  ami                    = "ami-006a0174c6c25ac06"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.test-public-subnet.id
  key_name               = "test-key"

  tags = {
    Name = "Test-Ubuntu"
    }
}

Deployment

There are four Terraform commands that you need to remember.

  • Terraform init - This command initializes a working directory containing Terraform configuration files. This is the first command that should be run after writing a new Terraform configuration
  • Terraform plan - This command creates an execution plan, which lets you preview the changes that Terraform plans to make to your infrastructure.
  • Terraform apply - This command executes the actions proposed in a Terraform plan.
  • Terraform destroy - This command is a convenient way to destroy all remote objects managed by a particular Terraform configuration.

Terraform init

Run terraform init CLI command to download the provider code and required modules.

Suresh-MacBook:Terraform suresh$ terraform init

Initializing the backend...

Initializing provider plugins...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 2.57"

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

You can run terraform plan CLI command to check and prepare the deployment. It will not apply any changes or create any resources on AWS. The plan command is just to view the changes that Terraform would make.

Terraform apply

To apply the changes run terraform apply which will start provisioning the resources defined in the main.tf file.

Suresh-MacBook:Terraform suresh$ 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.test-ubuntu will be created
  + resource "aws_instance" "test-ubuntu" {

****output ommited***

Plan: 7 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_vpc.test-vpc: Creating...
aws_vpc.test-vpc: Creation complete after 2s [id=vpc-0f15344ace746e043]
aws_internet_gateway.test-igw: Creating...
aws_route_table.public-route: Creating...
aws_subnet.test-public-subnet: Creating...
aws_route_table.public-route: Creation complete after 1s [id=rtb-027d72975ce69bedf]
aws_internet_gateway.test-igw: Creation complete after 1s [id=igw-0bbdfe05e4b6ccbe4]
aws_route.internet-access: Creating...
aws_subnet.test-public-subnet: Creation complete after 2s [id=subnet-04352871522d6cc58]
aws_route_table_association.subnet-association: Creating...
aws_instance.test-ubuntu: Creating...
aws_route.internet-access: Creation complete after 1s [id=r-rtb-027d72975ce69bedf1080289494]
aws_route_table_association.subnet-association: Creation complete after 0s [id=rtbassoc-0ac9bcf9a2d2e0f9c]
aws_instance.test-ubuntu: Still creating... [10s elapsed]
aws_instance.test-ubuntu: Still creating... [20s elapsed]
aws_instance.test-ubuntu: Creation complete after 22s [id=i-07c5a9606eeb59fa2]

Apply complete! Resources: 7 added, 0 changed, 0 destroyed.

Now that we've deployed the VPC and instance, we can try SSH to it to verify everything is working as expected.

Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-1057-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Apr 21 12:46:04 UTC 2020

  System load:  0.0               Processes:           89
  Usage of /:   13.6% of 7.69GB   Users logged in:     0
  Memory usage: 15%               IP address for eth0: 10.0.1.204
  Swap usage:   0%

0 packages can be updated.
0 updates are security updates.



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@ip-10-0-1-204:~$ 

Terraform destroy

As the name suggests you can use terraform destroy command to remove all the resources you just created.

Suresh-MacBook:Terraform suresh$ terraform destroy

aws_vpc.test-vpc: Refreshing state... [id=vpc-0b0f7228d474d9203]
aws_route_table.public-route: Refreshing state... [id=rtb-05b509bfb18daa9ea]
aws_internet_gateway.test-igw: Refreshing state... [id=igw-09ed09f903600541f]
aws_subnet.test-public-subnet: Refreshing state... [id=subnet-0429c70ca8434f29b]
aws_instance.test-ubuntu: Refreshing state... [id=i-01617bb7327b1571d]
aws_route_table_association.subnet-association: Refreshing state... [id=rtbassoc-0f396d421944908d8]
aws_route.internet-access: Refreshing state... [id=r-rtb-05b509bfb18daa9ea1080289494]

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

Terraform will perform the following actions:

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_route_table_association.subnet-association: Destroying... [id=rtbassoc-0f396d421944908d8]
aws_route.internet-access: Destroying... [id=r-rtb-05b509bfb18daa9ea1080289494]
aws_instance.test-ubuntu: Destroying... [id=i-01617bb7327b1571d]
aws_route_table_association.subnet-association: Destruction complete after 0s
aws_route.internet-access: Destruction complete after 0s
aws_internet_gateway.test-igw: Destroying... [id=igw-09ed09f903600541f]
aws_route_table.public-route: Destroying... [id=rtb-05b509bfb18daa9ea]
aws_route_table.public-route: Destruction complete after 0s
aws_instance.test-ubuntu: Still destroying... [id=i-01617bb7327b1571d, 10s elapsed]
aws_internet_gateway.test-igw: Still destroying... [id=igw-09ed09f903600541f, 10s elapsed]
aws_instance.test-ubuntu: Still destroying... [id=i-01617bb7327b1571d, 20s elapsed]
aws_internet_gateway.test-igw: Still destroying... [id=igw-09ed09f903600541f, 20s elapsed]
aws_internet_gateway.test-igw: Destruction complete after 25s
aws_instance.test-ubuntu: Destruction complete after 29s
aws_subnet.test-public-subnet: Destroying... [id=subnet-0429c70ca8434f29b]
aws_subnet.test-public-subnet: Destruction complete after 0s
aws_vpc.test-vpc: Destroying... [id=vpc-0b0f7228d474d9203]
aws_vpc.test-vpc: Destruction complete after 0s

Destroy complete! Resources: 7 destroyed.

Closing Thoughts

In conclusion, if you're an absolute beginner looking to learn about Terraform, don't be intimidated. Terraform is easier than you might think to learn, even if you have just a basic understanding of AWS.

With its simple and intuitive syntax, comprehensive documentation, flexible approach to IaC, and modularity, Terraform is an excellent tool for managing your infrastructure as code. So why not give it a try?

References

https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

https://registry.terraform.io/providers/hashicorp/aws/latest/docs

https://developer.hashicorp.com/terraform/cli

Written by
Suresh Vina
Tech enthusiast sharing Networking, Cloud & Automation insights. Join me in a welcoming space to learn & grow with simplicity and practicality.
Comments
More from Packetswitch
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Packetswitch.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.