From 783c6864d4fe0d610a62d00d5ff8e5edb08a008a Mon Sep 17 00:00:00 2001 From: Melissa Greenbaum <69476188+magreenbaum@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:24:36 -0400 Subject: [PATCH] feat: Add RDS cluster activity stream (#407) * add db_cluster_activity_stream * add ouptuts --------- Co-authored-by: magreenbaum --- README.md | 6 ++++ examples/mysql/README.md | 3 ++ examples/mysql/main.tf | 55 ++++++++++++++++++++++++++++++++++ examples/mysql/outputs.tf | 9 ++++++ examples/postgresql/README.md | 2 ++ examples/postgresql/main.tf | 19 ++++++++++++ examples/postgresql/outputs.tf | 9 ++++++ main.tf | 15 ++++++++++ outputs.tf | 9 ++++++ variables.tf | 28 +++++++++++++++++ 10 files changed, 155 insertions(+) diff --git a/README.md b/README.md index 656adae9..26451203 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,7 @@ No modules. | [aws_iam_role.rds_enhanced_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy_attachment.rds_enhanced_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_rds_cluster.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster) | resource | +| [aws_rds_cluster_activity_stream.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_activity_stream) | resource | | [aws_rds_cluster_endpoint.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_endpoint) | resource | | [aws_rds_cluster_instance.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_instance) | resource | | [aws_rds_cluster_parameter_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_parameter_group) | resource | @@ -286,12 +287,15 @@ No modules. | [copy\_tags\_to\_snapshot](#input\_copy\_tags\_to\_snapshot) | Copy all Cluster `tags` to snapshots | `bool` | `null` | no | | [create](#input\_create) | Whether cluster should be created (affects nearly all resources) | `bool` | `true` | no | | [create\_cloudwatch\_log\_group](#input\_create\_cloudwatch\_log\_group) | Determines whether a CloudWatch log group is created for each `enabled_cloudwatch_logs_exports` | `bool` | `false` | no | +| [create\_db\_cluster\_activity\_stream](#input\_create\_db\_cluster\_activity\_stream) | Determines whether a cluster activity stream is created. | `bool` | `false` | no | | [create\_db\_cluster\_parameter\_group](#input\_create\_db\_cluster\_parameter\_group) | Determines whether a cluster parameter should be created or use existing | `bool` | `false` | no | | [create\_db\_parameter\_group](#input\_create\_db\_parameter\_group) | Determines whether a DB parameter should be created or use existing | `bool` | `false` | no | | [create\_db\_subnet\_group](#input\_create\_db\_subnet\_group) | Determines whether to create the database subnet group or use existing | `bool` | `false` | no | | [create\_monitoring\_role](#input\_create\_monitoring\_role) | Determines whether to create the IAM role for RDS enhanced monitoring | `bool` | `true` | no | | [create\_security\_group](#input\_create\_security\_group) | Determines whether to create security group for RDS cluster | `bool` | `true` | no | | [database\_name](#input\_database\_name) | Name for an automatically created database on cluster creation | `string` | `null` | no | +| [db\_cluster\_activity\_stream\_kms\_key\_id](#input\_db\_cluster\_activity\_stream\_kms\_key\_id) | The AWS KMS key identifier for encrypting messages in the database activity stream | `string` | `null` | no | +| [db\_cluster\_activity\_stream\_mode](#input\_db\_cluster\_activity\_stream\_mode) | Specifies the mode of the database activity stream. Database events such as a change or access generate an activity stream event. One of: sync, async | `string` | `null` | no | | [db\_cluster\_db\_instance\_parameter\_group\_name](#input\_db\_cluster\_db\_instance\_parameter\_group\_name) | Instance parameter group to associate with all instances of the DB cluster. The `db_cluster_db_instance_parameter_group_name` is only valid in combination with `allow_major_version_upgrade` | `string` | `null` | no | | [db\_cluster\_instance\_class](#input\_db\_cluster\_instance\_class) | The compute and memory capacity of each DB instance in the Multi-AZ DB cluster, for example db.m6g.xlarge. Not all DB instance classes are available in all AWS Regions, or for all database engines | `string` | `null` | no | | [db\_cluster\_parameter\_group\_description](#input\_db\_cluster\_parameter\_group\_description) | The description of the DB cluster parameter group. Defaults to "Managed by Terraform" | `string` | `null` | no | @@ -312,6 +316,7 @@ No modules. | [endpoints](#input\_endpoints) | Map of additional cluster endpoints and their attributes to be created | `any` | `{}` | no | | [engine](#input\_engine) | The name of the database engine to be used for this DB cluster. Defaults to `aurora`. Valid Values: `aurora`, `aurora-mysql`, `aurora-postgresql` | `string` | `null` | no | | [engine\_mode](#input\_engine\_mode) | The database engine mode. Valid values: `global`, `multimaster`, `parallelquery`, `provisioned`, `serverless`. Defaults to: `provisioned` | `string` | `"provisioned"` | no | +| [engine\_native\_audit\_fields\_included](#input\_engine\_native\_audit\_fields\_included) | Specifies whether the database activity stream includes engine-native audit fields. This option only applies to an Oracle DB instance. By default, no engine-native audit fields are included | `bool` | `false` | no | | [engine\_version](#input\_engine\_version) | The database engine version. Updating this argument results in an outage | `string` | `null` | no | | [final\_snapshot\_identifier](#input\_final\_snapshot\_identifier) | The name of your final DB snapshot when this DB cluster is deleted. If omitted, no final snapshot will be made | `string` | `null` | no | | [global\_cluster\_identifier](#input\_global\_cluster\_identifier) | The global cluster identifier specified on `aws_rds_global_cluster` | `string` | `null` | no | @@ -389,6 +394,7 @@ No modules. | [cluster\_reader\_endpoint](#output\_cluster\_reader\_endpoint) | A read-only endpoint for the cluster, automatically load-balanced across replicas | | [cluster\_resource\_id](#output\_cluster\_resource\_id) | The RDS Cluster Resource ID | | [cluster\_role\_associations](#output\_cluster\_role\_associations) | A map of IAM roles associated with the cluster and their attributes | +| [db\_cluster\_activity\_stream\_kinesis\_stream\_name](#output\_db\_cluster\_activity\_stream\_kinesis\_stream\_name) | The name of the Amazon Kinesis data stream to be used for the database activity stream | | [db\_cluster\_cloudwatch\_log\_groups](#output\_db\_cluster\_cloudwatch\_log\_groups) | Map of CloudWatch log groups created and their attributes | | [db\_cluster\_parameter\_group\_arn](#output\_db\_cluster\_parameter\_group\_arn) | The ARN of the DB cluster parameter group created | | [db\_cluster\_parameter\_group\_id](#output\_db\_cluster\_parameter\_group\_id) | The ID of the DB cluster parameter group created | diff --git a/examples/mysql/README.md b/examples/mysql/README.md index ef80909a..21424c41 100644 --- a/examples/mysql/README.md +++ b/examples/mysql/README.md @@ -33,7 +33,9 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Source | Version | |------|--------|---------| | [aurora](#module\_aurora) | ../../ | n/a | +| [kms](#module\_kms) | terraform-aws-modules/kms/aws | ~> 2.0 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | +| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 | ## Resources @@ -63,6 +65,7 @@ No inputs. | [cluster\_reader\_endpoint](#output\_cluster\_reader\_endpoint) | A read-only endpoint for the cluster, automatically load-balanced across replicas | | [cluster\_resource\_id](#output\_cluster\_resource\_id) | The RDS Cluster Resource ID | | [cluster\_role\_associations](#output\_cluster\_role\_associations) | A map of IAM roles associated with the cluster and their attributes | +| [db\_cluster\_activity\_stream\_kinesis\_stream\_name](#output\_db\_cluster\_activity\_stream\_kinesis\_stream\_name) | The name of the Amazon Kinesis data stream to be used for the database activity stream | | [db\_cluster\_cloudwatch\_log\_groups](#output\_db\_cluster\_cloudwatch\_log\_groups) | Map of CloudWatch log groups created and their attributes | | [db\_cluster\_parameter\_group\_arn](#output\_db\_cluster\_parameter\_group\_arn) | The ARN of the DB cluster parameter group created | | [db\_cluster\_parameter\_group\_id](#output\_db\_cluster\_parameter\_group\_id) | The ID of the DB cluster parameter group created | diff --git a/examples/mysql/main.tf b/examples/mysql/main.tf index 60d92c68..45c108c3 100644 --- a/examples/mysql/main.tf +++ b/examples/mysql/main.tf @@ -51,6 +51,12 @@ module "aurora" { vpc_ingress = { cidr_blocks = module.vpc.private_subnets_cidr_blocks } + kms_vpc_endpoint = { + type = "egress" + from_port = 443 + to_port = 443 + source_security_group_id = module.vpc_endpoints.security_group_id + } } apply_immediately = true @@ -142,6 +148,12 @@ module "aurora" { enabled_cloudwatch_logs_exports = ["audit", "error", "general", "slowquery"] + create_db_cluster_activity_stream = true + db_cluster_activity_stream_kms_key_id = module.kms.key_id + + # https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/DBActivityStreams.Overview.html#DBActivityStreams.Overview.sync-mode + db_cluster_activity_stream_mode = "async" + tags = local.tags } @@ -163,3 +175,46 @@ module "vpc" { tags = local.tags } + +module "kms" { + source = "terraform-aws-modules/kms/aws" + version = "~> 2.0" + + deletion_window_in_days = 7 + description = "KMS key for ${local.name} cluster activity stream." + enable_key_rotation = true + is_enabled = true + key_usage = "ENCRYPT_DECRYPT" + + aliases = [local.name] + + tags = local.tags +} + +# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/DBActivityStreams.Prereqs.html#DBActivityStreams.Prereqs.KMS +module "vpc_endpoints" { + source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" + version = "~> 5.0" + + vpc_id = module.vpc.vpc_id + + create_security_group = true + security_group_name_prefix = "${local.name}-vpc-endpoints-" + security_group_description = "VPC endpoint security group" + security_group_rules = { + ingress_https = { + description = "HTTPS from VPC" + cidr_blocks = [module.vpc.vpc_cidr_block] + } + } + + endpoints = { + kms = { + service = "kms" + private_dns_enabled = true + subnet_ids = module.vpc.database_subnets + } + } + + tags = local.tags +} diff --git a/examples/mysql/outputs.tf b/examples/mysql/outputs.tf index 2deaba75..f882e4ee 100644 --- a/examples/mysql/outputs.tf +++ b/examples/mysql/outputs.tf @@ -157,3 +157,12 @@ output "db_cluster_cloudwatch_log_groups" { description = "Map of CloudWatch log groups created and their attributes" value = module.aurora.db_cluster_cloudwatch_log_groups } + +################################################################################ +# Cluster Activity Stream +################################################################################ + +output "db_cluster_activity_stream_kinesis_stream_name" { + description = "The name of the Amazon Kinesis data stream to be used for the database activity stream" + value = module.aurora.db_cluster_activity_stream_kinesis_stream_name +} diff --git a/examples/postgresql/README.md b/examples/postgresql/README.md index 6e4c45f4..0da32418 100644 --- a/examples/postgresql/README.md +++ b/examples/postgresql/README.md @@ -33,6 +33,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Source | Version | |------|--------|---------| | [aurora](#module\_aurora) | ../../ | n/a | +| [kms](#module\_kms) | terraform-aws-modules/kms/aws | ~> 2.0 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | ## Resources @@ -63,6 +64,7 @@ No inputs. | [cluster\_reader\_endpoint](#output\_cluster\_reader\_endpoint) | A read-only endpoint for the cluster, automatically load-balanced across replicas | | [cluster\_resource\_id](#output\_cluster\_resource\_id) | The RDS Cluster Resource ID | | [cluster\_role\_associations](#output\_cluster\_role\_associations) | A map of IAM roles associated with the cluster and their attributes | +| [db\_cluster\_activity\_stream\_kinesis\_stream\_name](#output\_db\_cluster\_activity\_stream\_kinesis\_stream\_name) | The name of the Amazon Kinesis data stream to be used for the database activity stream | | [db\_cluster\_cloudwatch\_log\_groups](#output\_db\_cluster\_cloudwatch\_log\_groups) | Map of CloudWatch log groups created and their attributes | | [db\_cluster\_parameter\_group\_arn](#output\_db\_cluster\_parameter\_group\_arn) | The ARN of the DB cluster parameter group created | | [db\_cluster\_parameter\_group\_id](#output\_db\_cluster\_parameter\_group\_id) | The ID of the DB cluster parameter group created | diff --git a/examples/postgresql/main.tf b/examples/postgresql/main.tf index 5cf2d69d..bd594abf 100644 --- a/examples/postgresql/main.tf +++ b/examples/postgresql/main.tf @@ -108,6 +108,10 @@ module "aurora" { enabled_cloudwatch_logs_exports = ["postgresql"] create_cloudwatch_log_group = true + create_db_cluster_activity_stream = true + db_cluster_activity_stream_kms_key_id = module.kms.key_id + db_cluster_activity_stream_mode = "async" + tags = local.tags } @@ -129,3 +133,18 @@ module "vpc" { tags = local.tags } + +module "kms" { + source = "terraform-aws-modules/kms/aws" + version = "~> 2.0" + + deletion_window_in_days = 7 + description = "KMS key for ${local.name} cluster activity stream." + enable_key_rotation = true + is_enabled = true + key_usage = "ENCRYPT_DECRYPT" + + aliases = [local.name] + + tags = local.tags +} diff --git a/examples/postgresql/outputs.tf b/examples/postgresql/outputs.tf index 2deaba75..f882e4ee 100644 --- a/examples/postgresql/outputs.tf +++ b/examples/postgresql/outputs.tf @@ -157,3 +157,12 @@ output "db_cluster_cloudwatch_log_groups" { description = "Map of CloudWatch log groups created and their attributes" value = module.aurora.db_cluster_cloudwatch_log_groups } + +################################################################################ +# Cluster Activity Stream +################################################################################ + +output "db_cluster_activity_stream_kinesis_stream_name" { + description = "The name of the Amazon Kinesis data stream to be used for the database activity stream" + value = module.aurora.db_cluster_activity_stream_kinesis_stream_name +} diff --git a/main.tf b/main.tf index 8e617c3e..e5a4ecdc 100644 --- a/main.tf +++ b/main.tf @@ -412,3 +412,18 @@ resource "aws_cloudwatch_log_group" "this" { tags = var.tags } + +################################################################################ +# Cluster Activity Stream +################################################################################ + +resource "aws_rds_cluster_activity_stream" "this" { + count = local.create && var.create_db_cluster_activity_stream ? 1 : 0 + + resource_arn = aws_rds_cluster.this[0].arn + mode = var.db_cluster_activity_stream_mode + kms_key_id = var.db_cluster_activity_stream_kms_key_id + engine_native_audit_fields_included = var.engine_native_audit_fields_included + + depends_on = [aws_rds_cluster_instance.this] +} diff --git a/outputs.tf b/outputs.tf index f3744c2a..5a461738 100644 --- a/outputs.tf +++ b/outputs.tf @@ -170,3 +170,12 @@ output "db_cluster_cloudwatch_log_groups" { description = "Map of CloudWatch log groups created and their attributes" value = aws_cloudwatch_log_group.this } + +################################################################################ +# Cluster Activity Stream +################################################################################ + +output "db_cluster_activity_stream_kinesis_stream_name" { + description = "The name of the Amazon Kinesis data stream to be used for the database activity stream" + value = try(aws_rds_cluster_activity_stream.this[0].kinesis_stream_name, null) +} diff --git a/variables.tf b/variables.tf index 0b226a5f..62f18b64 100644 --- a/variables.tf +++ b/variables.tf @@ -683,3 +683,31 @@ variable "cloudwatch_log_group_kms_key_id" { type = string default = null } + +################################################################################ +# Cluster Activity Stream +################################################################################ + +variable "create_db_cluster_activity_stream" { + description = "Determines whether a cluster activity stream is created." + type = bool + default = false +} + +variable "db_cluster_activity_stream_mode" { + description = "Specifies the mode of the database activity stream. Database events such as a change or access generate an activity stream event. One of: sync, async" + type = string + default = null +} + +variable "db_cluster_activity_stream_kms_key_id" { + description = "The AWS KMS key identifier for encrypting messages in the database activity stream" + type = string + default = null +} + +variable "engine_native_audit_fields_included" { + description = "Specifies whether the database activity stream includes engine-native audit fields. This option only applies to an Oracle DB instance. By default, no engine-native audit fields are included" + type = bool + default = false +}