diff --git a/examples/PostgreSQL/main.tf b/examples/PostgreSQL/main.tf index 7c6e0ef..1989d64 100644 --- a/examples/PostgreSQL/main.tf +++ b/examples/PostgreSQL/main.tf @@ -1,8 +1,15 @@ +locals { + name = "pgsql-new" + environment = "test" + region = "us-east-1" + label_order = ["name", "environment"] +} + ####---------------------------------------------------------------------------------- ## Provider block added, Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. ####---------------------------------------------------------------------------------- provider "aws" { - region = "ap-south-1" + region = local.region } ####---------------------------------------------------------------------------------- @@ -12,9 +19,9 @@ module "vpc" { source = "clouddrove/vpc/aws" version = "2.0.0" - name = "vpc" - environment = "test" - label_order = ["environment", "name"] + name = "${local.name}-vpc" + environment = local.environment + label_order = local.label_order cidr_block = "10.0.0.0/16" } @@ -26,13 +33,13 @@ module "private_subnets" { source = "clouddrove/subnet/aws" version = "2.0.1" - name = "subnets" - environment = "test" - label_order = ["name", "environment"] + name = "${local.name}-subnets" + environment = local.environment + label_order = local.label_order nat_gateway_enabled = true - availability_zones = ["ap-south-1a", "ap-south-1b"] + availability_zones = ["${local.region}a", "${local.region}b"] vpc_id = module.vpc.vpc_id type = "public-private" igw_id = module.vpc.igw_id @@ -46,17 +53,17 @@ module "private_subnets" { module "postgresql" { source = "../../" - name = "postgresql" - environment = "test" - label_order = ["environment", "name"] + name = local.name + environment = local.environment + label_order = local.label_order engine = "postgres" - engine_version = "14.6" + engine_version = "17.6" instance_class = "db.t3.medium" allocated_storage = 50 engine_name = "postgres" storage_encrypted = true - family = "postgres14" + family = "postgres17" # DB Details db_name = "test" username = "dbname" @@ -75,19 +82,22 @@ module "postgresql" { allowed_ports = [5432] # disable backups to create DB faster - backup_retention_period = 0 + backup_retention_period = 7 enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"] + # disable creation of Read Replica + enabled_read_replica = false + # DB subnet group subnet_ids = module.private_subnets.public_subnet_id publicly_accessible = true # DB option group - major_engine_version = "14" + major_engine_version = "17" # Database Deletion Protection - deletion_protection = true + deletion_protection = false ###ssm parameter ssm_parameter_endpoint_enabled = true diff --git a/examples/complete-mysql/main.tf b/examples/complete-mysql/main.tf index 0a3eb49..e07ae60 100644 --- a/examples/complete-mysql/main.tf +++ b/examples/complete-mysql/main.tf @@ -1,8 +1,15 @@ +locals { + name = "mysql" + environment = "test" + region = "us-east-1" + label_order = ["name", "environment"] +} + ####---------------------------------------------------------------------------------- ## Provider block added, Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. ####---------------------------------------------------------------------------------- provider "aws" { - region = "ap-south-1" + region = local.region } ####---------------------------------------------------------------------------------- @@ -12,9 +19,9 @@ module "vpc" { source = "clouddrove/vpc/aws" version = "2.0.0" - name = "vpc" - environment = "test" - label_order = ["environment", "name"] + name = "${local.name}-vpc" + environment = local.environment + label_order = local.label_order cidr_block = "10.0.0.0/16" } @@ -25,11 +32,11 @@ module "subnets" { source = "clouddrove/subnet/aws" version = "2.0.1" - name = "subnets" - environment = "test" - label_order = ["environment", "name"] + name = "${local.name}-subnets" + environment = local.environment + label_order = local.label_order - availability_zones = ["ap-south-1a", "ap-south-1b"] + availability_zones = ["${local.region}a", "${local.region}b"] vpc_id = module.vpc.vpc_id type = "public" igw_id = module.vpc.igw_id @@ -43,13 +50,13 @@ module "subnets" { module "mysql" { source = "../../" - name = "mysql" - environment = "test" - label_order = ["environment", "name"] + name = local.name + environment = local.environment + label_order = local.label_order engine = "mysql" - engine_version = "8.0.28" - instance_class = "db.t2.small" + engine_version = "8.0.43" + instance_class = "db.t3.small" allocated_storage = 5 ####---------------------------------------------------------------------------------- @@ -74,6 +81,9 @@ module "mysql" { enabled_cloudwatch_logs_exports = ["audit", "general"] + # disable creation of Read Replica + enabled_read_replica = true + # DB subnet group subnet_ids = module.subnets.public_subnet_id publicly_accessible = true @@ -85,7 +95,7 @@ module "mysql" { major_engine_version = "8.0" # Database Deletion Protection - deletion_protection = true + deletion_protection = false parameters = [ { diff --git a/examples/replica-mysql/main.tf b/examples/replica-mysql/main.tf index 2e89b7c..dfae804 100644 --- a/examples/replica-mysql/main.tf +++ b/examples/replica-mysql/main.tf @@ -45,7 +45,6 @@ module "mysql" { snapshot_identifier = "" kms_key_id = "" enabled_read_replica = true - enabled_replica = true # DB Details db_name = "replica" diff --git a/main.tf b/main.tf index b0138e2..f5124e0 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,21 @@ +####---------------------------------------------------------------------------------- +## Locals +####---------------------------------------------------------------------------------- +locals { + identifier_prefix = var.use_identifier_prefix ? "${var.identifier}-" : null + db_subnet_group_name = var.enabled_db_subnet_group ? join("", aws_db_subnet_group.this[*].id) : var.db_subnet_group_name + db_parameter_group_name = var.enabled_parameter_group ? join("", aws_db_parameter_group.this[*].id) : var.parameter_group_name + db_option_group_name = var.enabled_option_group ? join("", aws_db_option_group.this[*].id) : var.option_group_name + + # Replicas will use source metadata + username = var.replicate_source_db != null ? null : var.username + password = var.password == "" ? join("", random_id.password[*].b64_url) : var.password + engine = var.replicate_source_db != null ? null : var.engine + engine_version = var.replicate_source_db != null ? null : var.engine_version + // name_prefix = var.use_name_prefix ? "${var.name}-" : null + description = coalesce(var.option_group_description, format("%s option group", var.name)) +} + ####---------------------------------------------------------------------------------- ## Provider block added, Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. ####---------------------------------------------------------------------------------- @@ -6,6 +24,7 @@ module "labels" { version = "1.3.0" name = var.name + repository = var.repository environment = var.environment managedby = var.managedby label_order = var.label_order @@ -15,41 +34,17 @@ module "labels" { ## The resource random_id generates random numbers that are intended to be used as unique identifiers for other resources. ####---------------------------------------------------------------------------------- resource "random_id" "password" { - count = var.enabled ? 1 : 0 + count = var.enabled && var.enabled_custom_password == false ? 1 : 0 byte_length = 20 } -locals { - - identifier_prefix = var.use_identifier_prefix ? "${var.identifier}-" : null - db_subnet_group_name = var.enabled_db_subnet_group ? join("", aws_db_subnet_group.this[*].id) : var.db_subnet_group_name - - # Replicas will use source metadata - username = var.replicate_source_db != null ? null : var.username - password = var.password == "" ? join("", random_id.password[*].b64_url) : var.password - engine = var.replicate_source_db != null ? null : var.engine - engine_version = var.replicate_source_db != null ? null : var.engine_version - // name_prefix = var.use_name_prefix ? "${var.name}-" : null - description = coalesce(var.option_group_description, format("%s option group", var.name)) -} - -resource "random_id" "snapshot_identifier" { - count = var.enabled && !var.skip_final_snapshot ? 1 : 0 - - keepers = { - id = var.identifier - } - - byte_length = 4 -} - ####---------------------------------------------------------------------------------- ### a collection of subnets (typically private) that you create for a VPC and that you then designate for your DB instances. ####---------------------------------------------------------------------------------- resource "aws_db_subnet_group" "this" { count = var.enabled && var.enabled_db_subnet_group ? 1 : 0 name = module.labels.id - description = local.description + description = format("Subnet Group for %s", module.labels.id) subnet_ids = var.subnet_ids tags = merge( module.labels.tags, @@ -61,10 +56,10 @@ resource "aws_db_subnet_group" "this" { ### Provides an RDS DB parameter group resource. ####---------------------------------------------------------------------------------- resource "aws_db_parameter_group" "this" { - count = var.enabled ? 1 : 0 + count = var.enabled && var.enabled_parameter_group ? 1 : 0 name = module.labels.id - description = local.description + description = format("Parameter Group for %s", module.labels.id) family = var.family dynamic "parameter" { for_each = var.parameters @@ -90,10 +85,10 @@ resource "aws_db_parameter_group" "this" { ### Provides an RDS DB option group resource. ####---------------------------------------------------------------------------------- resource "aws_db_option_group" "this" { - count = var.enabled ? 1 : 0 + count = var.enabled && var.enabled_option_group ? 1 : 0 name = module.labels.id - option_group_description = local.description + option_group_description = format("Option group for %s", module.labels.id) engine_name = var.engine_name major_engine_version = var.major_engine_version dynamic "option" { @@ -148,33 +143,15 @@ resource "aws_cloudwatch_log_group" "this" { ) } -##----------------------------------------------------------------------------------- -### Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. -##----------------------------------------------------------------------------------- - -data "aws_iam_policy_document" "enhanced_monitoring" { - statement { - actions = [ - "sts:AssumeRole", - ] - - principals { - type = "Service" - identifiers = ["monitoring.rds.amazonaws.com"] - } - } -} - ####---------------------------------------------------------------------------------- -### IAM - Manage Roles ### AWS Identity and Access Management (IAM) roles are entities you create and assign specific permissions to that allow trusted identities such as workforce identities and applications to perform actions in AWS ####---------------------------------------------------------------------------------- resource "aws_iam_role" "enhanced_monitoring" { - count = var.enabled_monitoring_role ? 1 : 0 + count = var.enabled && var.enabled_monitoring_role ? 1 : 0 name = module.labels.id - assume_role_policy = data.aws_iam_policy_document.enhanced_monitoring.json - description = var.monitoring_role_description + assume_role_policy = data.aws_iam_policy_document.enhanced_monitoring[count.index].json + description = format("RDS Monitoring role for %s", module.labels.id) permissions_boundary = var.monitoring_role_permissions_boundary tags = merge( @@ -187,21 +164,39 @@ resource "aws_iam_role" "enhanced_monitoring" { } resource "aws_iam_role_policy_attachment" "enhanced_monitoring" { - count = var.enabled_monitoring_role ? 1 : 0 + count = var.enabled && var.enabled_monitoring_role ? 1 : 0 role = aws_iam_role.enhanced_monitoring[0].name policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole" } +##----------------------------------------------------------------------------------- +### Generates an IAM policy document in JSON format for use with resources that expect policy documents such as aws_iam_policy. +##----------------------------------------------------------------------------------- + +data "aws_iam_policy_document" "enhanced_monitoring" { + count = var.enabled && var.enabled_monitoring_role ? 1 : 0 + statement { + actions = [ + "sts:AssumeRole", + ] + + principals { + type = "Service" + identifiers = ["monitoring.rds.amazonaws.com"] + } + } +} + ##---------------------------------------------------------------------------------- ## Below resources will create SECURITY-GROUP and its components. ##---------------------------------------------------------------------------------- resource "aws_security_group" "default" { - count = var.enable_security_group && length(var.sg_ids) < 1 ? 1 : 0 + count = var.enabled && var.enable_security_group && length(var.sg_ids) < 1 ? 1 : 0 name = format("%s-sg", module.labels.id) vpc_id = var.vpc_id - description = var.sg_description + description = format("Security Group for %s", module.labels.id) tags = module.labels.tags lifecycle { create_before_destroy = true @@ -213,7 +208,7 @@ resource "aws_security_group" "default" { ##---------------------------------------------------------------------------------- #tfsec:ignore:aws-ec2-no-public-egress-sgr resource "aws_security_group_rule" "egress" { - count = (var.enable_security_group == true && length(var.sg_ids) < 1 && var.is_external == false && var.egress_rule == true) ? 1 : 0 + count = var.enabled && (var.enable_security_group == true && length(var.sg_ids) < 1 && var.is_external == false && var.egress_rule == true) ? 1 : 0 description = var.sg_egress_description type = "egress" @@ -225,7 +220,7 @@ resource "aws_security_group_rule" "egress" { } #tfsec:ignore:aws-ec2-no-public-egress-sgr resource "aws_security_group_rule" "egress_ipv6" { - count = (var.enable_security_group == true && length(var.sg_ids) < 1 && var.is_external == false) && var.egress_rule == true ? 1 : 0 + count = var.enabled && (var.enable_security_group == true && length(var.sg_ids) < 1 && var.is_external == false) && var.egress_rule == true ? 1 : 0 description = var.sg_egress_ipv6_description type = "egress" @@ -237,7 +232,7 @@ resource "aws_security_group_rule" "egress_ipv6" { } resource "aws_security_group_rule" "ingress" { - count = length(var.allowed_ip) > 0 == true && length(var.sg_ids) < 1 ? length(compact(var.allowed_ports)) : 0 + count = var.enabled && length(var.allowed_ip) > 0 == true && length(var.sg_ids) < 1 ? length(compact(var.allowed_ports)) : 0 description = var.sg_ingress_description type = "ingress" @@ -252,9 +247,9 @@ resource "aws_security_group_rule" "ingress" { ## Below resources will create KMS-KEY and its components. ##---------------------------------------------------------------------------------- resource "aws_kms_key" "default" { - count = var.kms_key_enabled && var.kms_key_id == "" ? 1 : 0 + count = var.enabled && var.kms_key_enabled && var.kms_key_id == "" ? 1 : 0 - description = var.kms_description + description = format("KMS Key for %s", module.labels.id) key_usage = var.key_usage deletion_window_in_days = var.deletion_window_in_days is_enabled = var.is_enabled @@ -266,7 +261,7 @@ resource "aws_kms_key" "default" { } resource "aws_kms_alias" "default" { - count = var.kms_key_enabled && var.kms_key_id == "" ? 1 : 0 + count = var.enabled && var.kms_key_enabled && var.kms_key_id == "" ? 1 : 0 name = coalesce(var.alias, format("alias/%v", module.labels.id)) target_key_id = var.kms_key_id == "" ? join("", aws_kms_key.default[*].id) : var.kms_key_id @@ -302,7 +297,7 @@ data "aws_iam_policy_document" "default" { ####---------------------------------------------------------------------------------- #tfsec:ignore:aws-rds-enable-performance-insights resource "aws_db_instance" "this" { - count = var.enabled && var.enabled_read_replica ? 1 : 0 + count = var.enabled ? 1 : 0 identifier = module.labels.id identifier_prefix = local.identifier_prefix @@ -391,7 +386,7 @@ resource "aws_db_instance" "this" { for_each = var.s3_import != null ? [var.s3_import] : [] content { - source_engine = "mysql" + source_engine = local.engine source_engine_version = s3_import.value.source_engine_version bucket_name = s3_import.value.bucket_name bucket_prefix = lookup(s3_import.value, "bucket_prefix", null) @@ -419,14 +414,14 @@ resource "aws_db_instance" "this" { ####---------------------------------------------------------------------------------- #tfsec:ignore:aws-rds-enable-performance-insights resource "aws_db_instance" "read" { - count = var.enabled && var.enabled_read_replica && var.enabled_replica ? 1 : 0 + count = var.enabled && var.enabled_read_replica ? 1 : 0 identifier = format("%s-replica", module.labels.id) identifier_prefix = local.identifier_prefix engine = null engine_version = null - instance_class = var.replica_instance_class + instance_class = var.instance_class allocated_storage = var.allocated_storage storage_type = var.storage_type storage_encrypted = var.storage_encrypted @@ -509,7 +504,7 @@ resource "aws_db_instance" "read" { for_each = var.s3_import != null ? [var.s3_import] : [] content { - source_engine = "mysql" + source_engine = local.engine source_engine_version = s3_import.value.source_engine_version bucket_name = s3_import.value.bucket_name bucket_prefix = lookup(s3_import.value, "bucket_prefix", null) diff --git a/variables.tf b/variables.tf index 570f217..cce1808 100644 --- a/variables.tf +++ b/variables.tf @@ -6,6 +6,18 @@ variable "name" { description = "Name (e.g. `app` or `cluster`)." } +variable "repository" { + type = string + default = "https://github.com/clouddrove/terraform-aws-ec2" + description = "Terraform current module repo" + + validation { + # regex(...) fails if it cannot find a match + condition = can(regex("^https://", var.repository)) + error_message = "The module-repo value must be a valid Git repo link." + } +} + variable "environment" { type = string default = "" @@ -42,6 +54,13 @@ variable "identifier" { description = "The name of the RDS instance" } +variable "enabled_custom_password" { + description = "Whether to use a custom password (true) or generate a random one (false)." + type = bool + default = false +} + + variable "custom_iam_instance_profile" { type = string default = null @@ -377,6 +396,12 @@ variable "cloudwatch_log_group_retention_in_days" { description = "The number of days to retain CloudWatch logs for the DB instance" } +variable "enabled_option_group" { + description = "Determines whether a cluster option group should be created or use existing" + type = bool + default = true +} + variable "option_group_description" { type = string default = null @@ -401,6 +426,13 @@ variable "options" { description = "A list of Options to apply" } +variable "option_group_name" { + description = "Existing DB option group name to use (if not creating a new one)." + type = string + default = null +} + + variable "timeouts" { type = map(string) default = {} @@ -419,6 +451,18 @@ variable "parameters" { default = [] } +variable "parameter_group_name" { + description = "Existing DB parameter group name to use (if not creating a new one)." + type = string + default = null +} + +variable "enabled_parameter_group" { + description = "Determines whether a cluster parameter should be created or use existing" + type = bool + default = true +} + variable "subnet_ids" { type = list(string) default = [] @@ -443,12 +487,6 @@ variable "enabled_read_replica" { description = "A list of enabled read replica" } -variable "enabled_replica" { - type = bool - default = false - description = "A list of enabled replica" -} - variable "db_subnet_group_tags" { type = map(any) default = {}