I recently started working with Terraform and decide to write a post about it. This would be an introduction to managing AWS using Terraform.
Terraform helps to automate the deployment of servers and other infrastructure on AWS.
Scenario
Let's say we need to create VPC, public subnet, route table, Internet gateway and EC2 using Terraform.
Follow the instructions here to install Terraform https://www.terraform.io/downloads.html
Once installed you should be able to check the version using terraform -v
Suresh-MacBook:~ suresh$ terraform -v
Terraform v0.12.24
Create IAM user in AWS
I already created a user in AWS with programatic access and provide full admin access. Copy the Access key ID and Secret access key which will enable Terraform to make changes in AWS. You can 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"

Deployment
- Go to your workspace, create a new directory and go inside the directory.
- Create a file called deploy-ec2.tf (can be anything)
Suresh-MacBook:Terraform suresh$ pwd
/Users/sureshvinasiththamby/Documents/Terraform <<
Suresh-MacBook:Terraform sureshvinasiththamby$ ls
deploy-ec2.tf << logs.txt terraform.tfstate terraform.tfstate.backup
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.
- region - we will deploy the resources into eu-west-2 (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) - 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
resource "aws_route_table" "public-route" {
vpc_id = aws_vpc.test-vpc.id
tags = {
Name = "public-route"
}
}
- Create a route table in the test-vpc
Internet Gateway
resource "aws_internet_gateway" "test-igw" {
vpc_id = aws_vpc.test-vpc.id
tags = {
Name = "test-igw"
}
}
- Create an Internet Gateway in the test-vpc
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 of 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
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 - kaey pair we will be using to login to the instance. I have already created a key pair called "test-key"
Deployment
Run terraform init 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.
You can run terraform plan command to check and prepare the deployment. It will not apply or create any resource on AWS.
Now we are ready and run terraform apply to start the deployment.
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.
Verify





SSH into the Ubuntu server with the public IP and test-key keypair.
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.
The end
Reference
