From 9cae8579380872b8261dd1a9eeb772c1443bfc18 Mon Sep 17 00:00:00 2001 From: Arabinda Pani <22154314+catcharbind@users.noreply.github.com> Date: Wed, 20 Jul 2022 09:37:53 -0700 Subject: [PATCH 1/3] provider change log --- providers.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/providers.tf b/providers.tf index af25230..364d6b5 100644 --- a/providers.tf +++ b/providers.tf @@ -1,3 +1,6 @@ +# https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md +# https://github.com/hashicorp/terraform/blob/v1.0.10/CHANGELOG.md + terraform { required_version = ">= 1.0.0" backend "remote" {} From fa8ed16d42fa7e6d56bd579fa2816345b99b3921 Mon Sep 17 00:00:00 2001 From: Arabinda Pani <22154314+catcharbind@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:08:33 -0800 Subject: [PATCH 2/3] Aurora Serverless v2 and Aurora I/O Optimized --- .pre-commit-config.yaml | 2 +- .tflint.hcl | 2 +- README.md | 47 ++++++++------ deploy/main.tf | 131 +++++++++++++++++++++++++++------------- deploy/outputs.tf | 16 +++++ deploy/providers.tf | 7 ++- deploy/variables.tf | 38 +++++++++++- locals.tf | 5 ++ main.tf | 102 +++++++++++++++++++++---------- outputs.tf | 69 +++++++++++++++++---- providers.tf | 6 +- variables.tf | 39 ++++++++---- 12 files changed, 340 insertions(+), 124 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cbafa4b..7addda9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,6 +6,6 @@ repos: repo: https://github.com/aws-ia/pre-commit-configs # To update run: # pre-commit autoupdate --freeze - rev: 80ed3f0a164f282afaac0b6aec70e20f7e541932 # frozen: v1.5.0 + rev: b3e647e360f04623c6c582c12245fc92e20cc2e8 # frozen: v1.6.3 hooks: - id: aws-ia-meta-hook diff --git a/.tflint.hcl b/.tflint.hcl index 0e31ba5..99d129a 100644 --- a/.tflint.hcl +++ b/.tflint.hcl @@ -3,7 +3,7 @@ plugin "aws" { enabled = true - version = "0.14.0" + version = "0.28.0" source = "github.com/terraform-linters/tflint-ruleset-aws" } diff --git a/README.md b/README.md index 21eb44b..0087ac9 100644 --- a/README.md +++ b/README.md @@ -63,17 +63,17 @@ David Wright (dwright@hashicorp.com), Tony Vattahil (tonynv@amazon.com), Arabind | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0.0 | -| [aws](#requirement\_aws) | >= 4.9.0 | +| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [aws](#requirement\_aws) | >= 5.30 | | [random](#requirement\_random) | >= 2.2 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.9.0 | -| [aws.primary](#provider\_aws.primary) | >= 4.9.0 | -| [aws.secondary](#provider\_aws.secondary) | >= 4.9.0 | +| [aws](#provider\_aws) | >= 5.30 | +| [aws.primary](#provider\_aws.primary) | >= 5.30 | +| [aws.secondary](#provider\_aws.secondary) | >= 5.30 | | [random](#provider\_random) | >= 2.2 | ## Modules @@ -137,22 +137,26 @@ No modules. | [enable\_postgresql\_log](#input\_enable\_postgresql\_log) | Enable PostgreSQL log export to Amazon Cloudwatch. | `bool` | `false` | no | | [enable\_slowquery\_log](#input\_enable\_slowquery\_log) | Enable MySQL slowquery log export to Amazon Cloudwatch. | `bool` | `false` | no | | [engine](#input\_engine) | Aurora database engine type: aurora (for MySQL 5.6-compatible Aurora), aurora-mysql (for MySQL 5.7-compatible Aurora), aurora-postgresql | `string` | `"aurora-postgresql"` | no | -| [engine\_version\_mysql](#input\_engine\_version\_mysql) | Aurora database engine version. | `string` | `"5.7.mysql_aurora.2.10.2"` | no | -| [engine\_version\_pg](#input\_engine\_version\_pg) | Aurora database engine version. | `string` | `"13.6"` | no | +| [engine\_version\_mysql](#input\_engine\_version\_mysql) | Aurora database engine version. | `string` | `"8.0.mysql_aurora.3.05.1"` | no | +| [engine\_version\_pg](#input\_engine\_version\_pg) | Aurora database engine version. | `string` | `"15.4"` | no | | [final\_snapshot\_identifier\_prefix](#input\_final\_snapshot\_identifier\_prefix) | The prefix name to use when creating a final snapshot on cluster destroy, appends a random 8 digits to name to ensure it's unique too. | `string` | `"final"` | no | | [identifier](#input\_identifier) | Cluster identifier | `string` | `"aurora"` | no | -| [instance\_class](#input\_instance\_class) | Instance type to use at replica instance | `string` | `"db.r5.large"` | no | +| [instance\_class](#input\_instance\_class) | Aurora DB Instance type. Specify db.serverless to create Aurora Serverless v2 instances. | `string` | `"db.r7g.large"` | no | +| [manage\_master\_user\_password](#input\_manage\_master\_user\_password) | Manage master user password using AWS Secrets Manager | `bool` | `false` | no | | [monitoring\_interval](#input\_monitoring\_interval) | Enhanced Monitoring interval in seconds | `number` | `1` | no | | [name](#input\_name) | Prefix for resource names | `string` | `"aurora"` | no | | [port](#input\_port) | The port on which to accept connections | `string` | `""` | no | | [preferred\_backup\_window](#input\_preferred\_backup\_window) | When to perform DB backups | `string` | `"02:00-03:00"` | no | | [primary\_instance\_count](#input\_primary\_instance\_count) | instance count for primary Aurora cluster | `number` | `2` | no | | [secondary\_instance\_count](#input\_secondary\_instance\_count) | instance count for secondary Aurora cluster | `number` | `1` | no | +| [serverless\_v2\_max\_acu](#input\_serverless\_v2\_max\_acu) | Aurora Serverless v2 Maximum ACU | `number` | `16` | no | +| [serverless\_v2\_min\_acu](#input\_serverless\_v2\_min\_acu) | Aurora Serverless v2 Minimum ACU | `number` | `0.5` | no | | [setup\_as\_secondary](#input\_setup\_as\_secondary) | Setup aws\_rds\_cluster.primary Terraform resource as Secondary Aurora cluster after an unplanned Aurora Global DB failover | `bool` | `false` | no | | [setup\_globaldb](#input\_setup\_globaldb) | Setup Aurora Global Database with 1 Primary and 1 X-region Secondary cluster | `bool` | `false` | no | | [skip\_final\_snapshot](#input\_skip\_final\_snapshot) | skip creating a final snapshot before deleting the DB | `bool` | `true` | no | | [snapshot\_identifier](#input\_snapshot\_identifier) | id of snapshot to restore. If you do not want to restore a db, leave the default empty string. | `string` | `""` | no | | [storage\_encrypted](#input\_storage\_encrypted) | Specifies whether the underlying Aurora storage layer should be encrypted | `bool` | `false` | no | +| [storage\_type](#input\_storage\_type) | Specifies Aurora storage type: Aurora Standard vs. Aurora I/O-Optimized | `string` | `""` | no | | [tags](#input\_tags) | A map of tags to add to all resources. | `map(string)` |
{
"Name": "aurora-db"
}
| no | | [username](#input\_username) | Master DB username | `string` | `"root"` | no | @@ -160,16 +164,25 @@ No modules. | Name | Description | |------|-------------| -| [aurora\_cluster\_arn](#output\_aurora\_cluster\_arn) | The ARN of the Primary Aurora cluster | | [aurora\_cluster\_database\_name](#output\_aurora\_cluster\_database\_name) | Name for an automatically created database on Aurora cluster creation | -| [aurora\_cluster\_endpoint](#output\_aurora\_cluster\_endpoint) | Primary Aurora cluster endpoint | -| [aurora\_cluster\_hosted\_zone\_id](#output\_aurora\_cluster\_hosted\_zone\_id) | Route53 hosted zone id of the Primary Aurora cluster | -| [aurora\_cluster\_id](#output\_aurora\_cluster\_id) | The ID of the Primary Aurora cluster | -| [aurora\_cluster\_instance\_endpoints](#output\_aurora\_cluster\_instance\_endpoints) | A list of all Primary Aurora cluster instance endpoints | -| [aurora\_cluster\_instance\_ids](#output\_aurora\_cluster\_instance\_ids) | A list of all Primary Aurora cluster instance ids | | [aurora\_cluster\_master\_password](#output\_aurora\_cluster\_master\_password) | Aurora master User password | | [aurora\_cluster\_master\_username](#output\_aurora\_cluster\_master\_username) | Aurora master username | -| [aurora\_cluster\_port](#output\_aurora\_cluster\_port) | Primary Aurora cluster endpoint port | -| [aurora\_cluster\_reader\_endpoint](#output\_aurora\_cluster\_reader\_endpoint) | Primary Aurora cluster reader endpoint | -| [aurora\_cluster\_resource\_id](#output\_aurora\_cluster\_resource\_id) | The Cluster Resource ID of the Primary Aurora cluster | +| [primary\_aurora\_cluster\_arn](#output\_primary\_aurora\_cluster\_arn) | The ARN of the Primary Aurora cluster | +| [primary\_aurora\_cluster\_endpoint](#output\_primary\_aurora\_cluster\_endpoint) | Primary Aurora cluster endpoint | +| [primary\_aurora\_cluster\_hosted\_zone\_id](#output\_primary\_aurora\_cluster\_hosted\_zone\_id) | Route53 hosted zone id of the Primary Aurora cluster | +| [primary\_aurora\_cluster\_id](#output\_primary\_aurora\_cluster\_id) | The ID of the Primary Aurora cluster | +| [primary\_aurora\_cluster\_instance\_endpoints](#output\_primary\_aurora\_cluster\_instance\_endpoints) | A list of all Primary Aurora cluster instance endpoints | +| [primary\_aurora\_cluster\_instance\_ids](#output\_primary\_aurora\_cluster\_instance\_ids) | A list of all Primary Aurora cluster instance ids | +| [primary\_aurora\_cluster\_port](#output\_primary\_aurora\_cluster\_port) | Primary Aurora cluster endpoint port | +| [primary\_aurora\_cluster\_reader\_endpoint](#output\_primary\_aurora\_cluster\_reader\_endpoint) | Primary Aurora cluster reader endpoint | +| [primary\_aurora\_cluster\_resource\_id](#output\_primary\_aurora\_cluster\_resource\_id) | The Cluster Resource ID of the Primary Aurora cluster | +| [secondary\_aurora\_cluster\_arn](#output\_secondary\_aurora\_cluster\_arn) | The ARN of the Secondary Aurora cluster | +| [secondary\_aurora\_cluster\_endpoint](#output\_secondary\_aurora\_cluster\_endpoint) | Secondary Aurora cluster endpoint | +| [secondary\_aurora\_cluster\_hosted\_zone\_id](#output\_secondary\_aurora\_cluster\_hosted\_zone\_id) | Route53 hosted zone id of the Secondary Aurora cluster | +| [secondary\_aurora\_cluster\_id](#output\_secondary\_aurora\_cluster\_id) | The ID of the Secondary Aurora cluster | +| [secondary\_aurora\_cluster\_instance\_endpoints](#output\_secondary\_aurora\_cluster\_instance\_endpoints) | A list of all Secondary Aurora cluster instance endpoints | +| [secondary\_aurora\_cluster\_instance\_ids](#output\_secondary\_aurora\_cluster\_instance\_ids) | A list of all Secondary Aurora cluster instance ids | +| [secondary\_aurora\_cluster\_port](#output\_secondary\_aurora\_cluster\_port) | Secondary Aurora cluster endpoint port | +| [secondary\_aurora\_cluster\_reader\_endpoint](#output\_secondary\_aurora\_cluster\_reader\_endpoint) | Secondary Aurora cluster reader endpoint | +| [secondary\_aurora\_cluster\_resource\_id](#output\_secondary\_aurora\_cluster\_resource\_id) | The Cluster Resource ID of the Secondary Aurora cluster | \ No newline at end of file diff --git a/deploy/main.tf b/deploy/main.tf index d5c47f6..6e163fc 100644 --- a/deploy/main.tf +++ b/deploy/main.tf @@ -3,28 +3,49 @@ ###################################### provider "aws" { + alias = "primary" region = var.region } +provider "aws" { + alias = "secondary" + region = var.sec_region +} + resource "random_string" "rand4" { length = 4 special = false upper = false } +######################### +# Collect data +######################### + +data "aws_caller_identity" "current" { + provider = aws.primary +} + ###################################### # Generate Tags ###################################### module "vpc_label" { source = "aws-ia/label/aws" - version = "0.0.2" - region = var.region + version = "0.0.5" + providers = { aws = aws.primary } + + account = var.account == null ? data.aws_caller_identity.current.account_id : var.account namespace = var.namespace env = var.env name = "${var.name}-${random_string.rand4.result}" delimiter = var.delimiter - tags = tomap({ propogate_at_launch = "true", "terraform" = "true" }) + tags = [ + { + "key" : "terraform", + "value" : "true" + } + ] } ###################################### @@ -32,29 +53,49 @@ module "vpc_label" { ###################################### module "aurora_vpc_p" { - source = "aws-ia/vpc/aws" - version = "0.1.0" - name = "aurora-vpc" - region = var.region - cidr = "10.0.0.0/16" - public_subnets = ["10.0.0.0/20", "10.0.32.0/20", "10.0.64.0/20"] - private_subnets_a = ["10.0.16.0/20", "10.0.48.0/20", "10.0.80.0/20"] - enable_dns_hostnames = true - tags = module.vpc_label.tags - create_vpc = true + source = "aws-ia/vpc/aws" + version = "4.4.1" + providers = { aws = aws.primary } + + name = "aurora-vpc" + az_count = 3 + cidr_block = "10.0.0.0/16" + subnets = { + public = { + netmask = 20 + nat_gateway_configuration = "all_azs" + } + private = { + netmask = 20 + connect_to_public_natgw = true + } + } + vpc_enable_dns_hostnames = true + tags = module.vpc_label.tags_aws } module "aurora_vpc_s" { - source = "aws-ia/vpc/aws" - version = "0.1.0" - name = "aurora-vpc" - region = var.sec_region - cidr = "10.0.0.0/16" - public_subnets = ["10.0.0.0/20", "10.0.32.0/20", "10.0.64.0/20"] - private_subnets_a = ["10.0.16.0/20", "10.0.48.0/20", "10.0.80.0/20"] - enable_dns_hostnames = true - tags = module.vpc_label.tags - create_vpc = var.setup_globaldb ? true : false + source = "aws-ia/vpc/aws" + version = "4.4.1" + providers = { aws = aws.secondary } + + count = var.setup_globaldb ? 1 : 0 + + name = "aurora-vpc" + az_count = 3 + cidr_block = "10.0.0.0/16" + subnets = { + public = { + netmask = 20 + nat_gateway_configuration = "all_azs" + } + private = { + netmask = 20 + connect_to_public_natgw = true + } + } + vpc_enable_dns_hostnames = true + tags = module.vpc_label.tags_aws } ###################################### @@ -63,23 +104,29 @@ module "aurora_vpc_s" { #tfsec:ignore:aws-rds-enable-performance-insights-encryption tfsec:ignore:aws-rds-enable-performance-insights module "aurora" { - source = "../" - region = var.region - sec_region = var.sec_region - #vpc_id = module.aurora_vpc.vpc_id - private_subnet_ids_p = [module.aurora_vpc_p.private_subnet_1a_id, module.aurora_vpc_p.private_subnet_2a_id, module.aurora_vpc_p.private_subnet_3a_id] - private_subnet_ids_s = var.setup_globaldb ? [module.aurora_vpc_s.private_subnet_1a_id, module.aurora_vpc_s.private_subnet_2a_id, module.aurora_vpc_s.private_subnet_3a_id] : null - engine = var.engine - engine_version_pg = var.engine_version_pg - engine_version_mysql = var.engine_version_mysql - username = var.username - password = var.password - setup_globaldb = var.setup_globaldb - setup_as_secondary = var.setup_as_secondary - tags = module.vpc_label.tags - monitoring_interval = var.monitoring_interval - storage_encrypted = var.storage_encrypted - primary_instance_count = var.primary_instance_count - secondary_instance_count = var.secondary_instance_count - snapshot_identifier = var.snapshot_identifier + source = "../" + providers = { aws = aws.primary } + + region = var.region + sec_region = var.sec_region + private_subnet_ids_p = [for _, value in module.aurora_vpc_p.private_subnet_attributes_by_az : value.id] + private_subnet_ids_s = var.setup_globaldb ? [for _, value in module.aurora_vpc_s[0].private_subnet_attributes_by_az : value.id] : null + name = var.name + identifier = var.identifier + engine = var.engine + engine_version_pg = var.engine_version_pg + engine_version_mysql = var.engine_version_mysql + instance_class = var.instance_class + username = var.username + password = var.password + manage_master_user_password = var.manage_master_user_password + setup_globaldb = var.setup_globaldb + setup_as_secondary = var.setup_as_secondary + tags = module.vpc_label.tags_aws + monitoring_interval = var.monitoring_interval + storage_encrypted = var.storage_encrypted + storage_type = var.storage_type + primary_instance_count = var.primary_instance_count + secondary_instance_count = var.secondary_instance_count + snapshot_identifier = var.snapshot_identifier } \ No newline at end of file diff --git a/deploy/outputs.tf b/deploy/outputs.tf index e69de29..ba9091b 100644 --- a/deploy/outputs.tf +++ b/deploy/outputs.tf @@ -0,0 +1,16 @@ +output "aurora_vpc_p" { + value = module.aurora_vpc_p +} +output "aurora_vpc_s" { + value = module.aurora_vpc_s +} +output "aurora" { + # value = module.aurora + value = { for k, v in module.aurora : k => v if k != "aurora_cluster_master_password" } +} + +output "aurora_cluster_master_password" { + description = "Aurora master User password" + value = module.aurora.aurora_cluster_master_password + sensitive = true +} \ No newline at end of file diff --git a/deploy/providers.tf b/deploy/providers.tf index af25230..d051937 100644 --- a/deploy/providers.tf +++ b/deploy/providers.tf @@ -1,10 +1,13 @@ +# https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md +# https://github.com/hashicorp/terraform/releases + terraform { - required_version = ">= 1.0.0" + required_version = ">= 1.3.0" backend "remote" {} required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.9.0" + version = ">= 5.30" } random = { source = "hashicorp/random" diff --git a/deploy/variables.tf b/deploy/variables.tf index 19bc8d3..b4860ab 100644 --- a/deploy/variables.tf +++ b/deploy/variables.tf @@ -10,6 +10,12 @@ variable "sec_region" { default = "us-west-2" } +variable "account" { + type = string + description = "account, which could be AWS Account Name or Number" + default = null +} + variable "namespace" { description = "namespace, which could be your organiation name, e.g. amazon" type = string @@ -20,11 +26,19 @@ variable "env" { type = string default = "dev" } + +variable "identifier" { + description = "Cluster identifier" + type = string + default = "aurora" +} + variable "name" { - description = "deployment name" + description = "Prefix for resource names" type = string default = "aurora" } + variable "delimiter" { description = "delimiter, which could be used between name, namespace and env" type = string @@ -44,6 +58,12 @@ variable "password" { description = "If no password is provided, a random password will be generated" } +variable "manage_master_user_password" { + description = "Manage master user password using AWS Secrets Manager" + type = bool + default = false +} + /* variable "tags" { default = {} @@ -61,13 +81,13 @@ variable "engine" { variable "engine_version_pg" { description = "Aurora PostgreSQL database engine version." type = string - default = "13.6" + default = "15.4" } variable "engine_version_mysql" { description = "Aurora MySQL database engine version." type = string - default = "5.7.mysql_aurora.2.10.2" + default = "8.0.mysql_aurora.3.05.1" } variable "setup_globaldb" { @@ -104,6 +124,12 @@ variable "storage_encrypted" { default = false } +variable "storage_type" { + description = "Specifies Aurora storage type: Aurora Standard vs. Aurora I/O-Optimized" + type = string + default = "" +} + variable "primary_instance_count" { description = "instance count for primary Aurora cluster" type = number @@ -114,4 +140,10 @@ variable "secondary_instance_count" { description = "instance count for secondary Aurora cluster" type = number default = 1 +} + +variable "instance_class" { + type = string + description = "Aurora DB Instance type. Specify db.serverless to create Aurora Serverless v2 instances." + default = "db.r7g.large" } \ No newline at end of file diff --git a/locals.tf b/locals.tf index 9fa9528..6837642 100644 --- a/locals.tf +++ b/locals.tf @@ -122,4 +122,9 @@ locals { var.enable_slowquery_log && (var.engine != "aurora-postgresql") ? "slowquery" : "", var.enable_postgresql_log && (var.engine == "aurora-postgresql") ? "postgresql" : "", ]) + + serverlessv2_scaling_configuration = { + max_capacity = var.serverless_v2_max_acu + min_capacity = var.serverless_v2_min_acu + } } \ No newline at end of file diff --git a/main.tf b/main.tf index eac67e4..5e7a7cc 100644 --- a/main.tf +++ b/main.tf @@ -102,8 +102,8 @@ resource "aws_db_subnet_group" "private_s" { resource "aws_kms_key" "kms_p" { provider = aws.primary - count = var.storage_encrypted ? 1 : 0 - description = "KMS key for Aurora Storage Encryption" + count = var.storage_encrypted || (!var.setup_globaldb && var.manage_master_user_password) ? 1 : 0 + description = "KMS key for Aurora Storage Encryption and master user Secrets Manager secret" tags = var.tags # following causes terraform destroy to fail. But this is needed so that Aurora encrypted snapshots can be restored for your production workload. lifecycle { @@ -143,25 +143,36 @@ resource "aws_rds_global_cluster" "globaldb" { count = var.setup_globaldb ? 1 : 0 provider = aws.primary global_cluster_identifier = "${var.identifier}-globaldb" - engine = var.engine - engine_version = var.engine == "aurora-postgresql" ? var.engine_version_pg : var.engine_version_mysql - database_name = (var.snapshot_identifier != "") ? null : var.database_name + engine = (var.snapshot_identifier == "") ? var.engine : null + engine_version = (var.snapshot_identifier == "") ? (var.engine == "aurora-postgresql" ? var.engine_version_pg : var.engine_version_mysql) : null + database_name = (var.snapshot_identifier == "") ? var.database_name : null storage_encrypted = var.storage_encrypted + # Uncomment the following line for restoring cluster from snapshot. Conditionally specifying null for the argument still creating Terraform Cycle error. + # source_db_cluster_identifier = (var.snapshot_identifier == "") ? null : aws_rds_cluster.primary.arn + force_destroy = (var.snapshot_identifier == "") ? null : true + + lifecycle { + ignore_changes = [source_db_cluster_identifier] + } } resource "aws_rds_cluster" "primary" { - provider = aws.primary - global_cluster_identifier = var.setup_globaldb ? aws_rds_global_cluster.globaldb[0].id : null - cluster_identifier = "${var.identifier}-${var.region}" - engine = var.engine - engine_version = var.engine == "aurora-postgresql" ? var.engine_version_pg : var.engine_version_mysql - allow_major_version_upgrade = var.allow_major_version_upgrade - availability_zones = [data.aws_availability_zones.region_p.names[0], data.aws_availability_zones.region_p.names[1], data.aws_availability_zones.region_p.names[2]] - db_subnet_group_name = aws_db_subnet_group.private_p.name - port = var.port == "" ? var.engine == "aurora-postgresql" ? "5432" : "3306" : var.port - database_name = var.setup_as_secondary || (var.snapshot_identifier != "") ? null : var.database_name + provider = aws.primary + # Comment the following line for restoring cluster from snapshot. Conditionally specifying null for the argument still creating Terraform Cycle error. + global_cluster_identifier = var.setup_globaldb && (var.snapshot_identifier == "") ? aws_rds_global_cluster.globaldb[0].id : null + cluster_identifier = "${var.identifier}-${var.region}" + engine = var.engine + engine_version = var.engine == "aurora-postgresql" ? var.engine_version_pg : var.engine_version_mysql + allow_major_version_upgrade = var.allow_major_version_upgrade + availability_zones = [data.aws_availability_zones.region_p.names[0], data.aws_availability_zones.region_p.names[1], data.aws_availability_zones.region_p.names[2]] + db_subnet_group_name = aws_db_subnet_group.private_p.name + port = var.port == "" ? var.engine == "aurora-postgresql" ? "5432" : "3306" : var.port + database_name = var.setup_as_secondary || (var.snapshot_identifier != "") ? null : var.database_name + # Aurora global DB currently doesnt support master password manager with AWS Secrets Manager + manage_master_user_password = !var.setup_globaldb && var.manage_master_user_password ? var.manage_master_user_password : null + master_user_secret_kms_key_id = !var.setup_globaldb && var.manage_master_user_password ? aws_kms_key.kms_p[0].arn : null master_username = var.setup_as_secondary || (var.snapshot_identifier != "") ? null : var.username - master_password = var.setup_as_secondary || (var.snapshot_identifier != "") ? null : (var.password == "" ? random_password.master_password.result : var.password) + master_password = (var.setup_as_secondary || (var.snapshot_identifier != "")) || (!var.setup_globaldb && var.manage_master_user_password) ? null : (var.password == "" ? random_password.master_password.result : var.password) db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.aurora_cluster_parameter_group_p.id db_instance_parameter_group_name = var.allow_major_version_upgrade ? aws_db_parameter_group.aurora_db_parameter_group_p.id : null backup_retention_period = var.backup_retention_period @@ -169,20 +180,34 @@ resource "aws_rds_cluster" "primary" { #tfsec:ignore:aws-rds-encrypt-cluster-storage-data storage_encrypted = var.storage_encrypted kms_key_id = var.storage_encrypted ? aws_kms_key.kms_p[0].arn : null + storage_type = var.storage_type apply_immediately = true skip_final_snapshot = var.skip_final_snapshot final_snapshot_identifier = var.skip_final_snapshot ? null : "${var.final_snapshot_identifier_prefix}-${var.identifier}-${var.region}-${random_id.snapshot_id.hex}" snapshot_identifier = var.snapshot_identifier != "" ? var.snapshot_identifier : null enabled_cloudwatch_logs_exports = local.logs_set tags = var.tags + + dynamic "serverlessv2_scaling_configuration" { + for_each = var.instance_class == "db.serverless" ? [local.serverlessv2_scaling_configuration] : [] + + content { + max_capacity = serverlessv2_scaling_configuration.value.max_capacity + min_capacity = serverlessv2_scaling_configuration.value.min_capacity + } + } + depends_on = [ # When this Aurora cluster is setup as a secondary, setting up the dependency makes sure to delete this cluster 1st before deleting current primary Cluster during terraform destroy # Comment out the following line if this cluster has changed role to be the primary Aurora cluster because of a failover for terraform destroy to work - #aws_rds_cluster_instance.secondary, + # aws_rds_cluster_instance.secondary, ] + lifecycle { ignore_changes = [ replication_source_identifier, + global_cluster_identifier, + snapshot_identifier, # Since Terraform doesn't allow to conditionally specify a lifecycle policy, this can't be done dynamically. # Uncomment the following line for Aurora Global Database to do major version upgrade as per https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_global_cluster # engine_version, @@ -227,22 +252,35 @@ resource "aws_rds_cluster" "secondary" { preferred_backup_window = var.preferred_backup_window source_region = var.storage_encrypted ? var.region : null kms_key_id = var.storage_encrypted ? aws_kms_key.kms_s[0].arn : null + storage_type = var.storage_type apply_immediately = true skip_final_snapshot = var.skip_final_snapshot final_snapshot_identifier = var.skip_final_snapshot ? null : "${var.final_snapshot_identifier_prefix}-${var.identifier}-${var.sec_region}-${random_id.snapshot_id.hex}" enabled_cloudwatch_logs_exports = local.logs_set tags = var.tags + + dynamic "serverlessv2_scaling_configuration" { + for_each = var.instance_class == "db.serverless" ? [local.serverlessv2_scaling_configuration] : [] + + content { + max_capacity = serverlessv2_scaling_configuration.value.max_capacity + min_capacity = serverlessv2_scaling_configuration.value.min_capacity + } + } + depends_on = [ # When this Aurora cluster is setup as a secondary, setting up the dependency makes sure to delete this cluster 1st before deleting current primary Cluster during terraform destroy # Comment out the following line if this cluster has changed role to be the primary Aurora cluster because of a failover for terraform destroy to work aws_rds_cluster_instance.primary, ] + lifecycle { ignore_changes = [ replication_source_identifier, + global_cluster_identifier, # Since Terraform doesn't allow to conditionally specify a lifecycle policy, this can't be done dynamically. # Uncomment the following line for Aurora Global Database to do major version upgrade as per https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_global_cluster - # engine_version, + # engine_version, ] } } @@ -410,7 +448,7 @@ resource "aws_db_event_subscription" "default_s" { resource "aws_cloudwatch_metric_alarm" "cpu_util_p" { count = var.primary_instance_count provider = aws.primary - alarm_name = "CPU_Util-${element(split(",", join(",", aws_rds_cluster_instance.primary.*.id)), count.index)}" + alarm_name = "CPU_Util-${element(split(",", join(",", aws_rds_cluster_instance.primary[*].id)), count.index)}" alarm_description = "This metric monitors Aurora Instance CPU Utilization" metric_name = "CPUUtilization" comparison_operator = "GreaterThanOrEqualToThreshold" @@ -423,14 +461,14 @@ resource "aws_cloudwatch_metric_alarm" "cpu_util_p" { alarm_actions = [aws_sns_topic.default_p.arn] namespace = "AWS/RDS" dimensions = { - DBInstanceIdentifier = "${element(aws_rds_cluster_instance.primary.*.id, count.index)}" + DBInstanceIdentifier = element(aws_rds_cluster_instance.primary[*].id, count.index) } } resource "aws_cloudwatch_metric_alarm" "free_local_storage_p" { count = var.primary_instance_count provider = aws.primary - alarm_name = "Free_local_storage-${element(split(",", join(",", aws_rds_cluster_instance.primary.*.id)), count.index)}" + alarm_name = "Free_local_storage-${element(split(",", join(",", aws_rds_cluster_instance.primary[*].id)), count.index)}" alarm_description = "This metric monitors Aurora Local Storage Utilization" metric_name = "FreeLocalStorage" comparison_operator = "LessThanOrEqualToThreshold" @@ -443,14 +481,14 @@ resource "aws_cloudwatch_metric_alarm" "free_local_storage_p" { alarm_actions = [aws_sns_topic.default_p.arn] namespace = "AWS/RDS" dimensions = { - DBInstanceIdentifier = "${element(aws_rds_cluster_instance.primary.*.id, count.index)}" + DBInstanceIdentifier = element(aws_rds_cluster_instance.primary[*].id, count.index) } } resource "aws_cloudwatch_metric_alarm" "free_random_access_memory_p" { count = var.primary_instance_count provider = aws.primary - alarm_name = "FreeableMemory-${element(split(",", join(",", aws_rds_cluster_instance.primary.*.id)), count.index)}" + alarm_name = "FreeableMemory-${element(split(",", join(",", aws_rds_cluster_instance.primary[*].id)), count.index)}" alarm_description = "This metric monitors Aurora Instance Random Access Memory Utilization" metric_name = "FreeableMemory" comparison_operator = "LessThanOrEqualToThreshold" @@ -463,7 +501,7 @@ resource "aws_cloudwatch_metric_alarm" "free_random_access_memory_p" { alarm_actions = [aws_sns_topic.default_p.arn] namespace = "AWS/RDS" dimensions = { - DBInstanceIdentifier = "${element(aws_rds_cluster_instance.primary.*.id, count.index)}" + DBInstanceIdentifier = element(aws_rds_cluster_instance.primary[*].id, count.index) } } @@ -483,7 +521,7 @@ resource "aws_cloudwatch_metric_alarm" "pg_max_used_tx_ids_p" { alarm_actions = [aws_sns_topic.default_p.arn] namespace = "AWS/RDS" dimensions = { - DBClusterIdentifier = "${aws_rds_cluster.primary.id}" + DBClusterIdentifier = aws_rds_cluster.primary.id Role = "WRITER" } } @@ -491,7 +529,7 @@ resource "aws_cloudwatch_metric_alarm" "pg_max_used_tx_ids_p" { resource "aws_cloudwatch_metric_alarm" "cpu_util_s" { count = var.setup_globaldb ? var.secondary_instance_count : 0 provider = aws.secondary - alarm_name = "CPU_Util-${element(split(",", join(",", aws_rds_cluster_instance.secondary.*.id)), count.index)}" + alarm_name = "CPU_Util-${element(split(",", join(",", aws_rds_cluster_instance.secondary[*].id)), count.index)}" alarm_description = "This metric monitors Aurora Instance CPU Utilization" metric_name = "CPUUtilization" comparison_operator = "GreaterThanOrEqualToThreshold" @@ -504,14 +542,14 @@ resource "aws_cloudwatch_metric_alarm" "cpu_util_s" { alarm_actions = [aws_sns_topic.default_s[0].arn] namespace = "AWS/RDS" dimensions = { - DBInstanceIdentifier = "${element(aws_rds_cluster_instance.secondary.*.id, count.index)}" + DBInstanceIdentifier = element(aws_rds_cluster_instance.secondary[*].id, count.index) } } resource "aws_cloudwatch_metric_alarm" "free_local_storage_s" { count = var.setup_globaldb ? var.secondary_instance_count : 0 provider = aws.secondary - alarm_name = "Free_local_storage-${element(split(",", join(",", aws_rds_cluster_instance.secondary.*.id)), count.index)}" + alarm_name = "Free_local_storage-${element(split(",", join(",", aws_rds_cluster_instance.secondary[*].id)), count.index)}" alarm_description = "This metric monitors Aurora Local Storage Utilization" metric_name = "FreeLocalStorage" comparison_operator = "LessThanOrEqualToThreshold" @@ -524,14 +562,14 @@ resource "aws_cloudwatch_metric_alarm" "free_local_storage_s" { alarm_actions = [aws_sns_topic.default_s[0].arn] namespace = "AWS/RDS" dimensions = { - DBInstanceIdentifier = "${element(aws_rds_cluster_instance.secondary.*.id, count.index)}" + DBInstanceIdentifier = element(aws_rds_cluster_instance.secondary[*].id, count.index) } } resource "aws_cloudwatch_metric_alarm" "free_random_access_memory_s" { count = var.setup_globaldb ? var.secondary_instance_count : 0 provider = aws.secondary - alarm_name = "FreeableMemory-${element(split(",", join(",", aws_rds_cluster_instance.secondary.*.id)), count.index)}" + alarm_name = "FreeableMemory-${element(split(",", join(",", aws_rds_cluster_instance.secondary[*].id)), count.index)}" alarm_description = "This metric monitors Aurora Instance Random Access Memory Utilization" metric_name = "FreeableMemory" comparison_operator = "LessThanOrEqualToThreshold" @@ -544,7 +582,7 @@ resource "aws_cloudwatch_metric_alarm" "free_random_access_memory_s" { alarm_actions = [aws_sns_topic.default_s[0].arn] namespace = "AWS/RDS" dimensions = { - DBInstanceIdentifier = "${element(aws_rds_cluster_instance.secondary.*.id, count.index)}" + DBInstanceIdentifier = element(aws_rds_cluster_instance.secondary[*].id, count.index) } } @@ -564,7 +602,7 @@ resource "aws_cloudwatch_metric_alarm" "pg_max_used_tx_ids_s" { alarm_actions = [aws_sns_topic.default_s[0].arn] namespace = "AWS/RDS" dimensions = { - DBClusterIdentifier = "${aws_rds_cluster.secondary[0].id}" + DBClusterIdentifier = aws_rds_cluster.secondary[0].id Role = "WRITER" } } \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index bb6894e..4dffe8c 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,34 +1,64 @@ # aws_rds_cluster -output "aurora_cluster_arn" { +output "primary_aurora_cluster_arn" { description = "The ARN of the Primary Aurora cluster" value = aws_rds_cluster.primary.arn } -output "aurora_cluster_id" { +output "secondary_aurora_cluster_arn" { + description = "The ARN of the Secondary Aurora cluster" + value = one(aws_rds_cluster.secondary[*].arn) +} + +output "primary_aurora_cluster_id" { description = "The ID of the Primary Aurora cluster" value = aws_rds_cluster.primary.id } -output "aurora_cluster_resource_id" { +output "secondary_aurora_cluster_id" { + description = "The ID of the Secondary Aurora cluster" + value = one(aws_rds_cluster.secondary[*].id) +} + +output "primary_aurora_cluster_resource_id" { description = "The Cluster Resource ID of the Primary Aurora cluster" value = aws_rds_cluster.primary.cluster_resource_id } -output "aurora_cluster_endpoint" { +output "secondary_aurora_cluster_resource_id" { + description = "The Cluster Resource ID of the Secondary Aurora cluster" + value = one(aws_rds_cluster.secondary[*].cluster_resource_id) +} + +output "primary_aurora_cluster_endpoint" { description = "Primary Aurora cluster endpoint" value = aws_rds_cluster.primary.endpoint } -output "aurora_cluster_reader_endpoint" { +output "secondary_aurora_cluster_endpoint" { + description = "Secondary Aurora cluster endpoint" + value = one(aws_rds_cluster.secondary[*].endpoint) +} + +output "primary_aurora_cluster_reader_endpoint" { description = "Primary Aurora cluster reader endpoint" value = aws_rds_cluster.primary.reader_endpoint } -output "aurora_cluster_port" { +output "secondary_aurora_cluster_reader_endpoint" { + description = "Secondary Aurora cluster reader endpoint" + value = one(aws_rds_cluster.secondary[*].reader_endpoint) +} + +output "primary_aurora_cluster_port" { description = "Primary Aurora cluster endpoint port" value = aws_rds_cluster.primary.port } +output "secondary_aurora_cluster_port" { + description = "Secondary Aurora cluster endpoint port" + value = one(aws_rds_cluster.secondary[*].port) +} + output "aurora_cluster_database_name" { description = "Name for an automatically created database on Aurora cluster creation" value = var.database_name @@ -41,22 +71,37 @@ output "aurora_cluster_master_username" { output "aurora_cluster_master_password" { description = "Aurora master User password" - value = aws_rds_cluster.primary.master_password + value = try(aws_rds_cluster.primary.master_password, null) sensitive = true } -output "aurora_cluster_hosted_zone_id" { +output "primary_aurora_cluster_hosted_zone_id" { description = "Route53 hosted zone id of the Primary Aurora cluster" value = aws_rds_cluster.primary.hosted_zone_id } +output "secondary_aurora_cluster_hosted_zone_id" { + description = "Route53 hosted zone id of the Secondary Aurora cluster" + value = one(aws_rds_cluster.secondary[*].hosted_zone_id) +} + # aws_rds_cluster_instance -output "aurora_cluster_instance_endpoints" { +output "primary_aurora_cluster_instance_endpoints" { description = "A list of all Primary Aurora cluster instance endpoints" - value = aws_rds_cluster_instance.primary.*.endpoint + value = aws_rds_cluster_instance.primary[*].endpoint } -output "aurora_cluster_instance_ids" { +output "secondary_aurora_cluster_instance_endpoints" { + description = "A list of all Secondary Aurora cluster instance endpoints" + value = try(aws_rds_cluster_instance.secondary[*].endpoint, null) +} + +output "primary_aurora_cluster_instance_ids" { description = "A list of all Primary Aurora cluster instance ids" - value = aws_rds_cluster_instance.primary.*.id + value = aws_rds_cluster_instance.primary[*].id +} + +output "secondary_aurora_cluster_instance_ids" { + description = "A list of all Secondary Aurora cluster instance ids" + value = try(aws_rds_cluster_instance.secondary[*].id, null) } \ No newline at end of file diff --git a/providers.tf b/providers.tf index 364d6b5..d051937 100644 --- a/providers.tf +++ b/providers.tf @@ -1,13 +1,13 @@ # https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md -# https://github.com/hashicorp/terraform/blob/v1.0.10/CHANGELOG.md +# https://github.com/hashicorp/terraform/releases terraform { - required_version = ">= 1.0.0" + required_version = ">= 1.3.0" backend "remote" {} required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.9.0" + version = ">= 5.30" } random = { source = "hashicorp/random" diff --git a/variables.tf b/variables.tf index ff03334..ff69088 100644 --- a/variables.tf +++ b/variables.tf @@ -20,13 +20,6 @@ variable "name" { default = "aurora" } -/* -variable "vpc_id" { - type = string - description = "VPC id" -} -*/ - variable "private_subnet_ids_p" { type = list(string) description = "A list of private subnet IDs in your Primary AWS region VPC" @@ -59,8 +52,8 @@ variable "secondary_instance_count" { variable "instance_class" { type = string - description = "Instance type to use at replica instance" - default = "db.r5.large" + description = "Aurora DB Instance type. Specify db.serverless to create Aurora Serverless v2 instances." + default = "db.r7g.large" } variable "skip_final_snapshot" { @@ -93,6 +86,12 @@ variable "password" { type = string } +variable "manage_master_user_password" { + description = "Manage master user password using AWS Secrets Manager" + type = bool + default = false +} + variable "backup_retention_period" { description = "How long to keep backups for (in days)" type = number @@ -129,6 +128,12 @@ variable "storage_encrypted" { default = false } +variable "storage_type" { + description = "Specifies Aurora storage type: Aurora Standard vs. Aurora I/O-Optimized" + type = string + default = "" +} + variable "engine" { description = "Aurora database engine type: aurora (for MySQL 5.6-compatible Aurora), aurora-mysql (for MySQL 5.7-compatible Aurora), aurora-postgresql" type = string @@ -138,13 +143,13 @@ variable "engine" { variable "engine_version_pg" { description = "Aurora database engine version." type = string - default = "13.6" + default = "15.4" } variable "engine_version_mysql" { description = "Aurora database engine version." type = string - default = "5.7.mysql_aurora.2.10.2" + default = "8.0.mysql_aurora.3.05.1" } variable "setup_globaldb" { @@ -219,4 +224,16 @@ variable "enable_postgresql_log" { description = "Enable PostgreSQL log export to Amazon Cloudwatch." type = bool default = false +} + +variable "serverless_v2_min_acu" { + description = "Aurora Serverless v2 Minimum ACU" + type = number + default = 0.5 +} + +variable "serverless_v2_max_acu" { + description = "Aurora Serverless v2 Maximum ACU" + type = number + default = 16 } \ No newline at end of file From b9e709b7cf3fc3478cf87dcaeed309e63ee118aa Mon Sep 17 00:00:00 2001 From: Arabinda Pani <22154314+catcharbind@users.noreply.github.com> Date: Wed, 20 Dec 2023 13:00:17 -0800 Subject: [PATCH 3/3] fixing typo --- main.tf | 2 +- providers.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index 5e7a7cc..9f7fba6 100644 --- a/main.tf +++ b/main.tf @@ -168,7 +168,7 @@ resource "aws_rds_cluster" "primary" { db_subnet_group_name = aws_db_subnet_group.private_p.name port = var.port == "" ? var.engine == "aurora-postgresql" ? "5432" : "3306" : var.port database_name = var.setup_as_secondary || (var.snapshot_identifier != "") ? null : var.database_name - # Aurora global DB currently doesnt support master password manager with AWS Secrets Manager + # Aurora global DB currently doesn't support master password management with AWS Secrets Manager manage_master_user_password = !var.setup_globaldb && var.manage_master_user_password ? var.manage_master_user_password : null master_user_secret_kms_key_id = !var.setup_globaldb && var.manage_master_user_password ? aws_kms_key.kms_p[0].arn : null master_username = var.setup_as_secondary || (var.snapshot_identifier != "") ? null : var.username diff --git a/providers.tf b/providers.tf index d051937..201c61a 100644 --- a/providers.tf +++ b/providers.tf @@ -3,7 +3,7 @@ terraform { required_version = ">= 1.3.0" - backend "remote" {} + # backend "remote" {} required_providers { aws = { source = "hashicorp/aws"