In this example we are going to create an AWS RDS for Postgres with Terraform. It will be publicly accessible from our local machine for testing purposes. In a real world scenario, you should provision AWS RDS instances in private subnets to shield them from direct internet traffic. You would have an application running in a public subnet and accessing to RDS in private subnet.


Prerequisites


Make sure your IAM group or user has iam:*,ec2:*,rds:*,rds:* permissions. However, ideally you should use bare minimum permissions. You can use tools like iamlive to identify exact permissions.


export TF_VAR_username=SecretUsername
export TF_VAR_password=SecretPassword

[default]
region = eu-west-1
output = json

[profile development]
source_profile = default
role_session_name = github-actions
role_arn = arn:aws:iam::1234567890:role/devops-provisioner

[default]
aws_access_key_id = QWERTYUIO12345678
aws_secret_access_key = sdfg23456/DFGHJKL9876543+plv/dft543

Structure


blog
└── terraform
└── development
├── aws_db_instance.tf
├── aws_security_group.tf
├── main.tf
├── outputs.tf
├── providers.tf
└── variables.tf

Files


variables.tf


variable "username" {
description = "The master username for the database."
type = string
sensitive = true
}

variable "password" {
description = "The master password for the database."
type = string
sensitive = true
}

main.tf


terraform {
required_version = "~> 1.4.4"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.30.0"
}
}
}

providers.tf


provider "aws" {
profile = "development"
region = "eu-west-1"
}

aws_security_group.tf


resource "aws_security_group" "postgres" {
name = "postgres-security-group"
description = "Security group for Postgres database"

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

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

aws_db_instance.tf


resource "aws_db_instance" "blog" {
allocated_storage = 5
storage_type = "gp2"
instance_class = "db.t2.micro"
identifier = "blog"
engine = "postgres"
engine_version = "12.10"
parameter_group_name = "default.postgres12"

db_name = "blog"
username = var.username
password = var.password

vpc_security_group_ids = [aws_security_group.postgres.id]
publicly_accessible = true # Only for testing!
skip_final_snapshot = true
}

outputs.tf


output "blog_database" {
value = aws_db_instance.blog.endpoint
}

Run


Just bare in mind that creating RDS instance takes a bit of time.


$ terraform apply
...
aws_db_instance.blog: Creation complete after 3m37s [id=blog]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

blog_database = "blog.qwert12345.eu-west-1.rds.amazonaws.com:5432"

Example connection strings


postgres://SecretUsername:SecretPassword@blog.qwert12345.eu-west-1.rds.amazonaws.com:5432/blog
postgres://SecretUsername:SecretPassword@blog.qwert12345.eu-west-1.rds.amazonaws.com:5432/blog?sslmode=disable