Table of Contents

Introduction

Hello again. I hope you guys are doing awesome, and I am back again with a new blog – how to create AWS application stack using Terraform.

It is obvious that the mind gets easily bored doing the same thing repeatedly all over and over. Being an AWS cloud solution architect, I have to manage the resources, even sometimes I have to provision server resources twice or thrice a day.

The provision of resources seems so easy, but let’s assume you have to create VPC on AWS that contains subnets, both public and private, public for hosting frontend i.e., Web Server and Private for Database.

IPs – I am working with VPC so it will contain both public and private IPs, and of course using CIDR block. Apart from that, you might need Route Table; here, I am using public and private subnet as each subnet required one Route Table. Still, Internet Gateway (IG) is missing, which precisely takes care of communication between instances and the Internet.

For security reasons, our Private Subnet (Database) is only through using Public subnet, let’s understand this through a Diagram.

aws cloud

Lots of configuration are there to host a single secure web application. Here we need a viable solution. From now onwards, if you need the same Stack and resources, then you won’t be required to spend the same amount of time in configuring VPC. We can achieve this using Terraform as IaaC, yes Terraform is a tool used for Infrastructure automation; it is an approach for provisioning and managing server resources using configuration file or script.

What is infrastructure as a code?

Infrastructure as a Code also known as -IaaC, is the management of infrastructure networks, load balancers, virtual machines, and connection topology within a dynamic and vivid model. This method smoothly combines DevOps principles into the AWS team’s process, making sure that managing infrastructure follows the same version control rules as handling source code. AWS consultation services play a pivotal role in ensuring that this integration is executed smoothly, allowing businesses to harness the full potential of IaaC while optimizing their infrastructure on the AWS platform.

Let’s get back on the track and understand how to write Terraform scripting and how to configure the AWS account.

Our Terraform script is going to use AccessKey and SecretKey for the provision and manage AWS resources.

Go to IAM users, security credential and save the ACCESS_KEY and the SECRET_ACCESS_KEY.
Setup Provider for Terraform.

In terraform script, you will have to mention provider, in the below example, AWS is the provider. Provider.tf file looks something like;

Copy Text
provider "aws" {
    access_key = "${var.aws_access_key}"
    secret_key = "${var.aws_secret_key}"
    region = "${var.aws_region}"
}

Note: We are getting this var.variable_name value from variable.tf file. Terraform scripting for VPC

Copy Text
resource "aws_instance" "gate" {
    ami = "${var.nat_ami}"
    instance_type = "t2.small"
    key_name = "${var.aws_key_name}"
    vpc_security_group_ids = ["${aws_security_group.gate.id}"]
    subnet_id = "${aws_subnet.eu-west-1-public.id}"
    associate_public_ip_address = true
    source_dest_check = false

    tags {
        Name = "VPC NAT"
    }
}

resource "aws_instance" "web-instance" {
    ami = "${lookup(var.amis, var.aws_region)}"
    instance_type = "t2.small"
    key_name = "${var.aws_key_name}"
    vpc_security_group_ids = ["${aws_security_group.web.id}"]
    subnet_id = "${aws_subnet.eu-west-1-public.id}"
    associate_public_ip_address = true
    source_dest_check = false


    tags {
        Name = "Web Server"
    }
}

resource "aws_instance" "db-instance" {
    ami = "${lookup(var.amis, var.aws_region)}"
    instance_type = "t2.small"
    key_name = "${var.aws_key_name}"
    vpc_security_group_ids = ["${aws_security_group.db.id}"]
    subnet_id = "${aws_subnet.eu-west-1-private.id}"
    source_dest_check = false

    tags {
        Name = "DB Server"
    }
}

resource "aws_vpc" "main_vpc" {
    cidr_block = "${var.vpc_cidr}"
    enable_dns_hostnames = true
    tags {
        Name = "bacancy-blog-vpc"
    }
}

resource "aws_eip" "gate" {
    instance = "${aws_instance.gate.id}"
    vpc = true
}

resource "aws_eip" "web-instance" {
    instance = "${aws_instance.web-instance.id}"
    vpc = true
}

resource "aws_route_table" "eu-west-1-public" {
    vpc_id = "${aws_vpc.main_vpc.id}"

    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.ig-main.id}"
    }

    tags {
        Name = "Public Subnet"
    }
}


resource "aws_route_table_association" "eu-west-1-public" {
    subnet_id = "${aws_subnet.eu-west-1-public.id}"
    route_table_id = "${aws_route_table.eu-west-1-public.id}"
}

resource "aws_route_table" "eu-west-1-private" {
    vpc_id = "${aws_vpc.main_vpc.id}"

    route {
        cidr_block = "0.0.0.0/0"
        instance_id = "${aws_instance.gate.id}"
    }

    tags {
        Name = "Private Subnet"
    }
}

resource "aws_route_table_association" "eu-west-1-private" {
    subnet_id = "${aws_subnet.eu-west-1-private.id}"
    route_table_id = "${aws_route_table.eu-west-1-private.id}"
}

resource "aws_subnet" "eu-west-1-public" {
    vpc_id = "${aws_vpc.main_vpc.id}"

    cidr_block = "${var.public_subnet_cidr}"

    tags {
        Name = "Public Subnet"
    }
}

resource "aws_subnet" "eu-west-1-private" {
    vpc_id = "${aws_vpc.main_vpc.id}"

    cidr_block = "${var.private_subnet_cidr}"

    tags {
        Name = "Private Subnet"
    }
}

resource "aws_internet_gateway" "ig-main" {
    vpc_id = "${aws_vpc.main_vpc.id}"
}

In the above vpc.tf file I have created VPC, now it’s time for security groups to create a Terraform file.

Copy Text
resource "aws_security_group" "gate" {
    name = "sg_for_nat_vpc"

    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["${var.private_subnet_cidr}"]
    }
    ingress {
        from_port = 443
        to_port = 443
        protocol = "tcp"
        cidr_blocks = ["${var.private_subnet_cidr}"]
    }
    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    egress {
        from_port = 443
        to_port = 443
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    egress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["${var.vpc_cidr}"]
    }
    egress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    vpc_id = "${aws_vpc.main_vpc.id}"

    tags {
        Name = "sg_for_nat"
    }
}

resource "aws_security_group" "web" {
    name = "webserver_sg"
    description = "Allow incoming HTTP connections."

    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    ingress {
        from_port = 443
        to_port = 443
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    egress { # MySQL
        from_port = 3306
        to_port = 3306
        protocol = "tcp"
        cidr_blocks = ["${var.private_subnet_cidr}"]
    }

    vpc_id = "${aws_vpc.main_vpc.id}"

    tags {
        Name = "web_server_sg"
    }
}

resource "aws_security_group" "db" {
    name = "database_sg"
    description = "Allow incoming database connections."

    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["${var.vpc_cidr}"]
    }
    ingress {
        from_port = -1
        to_port = -1
        protocol = "icmp"
        cidr_blocks = ["${var.vpc_cidr}"]
    }
    ingress {
        from_port = 3306
        to_port = 3306
        protocol = "tcp"
        security_groups = ["${aws_security_group.web.id}"]
    }
    egress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    egress {
        from_port = 443
        to_port = 443
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }


    vpc_id = "${aws_vpc.main_vpc.id}"

    tags {
        Name = "database_sg"
    }
}

Terraforming security groups are pretty easy. You only have to define ingress and egress rules.

Copy Text
variable "aws_region" {
    default = "eu-west-1"
}
variable "aws_access_key" {
    default = "access_key"
}
variable "aws_secret_key" {
    default = "secret_key"
}

variable "aws_key_name" {
    default = "bacancy_blog"
}

variable "vpc_cidr" {
    default = "0.0.0.0"
}

variable "public_subnet_cidr" {
    default = "0.0.0.0"
}

variable "private_subnet_cidr" {
    default = "0.0.0.0"
}

variable "amis" {
    default = {
        eu-west-1 = "ami-0713f98de93617bb4"
    }
}

Now it’s time for variable.tf view rawvariable.tf hosted with ❤ by GitHub
To create the AWS resource using Terraform script, please run the below commands.

terraform init
terraform apply

Please make sure you provide the correct region and AMI else you will get errors. In the above scenario, I have discussed about the VPC; you can customize based on your application stack.

I hope you have completely got the idea of how Terraform resource allocation and mapping is working. But, if you want to gain more knowledge on this, then I would like to request you to visit this link where all the AWS services and it’s mapping technology have mentioned and explained in detail. Also you can connect with our AWS expert and hire DevOps developers too.

Build Your Agile Team

Hire Skilled Developer From Us

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?