Terraform + AWS

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
working directory

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

Provider: AWS - Terraform by HashiCorp
The Amazon Web Services (AWS) provider is used to interact with the many resources supported by AWS. The provider needs to be configured with the proper credentials before it can be used.
Buy me a coffeeBuy me a coffee