Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional user and password #119

Closed
wants to merge 12 commits into from
4 changes: 2 additions & 2 deletions examples/complete/fixtures.us-east-2.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ deletion_protection = false

database_name = "test_db"

database_user = "admin"
database_user = "db_user"

database_password = "admin_password"
database_password = "db_password"

database_port = 3306

Expand Down
4 changes: 2 additions & 2 deletions examples/mssql/fixtures.us-east-2.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ deletion_protection = false

database_name = null

database_user = "admin"
database_user = "db_user"

database_password = "admin_password"
database_password = "db_password"

database_port = 1433

Expand Down
84 changes: 73 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,75 @@ 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_user = format(var.ssm_key_format, var.database_name, var.ssm_key_user)
ssm_key_password = format(var.ssm_key_format, var.database_name, var.ssm_key_password)
ssm_key_user_desc = "RDS Username for the master DB user"
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 = "!#$%^&*()<>-_"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU, you don't need override_specialif you includespecial = false`. No harm no foul, but just mentioning.


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_alias_name_ssm
overwrite = true
}

resource "aws_db_instance" "default" {
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
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 +153,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 +174,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 +206,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 +223,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 +235,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 +247,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 +261,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
10 changes: 10 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@ 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"
}
61 changes: 59 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."
nitrocode marked this conversation as resolved.
Show resolved Hide resolved
}
}

# 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,32 @@ 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_key_format" {
type = string
default = "/rds/%v/%v"
description = "SSM path prefix. The first value will use the `var.database_name` and then the appropriate ssm key like `var.ssm_key_user`"
}

variable "ssm_key_user" {
type = string
default = "admin/db_user"
description = "The SSM key to save the user. See `var.ssm_path_format`."
}

variable "ssm_key_password" {
type = string
default = "admin/db_password"
description = "The SSM key to save the password. See `var.ssm_path_format`."
}

variable "kms_alias_name_ssm" {
default = "alias/aws/ssm"
description = "KMS alias name for SSM"
}
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"
}
}
}