diff --git a/README.md b/README.md
index 4e8a9df..d4b5798 100644
--- a/README.md
+++ b/README.md
@@ -210,6 +210,7 @@ No modules.
| [aws_redshift_snapshot_schedule_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/redshift_snapshot_schedule_association) | resource |
| [aws_redshift_subnet_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/redshift_subnet_group) | resource |
| [aws_redshift_usage_limit.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/redshift_usage_limit) | resource |
+| [aws_secretsmanager_secret_rotation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_rotation) | resource |
| [random_password.master_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
| [aws_iam_policy_document.scheduled_action](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.scheduled_action_assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
@@ -262,8 +263,13 @@ No modules.
| [logging](#input\_logging) | Logging configuration for the cluster | `any` | `{}` | no |
| [maintenance\_track\_name](#input\_maintenance\_track\_name) | The name of the maintenance track for the restored cluster. When you take a snapshot, the snapshot inherits the MaintenanceTrack value from the cluster. The snapshot might be on a different track than the cluster that was the source for the snapshot. Default value is `current` | `string` | `null` | no |
| [manage\_master\_password](#input\_manage\_master\_password) | Whether to use AWS SecretsManager to manage the cluster admin credentials. Conflicts with `master_password`. One of `master_password` or `manage_master_password` is required unless `snapshot_identifier` is provided | `bool` | `false` | no |
+| [manage\_master\_password\_rotation](#input\_manage\_master\_password\_rotation) | Whether to manage the master user password rotation. Setting this value to false after previously having been set to true will disable automatic rotation. | `bool` | `false` | no |
| [manual\_snapshot\_retention\_period](#input\_manual\_snapshot\_retention\_period) | The default number of days to retain a manual snapshot. If the value is -1, the snapshot is retained indefinitely. This setting doesn't change the retention period of existing snapshots. Valid values are between `-1` and `3653`. Default value is `-1` | `number` | `null` | no |
| [master\_password](#input\_master\_password) | Password for the master DB user. (Required unless a `snapshot_identifier` is provided). Must contain at least 8 chars, one uppercase letter, one lowercase letter, and one number | `string` | `null` | no |
+| [master\_password\_rotate\_immediately](#input\_master\_password\_rotate\_immediately) | Specifies whether to rotate the secret immediately or wait until the next scheduled rotation window. | `bool` | `null` | no |
+| [master\_password\_rotation\_automatically\_after\_days](#input\_master\_password\_rotation\_automatically\_after\_days) | Specifies the number of days between automatic scheduled rotations of the secret. Either `master_user_password_rotation_automatically_after_days` or `master_user_password_rotation_schedule_expression` must be specified. | `number` | `null` | no |
+| [master\_password\_rotation\_duration](#input\_master\_password\_rotation\_duration) | The length of the rotation window in hours. For example, 3h for a three hour window. | `string` | `null` | no |
+| [master\_password\_rotation\_schedule\_expression](#input\_master\_password\_rotation\_schedule\_expression) | A cron() or rate() expression that defines the schedule for rotating your secret. Either `master_user_password_rotation_automatically_after_days` or `master_user_password_rotation_schedule_expression` must be specified. | `string` | `null` | no |
| [master\_password\_secret\_kms\_key\_id](#input\_master\_password\_secret\_kms\_key\_id) | ID of the KMS key used to encrypt the cluster admin credentials secret | `string` | `null` | no |
| [master\_username](#input\_master\_username) | Username for the master DB user (Required unless a `snapshot_identifier` is provided). Defaults to `awsuser` | `string` | `"awsuser"` | no |
| [multi\_az](#input\_multi\_az) | Specifies if the Redshift cluster is multi-AZ | `bool` | `null` | no |
@@ -320,6 +326,7 @@ No modules.
| [cluster\_preferred\_maintenance\_window](#output\_cluster\_preferred\_maintenance\_window) | The backup window |
| [cluster\_public\_key](#output\_cluster\_public\_key) | The public key for the cluster |
| [cluster\_revision\_number](#output\_cluster\_revision\_number) | The specific revision number of the database in the cluster |
+| [cluster\_secretsmanager\_secret\_rotation\_enabled](#output\_cluster\_secretsmanager\_secret\_rotation\_enabled) | Specifies whether automatic rotation is enabled for the secret |
| [cluster\_subnet\_group\_name](#output\_cluster\_subnet\_group\_name) | The name of a cluster subnet group to be associated with this cluster |
| [cluster\_type](#output\_cluster\_type) | The Redshift cluster type |
| [cluster\_version](#output\_cluster\_version) | The version of Redshift engine software |
diff --git a/examples/complete/README.md b/examples/complete/README.md
index 46996aa..2e1a916 100644
--- a/examples/complete/README.md
+++ b/examples/complete/README.md
@@ -92,6 +92,7 @@ No inputs.
| [endpoint\_access\_port](#output\_endpoint\_access\_port) | The port number on which the cluster accepts incoming connections |
| [endpoint\_access\_vpc\_endpoint](#output\_endpoint\_access\_vpc\_endpoint) | The connection endpoint for connecting to an Amazon Redshift cluster through the proxy. See details below |
| [master\_password\_secret\_arn](#output\_master\_password\_secret\_arn) | ARN of managed master password secret |
+| [master\_password\_secretsmanager\_secret\_rotation\_enabled](#output\_master\_password\_secretsmanager\_secret\_rotation\_enabled) | Specifies whether automatic rotation is enabled for the secret |
| [parameter\_group\_arn](#output\_parameter\_group\_arn) | Amazon Resource Name (ARN) of the parameter group created |
| [parameter\_group\_id](#output\_parameter\_group\_id) | The name of the Redshift parameter group created |
| [scheduled\_action\_iam\_role\_arn](#output\_scheduled\_action\_iam\_role\_arn) | Scheduled actions IAM role ARN |
diff --git a/examples/complete/main.tf b/examples/complete/main.tf
index d2e7fc7..f61c8f8 100644
--- a/examples/complete/main.tf
+++ b/examples/complete/main.tf
@@ -45,6 +45,9 @@ module "redshift" {
# Or make Redshift manage it in secrets manager
manage_master_password = true
+ manage_master_password_rotation = true
+ master_password_rotation_schedule_expression = "rate(90 days)"
+
encrypted = true
kms_key_arn = aws_kms_key.redshift.arn
diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf
index a2ecfb1..9f11387 100644
--- a/examples/complete/outputs.tf
+++ b/examples/complete/outputs.tf
@@ -222,3 +222,8 @@ output "master_password_secret_arn" {
description = "ARN of managed master password secret"
value = module.redshift.master_password_secret_arn
}
+
+output "master_password_secretsmanager_secret_rotation_enabled" {
+ description = "Specifies whether automatic rotation is enabled for the secret"
+ value = module.redshift.cluster_secretsmanager_secret_rotation_enabled
+}
diff --git a/main.tf b/main.tf
index 6a8c57d..80dd9e5 100644
--- a/main.tf
+++ b/main.tf
@@ -336,3 +336,20 @@ resource "aws_cloudwatch_log_group" "this" {
tags = merge(var.tags, var.cloudwatch_log_group_tags)
}
+
+################################################################################
+# Managed Secret Rotation
+################################################################################
+
+resource "aws_secretsmanager_secret_rotation" "this" {
+ count = var.create && var.manage_master_password && var.manage_master_password_rotation ? 1 : 0
+
+ secret_id = aws_redshift_cluster.this[0].master_password_secret_arn
+ rotate_immediately = var.master_password_rotate_immediately
+
+ rotation_rules {
+ automatically_after_days = var.master_password_rotation_automatically_after_days
+ duration = var.master_password_rotation_duration
+ schedule_expression = var.master_password_rotation_schedule_expression
+ }
+}
diff --git a/outputs.tf b/outputs.tf
index d0ed8e5..589abe7 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -227,3 +227,12 @@ output "master_password_secret_arn" {
description = "ARN of managed master password secret"
value = try(aws_redshift_cluster.this[0].master_password_secret_arn, null)
}
+
+################################################################################
+# Managed Secret Rotation
+################################################################################
+
+output "cluster_secretsmanager_secret_rotation_enabled" {
+ description = "Specifies whether automatic rotation is enabled for the secret"
+ value = try(aws_secretsmanager_secret_rotation.this[0].rotation_enabled, null)
+}
diff --git a/variables.tf b/variables.tf
index 809ed74..f9cfc55 100644
--- a/variables.tf
+++ b/variables.tf
@@ -508,3 +508,37 @@ variable "cloudwatch_log_group_tags" {
type = map(string)
default = {}
}
+
+################################################################################
+# Managed Secret Rotation
+################################################################################
+
+variable "manage_master_password_rotation" {
+ description = "Whether to manage the master user password rotation. Setting this value to false after previously having been set to true will disable automatic rotation."
+ type = bool
+ default = false
+}
+
+variable "master_password_rotate_immediately" {
+ description = "Specifies whether to rotate the secret immediately or wait until the next scheduled rotation window."
+ type = bool
+ default = null
+}
+
+variable "master_password_rotation_automatically_after_days" {
+ description = "Specifies the number of days between automatic scheduled rotations of the secret. Either `master_user_password_rotation_automatically_after_days` or `master_user_password_rotation_schedule_expression` must be specified."
+ type = number
+ default = null
+}
+
+variable "master_password_rotation_duration" {
+ description = "The length of the rotation window in hours. For example, 3h for a three hour window."
+ type = string
+ default = null
+}
+
+variable "master_password_rotation_schedule_expression" {
+ description = "A cron() or rate() expression that defines the schedule for rotating your secret. Either `master_user_password_rotation_automatically_after_days` or `master_user_password_rotation_schedule_expression` must be specified."
+ type = string
+ default = null
+}