Terraform Hands-On: Setting Up a Database for a Web Application Using AWS RDS with Terraform

I will walk through the steps to provision a database for a web application using AWS RDS (Relational Database Service) with Terraform. This setup will include creating a subnet group, a security group, IAM roles, and an RDS instance. Let's dive into the details.

Prerequisites

Before we begin, ensure you have the following:

  1. Terraform installed on your local machine.

  2. AWS credentials configured (e.g., using aws configure).

  3. Subnets in your VPC to deploy the database.

Project Structure

First, let's outline the structure of our Terraform project:

  1. Configuring the AWS Provider In provider.tf, we start by configuring the AWS provider. This tells Terraform to use AWS for provisioning resources.
# Configure AWS provider
provider "aws" {
  region = var.aws_region
}
  1. Defining Variables We define our variables in variables.tf to make our configuration flexible and reusable. This includes the AWS region, database engine, instance class, database name, username, password, and subnet IDs.
variable "aws_region" {
  description = "AWS region to deploy resources in"
  default     = "us-east-2"
}

variable "subnet_ids" {
  type        = list(string)
  description = "List of subnet IDs for the DB subnet group"
}

# Define variables
variable "db_engine" {
  default = "mysql"
}

variable "db_instance_class" {
  default = "db.t3.micro"
}

variable "db_name" {
  default = "mydatabase"
}

variable "db_username" {
  default = "admin"
}

variable "db_password" {
  default = "abcxyz123"  # Replace with secure password
}
  1. Provisioning the RDS Instance

    We provision the RDS instance using the specified parameters. We associate the instance with the subnet group and security group that we create. Creating an IAM role that the RDS instance can assume. This role allows the RDS to interact with other AWS services securely.

# Create a DB subnet group
resource "aws_db_subnet_group" "my_subnet_group" {
  name       = "my-subnet-group"
  subnet_ids = var.subnet_ids
  tags = {
    Name = "My DB Subnet Group"
  }
}

# Create a DB security group
resource "aws_security_group" "db_security_group" {
  name        = "db-security-group"
  description = "Allow database inbound traffic"

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

  tags = {
    Name = "DB Security Group"
  }
}

# Create an IAM role for RDS
resource "aws_iam_role" "rds_role" {
  name = "rds-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Effect    = "Allow",
      Principal = {
        Service = "rds.amazonaws.com"
      },
      Action    = "sts:AssumeRole"
    }]
  })
}

# Create RDS instance
resource "aws_db_instance" "my_database" {
  identifier           = "mydatabase-instance"
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = var.db_engine
  engine_version       = "8.0.35"
  instance_class       = var.db_instance_class
  db_name                 = var.db_name
  username             = var.db_username
  password             = var.db_password
  db_subnet_group_name = aws_db_subnet_group.my_subnet_group.name
  vpc_security_group_ids = [aws_security_group.db_security_group.id]
  iam_database_authentication_enabled = true
  skip_final_snapshot = true
  publicly_accessible = false
  tags = {
    Name = "My Database"
  }
}

# Output
output "db_endpoint" {
  value = aws_db_instance.my_database.endpoint
}
  1. Outputs

    We define outputs to display the endpoint of the RDS instance after it has been created. This endpoint is essential for connecting your web application to the database.

output "database_endpoint" {
  description = "Endpoint of the provisioned database"
  value       = aws_db_instance.my_database.endpoint
}
  1. terraform.tfvars Block

     aws_region   = "us-east-2"
     subnet_ids   = ["subnet-0eaa8b8dbef1a4749", "subnet-022f81991f8a78cd6", "subnet-049a83138e31b1e8d"]
    

Terraform Initialization (terraform init)

The terraform init command initializes a Terraform working directory by downloading necessary providers and modules defined in your configuration files (main.tf, variables.tf, etc.).

terraform init

Terraform Plan (terraform plan)

The terraform plan command creates an execution plan detailing the actions Terraform will take to achieve the desired state as defined in your configuration files.

terraform plan

Terraform Apply (terraform apply)

The terraform apply command executes the actions proposed in the execution plan generated by terraform plan, provisioning and managing infrastructure according to your Terraform configuration.

 terraform apply

Terraform Destroy (terraform destroy)

The terraform destroy command deletes the resources made by the apply command.

 terraform destroy

Conclusion:

We have successfully set up a database for a web application using AWS RDS with Terraform. This setup includes creating necessary subnet groups, security groups, IAM roles, and the RDS instance itself. Terraform makes it easier to manage infrastructure as code, allowing for version control, collaboration, and automation