Automating AWS Infrastructure with Terraform

Automating AWS Infrastructure with Terraform

This article is useful for cloud enthusiasts, DevOps engineers, and developers. Let's outline a scenario-based guide to demonstrate how to use Terraform for setting up a basic AWS infrastructure.


Introduction

Infrastructure as Code (IaC) is a key practice in modern DevOps that allows teams to manage and provision infrastructure using code. Terraform, an open-source tool developed by HashiCorp, is widely used for this purpose due to its flexibility and support for multiple cloud providers, including AWS. In this guide, I will walk you through a real-world scenario of setting up AWS infrastructure using Terraform.

Scenario Overview

Imagine you are tasked with setting up a new environment on AWS for a web application. The requirements are:

  1. VPC (Virtual Private Cloud): To isolate our resources.

  2. Subnets: Public and private subnets to organize resources.

  3. EC2 Instances: To run the web servers.

  4. Security Groups: To control the traffic to and from the EC2 instances.

  5. RDS Instance: For the backend database.

Set Up AWS Credentials Using the AWS CLI

The most common way to configure AWS credentials is by using the AWS CLI. Here’s how you can do it:

  1. Install the AWS CLI: If you haven't already installed it, you can follow the AWS CLI installation guide.

  2. Configure AWS CLI: Run the following command to configure the AWS CLI with your credentials:

     aws configure
    

    You will be prompted to enter your AWS Access Key ID, Secret Access Key, default region name, and default output format. These credentials will be saved in the ~/.aws/credentials file on Unix/Linux/macOS or %USERPROFILE%\.aws\credentials on Windows.

2. Set AWS Credentials in Environment Variables

Terraform also supports using environment variables for AWS credentials. You can set them like this:

  • Linux/macOS:

      export AWS_ACCESS_KEY_ID="your_access_key"
      export AWS_SECRET_ACCESS_KEY="your_secret_key"
      export AWS_DEFAULT_REGION="us-east-1"
    
  • Windows (Command Prompt):

      set AWS_ACCESS_KEY_ID=your_access_key
      set AWS_SECRET_ACCESS_KEY=your_secret_key
      set AWS_DEFAULT_REGION=us-east-1
    

Replace "your_access_key" and "your_secret_key" with your actual AWS access key ID and secret access key.

3. Using a Shared Credentials File

If you have multiple AWS profiles set up in a shared credentials file (e.g., ~/.aws/credentials), you can specify which profile Terraform should use by adding the profile argument to the AWS provider block:

provider "aws" {
  region  = "us-east-1"
  profile = "your_profile_name"
}

Replace "your_profile_name" with the name of the profile you want to use.

Prerequisites

  • Basic understanding of AWS services (VPC, EC2, RDS, etc.).

  • Terraform installed.

  • AWS CLI installed and configured with your credentials.

  • An AWS account with permissions to create the necessary resources.

  • Windows user should install (Git Bash and VS Code) to follow along

Step 1: Set Up Your Terraform Environment

First, create a new directory for your Terraform configuration files, by running the following commands. Please note I will be using Git Bash and VS Code in this project.

mkdir terraform-aws-setup
cd terraform-aws-setup

Step 2: Define Your AWS Provider

Create a file named main.tf to define the AWS provider. This tells Terraform to use AWS as the target for resource provisioning.

Copy and paste this code below in your main.tf file, don't forget to save.

# main.tf
provider "aws" {
  region = "us-east-1"
}

Step 3: Create a VPC

In the same main.tf file, add the configuration to create a VPC.

# main.tf
resource "aws_vpc" "main_vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "main_vpc"
  }
}

Step 4: Create Subnets

Next, define public and private subnets within the VPC.

# main.tf
resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.main_vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "public_subnet"
  }
}

resource "aws_subnet" "private_subnet" {
  vpc_id            = aws_vpc.main_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-east-1b"

  tags = {
    Name = "private_subnet"
  }
}

Step 5: Set Up Security Groups

Create a security group to allow HTTP and SSH access to the EC2 instances.

# main.tf
resource "aws_security_group" "web_sg" {
  vpc_id = aws_vpc.main_vpc.id

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

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web_sg"
  }
}

Step 6: Launch EC2 Instances

Define the EC2 instances in the main.tf file.

# web_server
resource "aws_instance" "web_server" {
  ami                    = "ami-0c94855ba95c71c99"  # Replace with your actual AMI ID
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.public_subnet.id  # Ensure this is a valid subnet ID
  vpc_security_group_ids = [aws_security_group.web_sg.id]  # Use security group IDs

  # Other necessary configurations
  tags = {
    Name = "web_server"
  }
}

Step 7: Set Up RDS Instance

Add the configuration to create an RDS instance for the database.

# web_app_db
resource "aws_db_instance" "web_app_db" {
  allocated_storage    = 20
  engine               = "mysql"
  instance_class       = "db.t3.micro"
  db_name              = "mydb"
  username             = "admin"
  password             = "password"
  parameter_group_name = "default.mysql8.0"
  skip_final_snapshot  = true
  vpc_security_group_ids = [aws_security_group.web_sg.id]
  db_subnet_group_name = aws_db_subnet_group.db_subnet_group.name
}

resource "aws_db_subnet_group" "db_subnet_group" {
  name       = "my-db-subnet-group"
  subnet_ids = [
    aws_subnet.private_subnet.id,  # Subnet in AZ1
    aws_subnet.public_subnet.id   # Subnet in AZ2
  ]

  tags = {
    Name = "db_subnet_group"
  }
}

Save your main.tf file

Step 8: Initialize Terraform

Run the "terraform init" command to initialize your Terraform workspace. This will download the necessary provider plugins.

terraform init

Step 9: Plan and Apply

Generate an execution plan with:

terraform plan

Apply the changes by running this command, "terraform apply":

terraform apply

Confirm the action, and Terraform will proceed to create your AWS infrastructure as defined.

Step 10: Verify the Setup

After the Terraform script completes, log in to the AWS Management Console and check:

  • The VPC and subnets are created.

    Click the "VPC ID" to see the created subnet, then scroll down to the "Subnet" section.

  • EC2 instance is running with the correct security group settings. Search and select "EC2" in your AWS console.

    Click on the Instance ID as shown above to verify the security group. Scroll down and select the "Security" tab.

  • RDS instance is up and connected to the private subnet. Search and select "RDS" in your AWS console. Click the "DB Instances" link to view details.

    Click "DB identifier" to view more details as shown below.

    Scroll down to "Connectivity & Security" to see the following information:

Step 11 : Clean up

Run this command "terraform destroy" and type "yes" when you are prompted to delete all the resources you created with "main.tf"

You should get a similar message like this:

Final Thought

Using Terraform to manage AWS infrastructure allows for consistent and repeatable deployments. By following this guide, you have automated the process of creating a VPC, subnets, EC2 instances, security groups, and an RDS instance, all with a few lines of code. This approach reduces the risk of manual errors and enhances collaboration through version-controlled infrastructure definitions.

Further Learning

  • Explore Terraform modules to reuse code.

  • Check out AWS Best Practices for designing robust infrastructure.

  • Try integrating Terraform with CI/CD pipelines for automated deployments.

Thanks

:Valentine Stephen