Now available in non-serverless flavour!

This commit is contained in:
Greyscale 2024-12-26 21:56:31 +01:00
parent 1fd8e21a33
commit d806336734
Signed by: grey
GPG key ID: DDB392AE64B32D89
10 changed files with 315 additions and 0 deletions

5
cloud/aws/rds/aws.tf Normal file
View file

@ -0,0 +1,5 @@
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
data "aws_vpc" "current" {
id = data.aws_security_group.source.vpc_id
}

61
cloud/aws/rds/debug.tf Normal file
View file

@ -0,0 +1,61 @@
resource "local_file" "debug" {
content = nonsensitive(jsonencode({
rds = {
instance_name = var.instance_name,
sanitised_name = local.sanitised_name
tennants = var.tenants,
application_arn = try(var.application.arn, null),
application_name = try(var.application.name, null),
engine = {
requested = {
engine = var.engine,
version = var.engine_version
}
resolved = {
engine = data.aws_rds_engine_version.latest.engine,
version = data.aws_rds_engine_version.latest.version,
match = data.aws_rds_engine_version.latest,
}
}
#endpoints = {
# write = aws_rds_cluster_endpoint.endpoint["write"].endpoint,
# read = aws_rds_cluster_endpoint.endpoint["read"].endpoint
#}
admin = {
username = module.admin_identity.username
password = nonsensitive(module.admin_identity.password)
}
}
tenants = var.tenants
}))
filename = "${path.root}/.debug/aws/rds/${var.instance_name}.provided.json"
file_permission = "0600"
}
resource "local_file" "debug_result" {
content = nonsensitive(jsonencode({
rds = {
instance_name = var.instance_name,
tennants = var.tenants,
application_arn = try(var.application.arn, null),
application_name = try(var.application.name, null),
engine = {
requested = {
engine = var.engine,
version = var.engine_version
}
resolved = {
engine = data.aws_rds_engine_version.latest.engine,
version = data.aws_rds_engine_version.latest.version,
match = data.aws_rds_engine_version.latest,
}
}
endpoints = aws_db_instance.instance.endpoint
}
tenants = merge({ admin = {
username = module.admin_identity.username
password = nonsensitive(module.admin_identity.password)
} }, local.output_tenants)
}))
filename = "${path.root}/.debug/aws/rds/${var.instance_name}.result.json"
file_permission = "0600"
}

68
cloud/aws/rds/inputs.tf Normal file
View file

@ -0,0 +1,68 @@
variable "instance_name" {
type = string
description = "The name of the RDS serverless instance"
default = "serverless-multitennant"
}
locals {
sanitised_name = replace(replace(lower(var.instance_name), "[^a-z0-9A-Z-]", "-"), " ", "-")
}
variable "tenants" {
type = map(object({
username = string
database = string
active = optional(bool, true)
}))
default = null
}
variable "application" {
description = "The AWS myApplication to be associated with this cluster"
type = object({
arn = string
name = string
description = string
application_tag = map(string)
})
default = null
}
variable "engine" {
type = string
description = "The database engine to use. This must be either aurora-mysql or aurora-postgresql"
default = "mysql"
validation {
error_message = "Must be either ${join(" or ", local.supported_engines)}."
condition = contains(local.supported_engines, var.engine)
}
}
locals {
supported_engines = ["mysql", "postgresql", "mariadb", ]
is_mysql = var.engine == "mysql"
is_postgres = var.engine == "postgresql"
is_mariadb = var.engine == "mariadb"
}
variable "engine_version" {
type = string
default = null
}
variable "backup_window" {
type = string
description = "The daily time range during which automated backups are created if automated backups are enabled."
default = "03:00-05:00"
}
variable "backup_retention_period_days" {
type = number
default = 30
validation {
error_message = "backup_retention_period_days must be between 1 and 35."
condition = var.backup_retention_period_days >= 1 && var.backup_retention_period_days <= 35
}
}
variable "skip_final_snapshot" {
type = bool
description = "Determines whether a final DB snapshot is created before the DB cluster is deleted."
default = false
}
variable "enable_performance_insights" {
type = bool
default = false
}

16
cloud/aws/rds/outputs.tf Normal file
View file

@ -0,0 +1,16 @@
locals {
output_tenants = {
#for key, tenant in module.tenants : key => {
# username = tenant.username
# database = tenant.database
# password = tenant.password
# connection_string = tenant.connection_string
#}
}
}
output "tenants" {
value = local.output_tenants
}
output "admin" {
value = module.admin_identity
}

View file

@ -0,0 +1,13 @@
data "aws_rds_certificate" "default" {
id = aws_db_instance.instance.ca_cert_identifier
latest_valid_till = true
}
data "http" "cert_data" {
url = "https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem"
}
output "cert" {
value = data.aws_rds_certificate.default
}
output "cert_data" {
value = data.http.cert_data.response_body
}

68
cloud/aws/rds/rds.tf Normal file
View file

@ -0,0 +1,68 @@
data "aws_rds_engine_version" "latest" {
engine = var.engine
version = var.engine_version
latest = true
}
resource "aws_kms_key" "db_key" {
description = "RDS ${var.instance_name} Encryption Key"
tags = merge(
try(var.application.application_tag, {}),
{
TerraformSecretType = "RDSMasterEncryptionKey"
}
)
}
variable "instance_class" {
type = string
description = "The instance class to use for the RDS instance"
default = "db.t4g.small"
}
module "admin_identity" {
source = "../../../utils/identity"
username_words = 2
}
variable "allocated_storage_gb" {
type = number
default = 5
description = "The storage size for the RDS instance, measured in GB."
}
variable "max_allocated_storage_gb" {
type = number
default = 100
description = "The maximum storage size for the RDS instance, measured in GB."
}
resource "aws_db_instance" "instance" {
identifier_prefix = "${local.sanitised_name}-"
instance_class = var.instance_class
engine = data.aws_rds_engine_version.latest.engine
engine_version = data.aws_rds_engine_version.latest.version
storage_encrypted = true
kms_key_id = aws_kms_key.db_key.arn
publicly_accessible = false
apply_immediately = true
db_subnet_group_name = aws_db_subnet_group.sg.name
vpc_security_group_ids = [aws_security_group.rds.id]
skip_final_snapshot = var.skip_final_snapshot
username = module.admin_identity.username
password = module.admin_identity.password
backup_window = var.backup_window
backup_retention_period = var.backup_retention_period_days
allocated_storage = var.allocated_storage_gb
max_allocated_storage = var.max_allocated_storage_gb
performance_insights_enabled = var.enable_performance_insights
performance_insights_retention_period = var.enable_performance_insights ? 7 : null
performance_insights_kms_key_id = var.enable_performance_insights ? aws_kms_key.db_key.arn : null
lifecycle {
create_before_destroy = false
}
tags = merge(
try(var.application.application_tag, {}),
{}
)
}
output "endpoints" {
value = aws_db_instance.instance.endpoint
}

View file

@ -0,0 +1,24 @@
resource "aws_security_group" "rds" {
name = join("-", [var.instance_name, "rds"])
description = "RDS Security Group for ${var.instance_name}"
vpc_id = data.aws_vpc.current.id
tags = merge(
try(var.application.application_tag, {}),
{}
)
}
variable "source_security_group_id" {
type = string
description = "The security group ID to allow access to the RDS instance"
}
data "aws_security_group" "source" {
id = var.source_security_group_id
}
resource "aws_security_group_rule" "sgr" {
security_group_id = aws_security_group.rds.id
type = "ingress"
protocol = "tcp"
from_port = var.engine == "aurora-postgres" ? 5432 : 3306
to_port = var.engine == "aurora-postgres" ? 5432 : 3306
source_security_group_id = var.source_security_group_id
}

22
cloud/aws/rds/subnets.tf Normal file
View file

@ -0,0 +1,22 @@
variable "aws_subnets" {
description = "Pass an aws_subnets data object to the module"
type = object({
ids = list(string)
})
}
data "aws_subnets" "subnets" {
filter {
name = "subnet-id"
values = var.aws_subnets.ids
}
}
resource "aws_db_subnet_group" "sg" {
name = lower(join("-", [var.instance_name, "subnet-group"]))
subnet_ids = data.aws_subnets.subnets.ids
tags = merge(
try(var.application.application_tag, {}),
{
Name = "${var.instance_name} Subnet Group"
}
)
}

12
cloud/aws/rds/tenants.tf Normal file
View file

@ -0,0 +1,12 @@
/*module "tenants" {
depends_on = [aws_db_instance.instance]
for_each = var.tenants
source = "./tenant"
username = each.value.username
database = each.value.database
vpc_id = data.aws_vpc.current.id
cluster_id = aws_rds_cluster.cluster.id
engine = data.aws_rds_engine_version.latest.engine
admin_username = module.admin_identity.username
admin_password = module.admin_identity.password
}*/

View file

@ -0,0 +1,26 @@
terraform {
required_version = "~> 1.6"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
null = {
source = "hashicorp/null"
version = "~> 3.0"
}
ssh = {
source = "matthewbaggett/ssh"
version = "~> 0.1"
}
}
}