Skip to content

Commit

Permalink
feat(awstf): RDS support
Browse files Browse the repository at this point in the history
Co-authored-by: Jye Cusch<jye.cusch@gmail.com>
  • Loading branch information
jyecusch authored and tjholm committed Jun 27, 2024
1 parent 8009fe8 commit ec75023
Show file tree
Hide file tree
Showing 106 changed files with 3,777 additions and 153 deletions.
144 changes: 144 additions & 0 deletions cloud/aws/deploytf/.nitric/modules/rds/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Create a new random password for the RDS cluster
resource "random_password" "rds_password" {
length = 16
special = false
}

# Create a subnet group for the RDS instance
resource "aws_db_subnet_group" "rds_subnet_group" {
subnet_ids = var.private_subnet_ids
}

# Create a security group for the RDS instance
resource "aws_security_group" "rds_security_group" {
vpc_id = var.vpc_id

ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
self = true
}

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

# Create a role for the codebuild job
resource "aws_iam_role" "codebuild_role" {
name = "nitric-codebuild-role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
Service = "codebuild.amazonaws.com"
},
Action = "sts:AssumeRole"
}
]
})
}

# Attach managed policies to the codebuild role
locals {
codebuildManagedPolicies = {
"codeBuildAdmin" = "arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess"
"rdsAdmin" = "arn:aws:iam::aws:policy/AmazonRDSFullAccess"
"ec2Admin" = "arn:aws:iam::aws:policy/AmazonEC2FullAccess"
"cloudWatchLogs" = "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
"ecrReadonly" = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}
}

resource "aws_iam_role_policy_attachment" "codebuild_managed_policies" {
for_each = local.codebuildManagedPolicies

role = aws_iam_role.codebuild_role.name
policy_arn = each.value
}

# Create an RDS cluster with serverless v2
resource "aws_rds_cluster" "rds_cluster" {
cluster_identifier = "nitric-rds-cluster"
engine = "aurora-postgresql"
engine_mode = "provisioned"
engine_version = "13.14"
database_name = "nitric"
master_username = "nitric"
master_password = random_password.rds_password.result
db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.id
vpc_security_group_ids = [aws_security_group.rds_security_group.id]
skip_final_snapshot = true
deletion_protection = false
serverlessv2_scaling_configuration {
max_capacity = var.max_capacity
min_capacity = var.min_capacity
}
}

# Create a rds cluster instance
resource "aws_rds_cluster_instance" "rds_cluster_instance" {
cluster_identifier = aws_rds_cluster.rds_cluster.id
instance_class = "db.serverless"
engine = aws_rds_cluster.rds_cluster.engine
engine_version = aws_rds_cluster.rds_cluster.engine_version
db_subnet_group_name = aws_rds_cluster.rds_cluster.db_subnet_group_name
}



# Create an AWS Codebuild job to create a database on the RDS cluster
resource "aws_codebuild_project" "create_database" {
name = "nitric-create-database"
description = "Create the database on the RDS cluster"
build_timeout = 60
service_role = aws_iam_role.codebuild_role.arn

artifacts {
type = "NO_ARTIFACTS"
}


environment {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/amazonlinux2-x86_64-standard:4.0"
type = "LINUX_CONTAINER"

environment_variable {
name = "DB_PASSWORD"
value = random_password.rds_password.result
type = "PLAINTEXT"
}
}


vpc_config {
subnets = var.private_subnet_ids
security_group_ids = aws_rds_cluster.rds_cluster.vpc_security_group_ids
vpc_id = var.vpc_id
}

source {
type = "NO_SOURCE"
buildspec = jsonencode({
version = "0.2",
phases = {
build = {
commands = [
"echo 'Creating database $DB_NAME'",
# FIXME: Store the password in a secret manager
"export PGPASSWORD=$${DB_PASSWORD}",
# "CREATE DATABASE ${DB_NAME}" || echo "database ${DB_NAME} already exists"
"psql -h ${aws_rds_cluster.rds_cluster.endpoint} -U ${aws_rds_cluster.rds_cluster.master_username} -d ${aws_rds_cluster.rds_cluster.database_name} -c \"CREATE DATABASE $${DB_NAME}\" || echo \"database $${DB_NAME} already exists\""
]
}
}
})
}
}
29 changes: 29 additions & 0 deletions cloud/aws/deploytf/.nitric/modules/rds/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
output "cluster_endpoint" {
description = "The endpoint of the RDS cluster"
value = aws_rds_cluster.rds_cluster.endpoint
}

output "cluster_username" {
description = "The username to connect to the RDS cluster"
value = aws_rds_cluster.rds_cluster.master_username
}

output "cluster_password" {
description = "The password to connect to the RDS cluster"
value = aws_rds_cluster.rds_cluster.master_password
}

output "codebuild_role_arn" {
description = "The arn of the codebuild role"
value = aws_iam_role.codebuild_role.arn
}

output "security_group_id" {
description = "The security group id for the RDS cluster"
value = aws_security_group.rds_security_group.id
}

output "create_database_project_name" {
description = "The name of the create database codebuild project"
value = aws_codebuild_project.create_database.name
}
24 changes: 24 additions & 0 deletions cloud/aws/deploytf/.nitric/modules/rds/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
variable "vpc_id" {
type = string
description = "the VPC to assign to the RDS cluster"
}

variable "private_subnet_ids" {
type = list(string)
description = "private subnets to assign to the RDS cluster"
}

variable "min_capacity" {
type = number
description = "the minimum capacity of the RDS cluster"
}

variable "max_capacity" {
type = number
description = "the maximum capacity of the RDS cluster"
}

variable "stack_id" {
type = string
description = "The nitric stack ID"
}
23 changes: 15 additions & 8 deletions cloud/aws/deploytf/.nitric/modules/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ resource "aws_ecr_repository" "repo" {
data "aws_ecr_authorization_token" "ecr_auth" {
}

provider "docker" {
registry_auth {
address = data.aws_ecr_authorization_token.ecr_auth.proxy_endpoint
username = data.aws_ecr_authorization_token.ecr_auth.user_name
password = data.aws_ecr_authorization_token.ecr_auth.password
}
}

# Tag the provided docker image with the ECR repository url
resource "docker_tag" "tag" {
source_image = var.image
Expand Down Expand Up @@ -85,6 +77,13 @@ resource "aws_iam_role_policy_attachment" "basic-execution" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# Attach vpc access execution role if subnets are provided
resource "aws_iam_role_policy_attachment" "vpc-access" {
count = length(var.subnet_ids) > 0 ? 1 : 0
role = aws_iam_role.role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}

# Create a lambda function using the pushed image
resource "aws_lambda_function" "function" {
function_name = "${var.service_name}-${var.stack_id}"
Expand All @@ -97,6 +96,14 @@ resource "aws_lambda_function" "function" {
variables = var.environment
}

dynamic "vpc_config" {
for_each = length(var.subnet_ids) > 0 ? ["1"] : []
content {
subnet_ids = var.subnet_ids
security_group_ids = var.security_group_ids
}
}

depends_on = [docker_registry_image.push]

tags = {
Expand Down
39 changes: 27 additions & 12 deletions cloud/aws/deploytf/.nitric/modules/service/variables.tf
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
variable "service_name" {
type = string
description = "The name of the service"
type = string
description = "The name of the service"
}

variable "image" {
type = string
description = "The docker image to deploy"
type = string
description = "The docker image to deploy"
}

# environment variables
variable "environment" {
type = map(string)
description = "Environment variables to set on the lambda function"
type = map(string)
description = "Environment variables to set on the lambda function"
}

variable "stack_id" {
Expand All @@ -20,13 +20,28 @@ variable "stack_id" {
}

variable "memory" {
description = "The amount of memory to allocate to the lambda function"
type = number
default = 128
description = "The amount of memory to allocate to the lambda function"
type = number
default = 128
}

variable "timeout" {
description = "The timeout for the lambda function"
type = number
default = 10
description = "The timeout for the lambda function"
type = number
default = 10
}

variable "subnet_ids" {
description = "The subnet ids to use for the aws lambda function"
type = list(string)
default = []
}

variable "security_group_ids" {
description = "The security group ids to use for the aws lambda function"
type = list(string)
default = []

}


Loading

0 comments on commit ec75023

Please sign in to comment.