Skip to content

Commit

Permalink
Allow database user and password to be optional
Browse files Browse the repository at this point in the history
  • Loading branch information
nitrocode committed Jul 7, 2021
1 parent cb41a4c commit 1ea1d29
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 13 deletions.
85 changes: 74 additions & 11 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module "final_snapshot_label" {
}

locals {
enabled = module.this.enabled

computed_major_engine_version = var.engine == "postgres" ? join(".", slice(split(".", var.engine_version), 0, 1)) : join(".", slice(split(".", var.engine_version), 0, 2))
major_engine_version = var.major_engine_version == "" ? local.computed_major_engine_version : var.major_engine_version

Expand All @@ -17,15 +19,76 @@ locals {
)

availability_zone = var.multi_az ? null : var.availability_zone

create_user = local.enabled && length(var.database_user) == 0
create_password = local.enabled && length(var.database_password) == 0

ssm_enabled = local.enabled && var.ssm_enabled
ssm_key_prefix = format("/%v/%v", var.ssm_path_prefix, var.database_name)
ssm_key_user = format("%s/%s", local.ssm_key_prefix, "admin/db_user")
ssm_key_user_desc = "RDS Username for the master DB user"
ssm_key_password = format("%s/%s", local.ssm_key_prefix, "admin/db_password")
ssm_key_password_desc = "RDS Password for the master DB user"

database_user = local.create_user ? join("", random_pet.database_user.*.id) : var.database_user
database_password = local.create_password ? join("", random_password.database_password.*.result) : var.database_password
}

resource "random_pet" "database_user" {
count = local.create_user ? 1 : 0

# word length
length = 3

keepers = {
db_name = var.database_name
}
}

resource "random_password" "database_password" {
count = local.create_password ? 1 : 0

# character length
length = 33

# Leave special characters out to avoid quoting and other issues.
# Special characters have no additional security compared to increasing length.
special = false
override_special = "!#$%^&*()<>-_"

keepers = {
db_name = var.database_name
}
}

resource "aws_ssm_parameter" "database_user" {
count = local.ssm_enabled ? 1 : 0

name = local.ssm_key_user
value = local.database_user
description = local.ssm_key_user_desc
type = "String"
overwrite = true
}

resource "aws_ssm_parameter" "database_password" {
count = local.ssm_enabled ? 1 : 0

name = local.ssm_key_password
value = local.database_password
description = local.ssm_key_password_desc
type = "SecureString"
key_id = var.kms_key_arn
overwrite = true
}

resource "aws_db_instance" "default" {
count = module.this.enabled ? 1 : 0
count = local.enabled ? 1 : 0

identifier = module.this.id
name = var.database_name
username = var.database_user
password = var.database_password
username = local.database_user
password = local.database_password
port = var.database_port
engine = var.engine
engine_version = var.engine_version
Expand Down Expand Up @@ -91,7 +154,7 @@ resource "aws_db_instance" "default" {
}

resource "aws_db_parameter_group" "default" {
count = length(var.parameter_group_name) == 0 && module.this.enabled ? 1 : 0
count = length(var.parameter_group_name) == 0 && local.enabled ? 1 : 0

name_prefix = "${module.this.id}${module.this.delimiter}"
family = var.db_parameter_group
Expand All @@ -112,7 +175,7 @@ resource "aws_db_parameter_group" "default" {
}

resource "aws_db_option_group" "default" {
count = length(var.option_group_name) == 0 && module.this.enabled ? 1 : 0
count = length(var.option_group_name) == 0 && local.enabled ? 1 : 0

name_prefix = "${module.this.id}${module.this.delimiter}"
engine_name = var.engine
Expand Down Expand Up @@ -144,15 +207,15 @@ resource "aws_db_option_group" "default" {
}

resource "aws_db_subnet_group" "default" {
count = module.this.enabled && local.subnet_ids_provided && ! local.db_subnet_group_name_provided ? 1 : 0
count = local.enabled && local.subnet_ids_provided && ! local.db_subnet_group_name_provided ? 1 : 0

name = module.this.id
subnet_ids = var.subnet_ids
tags = module.this.tags
}

resource "aws_security_group" "default" {
count = module.this.enabled ? 1 : 0
count = local.enabled ? 1 : 0

name = module.this.id
description = "Allow inbound traffic from the security groups"
Expand All @@ -161,7 +224,7 @@ resource "aws_security_group" "default" {
}

resource "aws_security_group_rule" "ingress_security_groups" {
count = module.this.enabled ? length(var.security_group_ids) : 0
count = local.enabled ? length(var.security_group_ids) : 0

description = "Allow inbound traffic from existing Security Groups"
type = "ingress"
Expand All @@ -173,7 +236,7 @@ resource "aws_security_group_rule" "ingress_security_groups" {
}

resource "aws_security_group_rule" "ingress_cidr_blocks" {
count = module.this.enabled && length(var.allowed_cidr_blocks) > 0 ? 1 : 0
count = local.enabled && length(var.allowed_cidr_blocks) > 0 ? 1 : 0

description = "Allow inbound traffic from CIDR blocks"
type = "ingress"
Expand All @@ -185,7 +248,7 @@ resource "aws_security_group_rule" "ingress_cidr_blocks" {
}

resource "aws_security_group_rule" "egress" {
count = module.this.enabled ? 1 : 0
count = local.enabled ? 1 : 0
description = "Allow all egress traffic"
type = "egress"
from_port = 0
Expand All @@ -199,7 +262,7 @@ module "dns_host_name" {
source = "cloudposse/route53-cluster-hostname/aws"
version = "0.12.0"

enabled = length(var.dns_zone_id) > 0 && module.this.enabled
enabled = length(var.dns_zone_id) > 0 && local.enabled
dns_name = var.host_name
zone_id = var.dns_zone_id
records = coalescelist(aws_db_instance.default.*.address, [""])
Expand Down
15 changes: 15 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,18 @@ output "resource_id" {
value = join("", aws_db_instance.default.*.resource_id)
description = "The RDS Resource ID of this instance."
}

output "instance_user" {
value = local.database_user
description = "RDS Username for the master DB user"
}

output "instance_password_ssm_key" {
value = local.ssm_enabled ? local.ssm_key_password : null
description = "SSM key of RDS password for the master DB user"
}

output "instance_ssm_key_prefix" {
value = local.ssm_enabled ? local.ssm_key_prefix : null
description = "SSM key prefix of all parameters stored for this instance"
}
44 changes: 42 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,44 @@ variable "database_name" {
description = "The name of the database to create when the DB instance is created"
}

# Don't use `admin`
# Read more: <https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html>
# ("MasterUsername admin cannot be used as it is a reserved word used by the engine")
variable "database_user" {
type = string
default = ""
description = "(Required unless a `snapshot_identifier` or `replicate_source_db` is provided) Username for the master DB user"
default = ""

validation {
condition = (
length(var.database_user) == 0 ||
(var.database_user != "admin" &&
length(var.database_user) >= 1 &&
length(var.database_user) <= 16)
)
error_message = "Per the RDS API, admin cannot be used as it is a reserved word used by the engine. Master username must be between 1 and 16 characters. If null is provided then a random string will be used."
}
}

# Must be longer than 8 chars
# Read more: <https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html>
# ("The parameter MasterUserPassword is not a valid password because it is shorter than 8 characters")
variable "database_password" {
type = string
default = ""
description = "(Required unless a snapshot_identifier or replicate_source_db is provided) Password for the master DB user"
default = ""

# "sensitive" required Terraform 0.14 or later
# sensitive = true

validation {
condition = (
length(var.database_password) == 0 ||
(length(var.database_password) >= 8 &&
length(var.database_password) <= 128)
)
error_message = "Per the RDS API, master password must be between 8 and 128 characters. If null is provided then a random password will be used."
}
}

variable "database_port" {
Expand Down Expand Up @@ -321,3 +349,15 @@ variable "iam_database_authentication_enabled" {
description = "Specifies whether or mappings of AWS Identity and Access Management (IAM) accounts to database accounts is enabled"
default = false
}

variable "ssm_enabled" {
type = bool
default = false
description = "If `true` create SSM keys for the database user and password."
}

variable "ssm_path_prefix" {
type = string
default = "rds"
description = "SSM path prefix (without leading or trailing slash)"
}
4 changes: 4 additions & 0 deletions versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,9 @@ terraform {
source = "hashicorp/null"
version = ">= 2.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.0"
}
}
}

0 comments on commit 1ea1d29

Please sign in to comment.