From ecc276f71cf6091685591bb3fc1201e74b285ec1 Mon Sep 17 00:00:00 2001 From: Alexei Mikhailov Date: Mon, 28 Jul 2025 10:26:39 +0300 Subject: [PATCH 1/5] feat: Upgrade AWS provider to 6.0 --- README.md | 6 ++++-- examples/complete/README.md | 5 +++-- examples/complete/main.tf | 11 +++++++++++ examples/complete/versions.tf | 2 +- main.tf | 10 ++++++++++ outputs.tf | 5 +++++ variables.tf | 6 ++++++ versions.tf | 2 +- wrappers/main.tf | 1 + wrappers/versions.tf | 2 +- 10 files changed, 43 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 67b91ad..2ead664 100644 --- a/README.md +++ b/README.md @@ -124,14 +124,14 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 5.0 | +| [aws](#requirement\_aws) | >= 6.0 | | [random](#requirement\_random) | >= 3.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.0 | +| [aws](#provider\_aws) | >= 6.0 | | [random](#provider\_random) | >= 3.0 | ## Modules @@ -170,6 +170,7 @@ No modules. | [random\_password\_length](#input\_random\_password\_length) | The length of the generated random password | `number` | `32` | no | | [random\_password\_override\_special](#input\_random\_password\_override\_special) | Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument | `string` | `"!@#$%&*()-_=+[]{}<>:?"` | no | | [recovery\_window\_in\_days](#input\_recovery\_window\_in\_days) | Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be `0` to force deletion without recovery or range from `7` to `30` days. The default value is `30` | `number` | `null` | no | +| [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no | | [replica](#input\_replica) | Configuration block to support secret replication | `map(any)` | `{}` | no | | [rotation\_lambda\_arn](#input\_rotation\_lambda\_arn) | Specifies the ARN of the Lambda function that can rotate the secret | `string` | `""` | no | | [rotation\_rules](#input\_rotation\_rules) | A structure that defines the rotation configuration for this secret | `map(any)` | `{}` | no | @@ -187,6 +188,7 @@ No modules. | [secret\_binary](#output\_secret\_binary) | The secret binary | | [secret\_id](#output\_secret\_id) | The ID of the secret | | [secret\_name](#output\_secret\_name) | The name of the secret | +| [secret\_region](#output\_secret\_region) | The region of the secret | | [secret\_replica](#output\_secret\_replica) | Attributes of the replica created | | [secret\_string](#output\_secret\_string) | The secret string | | [secret\_version\_id](#output\_secret\_version\_id) | The unique identifier of the version of the secret | diff --git a/examples/complete/README.md b/examples/complete/README.md index de91e6c..bdc0c99 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -29,13 +29,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 5.0 | +| [aws](#requirement\_aws) | >= 6.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.0 | +| [aws](#provider\_aws) | >= 6.0 | ## Modules @@ -43,6 +43,7 @@ Note that this example may create resources which will incur monetary charges on |------|--------|---------| | [lambda](#module\_lambda) | terraform-aws-modules/lambda/aws | ~> 6.0 | | [secrets\_manager](#module\_secrets\_manager) | ../.. | n/a | +| [secrets\_manager\_another\_region](#module\_secrets\_manager\_another\_region) | ../.. | n/a | | [secrets\_manager\_disabled](#module\_secrets\_manager\_disabled) | ../.. | n/a | | [secrets\_manager\_rotate](#module\_secrets\_manager\_rotate) | ../.. | n/a | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 4c2be4e..58a908b 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -123,6 +123,17 @@ module "secrets_manager_disabled" { create = false } +module "secrets_manager_another_region" { + source = "../.." + + region = "us-east-1" + name_prefix = local.name + + create_random_password = true + + tags = local.tags +} + ################################################################################ # Supporting Resources ################################################################################ diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index ddfcb0e..aaf26b8 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.0" + version = ">= 6.0" } } } diff --git a/main.tf b/main.tf index 53e12f9..900c3dd 100644 --- a/main.tf +++ b/main.tf @@ -6,6 +6,8 @@ resource "aws_secretsmanager_secret" "this" { count = var.create ? 1 : 0 + region = var.region + description = var.description force_overwrite_replica_secret = var.force_overwrite_replica_secret kms_key_id = var.kms_key_id @@ -80,6 +82,8 @@ data "aws_iam_policy_document" "this" { resource "aws_secretsmanager_secret_policy" "this" { count = var.create && var.create_policy ? 1 : 0 + region = var.region + secret_arn = aws_secretsmanager_secret.this[0].arn policy = data.aws_iam_policy_document.this[0].json block_public_policy = var.block_public_policy @@ -92,6 +96,8 @@ resource "aws_secretsmanager_secret_policy" "this" { resource "aws_secretsmanager_secret_version" "this" { count = var.create && !(var.enable_rotation || var.ignore_secret_changes) ? 1 : 0 + region = var.region + secret_id = aws_secretsmanager_secret.this[0].id secret_string = var.create_random_password ? random_password.this[0].result : var.secret_string secret_binary = var.secret_binary @@ -101,6 +107,8 @@ resource "aws_secretsmanager_secret_version" "this" { resource "aws_secretsmanager_secret_version" "ignore_changes" { count = var.create && (var.enable_rotation || var.ignore_secret_changes) ? 1 : 0 + region = var.region + secret_id = aws_secretsmanager_secret.this[0].id secret_string = var.create_random_password ? random_password.this[0].result : var.secret_string secret_binary = var.secret_binary @@ -130,6 +138,8 @@ resource "random_password" "this" { resource "aws_secretsmanager_secret_rotation" "this" { count = var.create && var.enable_rotation ? 1 : 0 + region = var.region + rotation_lambda_arn = var.rotation_lambda_arn dynamic "rotation_rules" { diff --git a/outputs.tf b/outputs.tf index 2f5df47..9bfcc7d 100644 --- a/outputs.tf +++ b/outputs.tf @@ -34,6 +34,11 @@ output "secret_binary" { value = try(aws_secretsmanager_secret_version.this[0].secret_binary, aws_secretsmanager_secret_version.ignore_changes[0].secret_binary, null) } +output "secret_region" { + description = "The region of the secret" + value = try(aws_secretsmanager_secret.this[0].region, null) +} + ################################################################################ # Version ################################################################################ diff --git a/variables.tf b/variables.tf index b4b915a..1271a50 100644 --- a/variables.tf +++ b/variables.tf @@ -4,6 +4,12 @@ variable "create" { default = true } +variable "region" { + description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration" + type = string + default = null +} + variable "tags" { description = "A map of tags to add to all resources" type = map(string) diff --git a/versions.tf b/versions.tf index d7b00bc..9740e49 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.0" + version = ">= 6.0" } random = { source = "hashicorp/random" diff --git a/wrappers/main.tf b/wrappers/main.tf index ef2db77..5c3e7f7 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -19,6 +19,7 @@ module "wrapper" { random_password_length = try(each.value.random_password_length, var.defaults.random_password_length, 32) random_password_override_special = try(each.value.random_password_override_special, var.defaults.random_password_override_special, "!@#$%&*()-_=+[]{}<>:?") recovery_window_in_days = try(each.value.recovery_window_in_days, var.defaults.recovery_window_in_days, null) + region = try(each.value.region, var.defaults.region, null) replica = try(each.value.replica, var.defaults.replica, {}) rotation_lambda_arn = try(each.value.rotation_lambda_arn, var.defaults.rotation_lambda_arn, "") rotation_rules = try(each.value.rotation_rules, var.defaults.rotation_rules, {}) diff --git a/wrappers/versions.tf b/wrappers/versions.tf index d7b00bc..9740e49 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.0" + version = ">= 6.0" } random = { source = "hashicorp/random" From 8c83dc4f95c974d10b37082604e69e9c888da1a6 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Tue, 5 Aug 2025 11:36:28 -0500 Subject: [PATCH 2/5] fix: Updates for ephemeral/write-only arguments --- .pre-commit-config.yaml | 2 +- README.md | 21 ++++----- examples/complete/README.md | 6 +-- examples/complete/main.tf | 44 ++++++++----------- examples/complete/versions.tf | 6 ++- main.tf | 67 ++++++++++++++-------------- variables.tf | 82 +++++++++++++++++++++++------------ versions.tf | 6 +-- wrappers/main.tf | 50 ++++++++++----------- wrappers/versions.tf | 6 +-- 10 files changed, 151 insertions(+), 139 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e4e7da..b784816 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.96.1 + rev: v1.99.5 hooks: - id: terraform_fmt - id: terraform_wrapper_module_for_each diff --git a/README.md b/README.md index 2ead664..d481692 100644 --- a/README.md +++ b/README.md @@ -123,16 +123,14 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | +| [terraform](#requirement\_terraform) | >= 1.11 | | [aws](#requirement\_aws) | >= 6.0 | -| [random](#requirement\_random) | >= 3.0 | ## Providers | Name | Version | |------|---------| | [aws](#provider\_aws) | >= 6.0 | -| [random](#provider\_random) | >= 3.0 | ## Modules @@ -147,7 +145,6 @@ No modules. | [aws_secretsmanager_secret_rotation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_rotation) | resource | | [aws_secretsmanager_secret_version.ignore_changes](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource | | [aws_secretsmanager_secret_version.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource | -| [random_password.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | | [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | ## Inputs @@ -157,7 +154,6 @@ No modules. | [block\_public\_policy](#input\_block\_public\_policy) | Makes an optional API call to Zelkova to validate the Resource Policy to prevent broad access to your secret | `bool` | `null` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_policy](#input\_create\_policy) | Determines whether a policy will be created | `bool` | `false` | no | -| [create\_random\_password](#input\_create\_random\_password) | Determines whether a random password will be generated | `bool` | `false` | no | | [description](#input\_description) | A description of the secret | `string` | `null` | no | | [enable\_rotation](#input\_enable\_rotation) | Determines whether secret rotation is enabled | `bool` | `false` | no | | [force\_overwrite\_replica\_secret](#input\_force\_overwrite\_replica\_secret) | Accepts boolean value to specify whether to overwrite a secret with the same name in the destination Region | `bool` | `null` | no | @@ -166,16 +162,17 @@ No modules. | [name](#input\_name) | Friendly name of the new secret. The secret name can consist of uppercase letters, lowercase letters, digits, and any of the following characters: `/_+=.@-` | `string` | `null` | no | | [name\_prefix](#input\_name\_prefix) | Creates a unique name beginning with the specified prefix | `string` | `null` | no | | [override\_policy\_documents](#input\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no | -| [policy\_statements](#input\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `map(any)` | `{}` | no | -| [random\_password\_length](#input\_random\_password\_length) | The length of the generated random password | `number` | `32` | no | -| [random\_password\_override\_special](#input\_random\_password\_override\_special) | Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument | `string` | `"!@#$%&*()-_=+[]{}<>:?"` | no | +| [policy\_statements](#input\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | | [recovery\_window\_in\_days](#input\_recovery\_window\_in\_days) | Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be `0` to force deletion without recovery or range from `7` to `30` days. The default value is `30` | `number` | `null` | no | | [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no | -| [replica](#input\_replica) | Configuration block to support secret replication | `map(any)` | `{}` | no | +| [replica](#input\_replica) | Configuration block to support secret replication |
map(object({
kms_key_id = optional(string)
region = optional(string) # will default to the key name
}))
| `null` | no | +| [rotate\_immediately](#input\_rotate\_immediately) | Specifies whether to rotate the secret immediately or wait until the next scheduled rotation window. The rotation schedule is defined in `rotation_rules` | `bool` | `null` | no | | [rotation\_lambda\_arn](#input\_rotation\_lambda\_arn) | Specifies the ARN of the Lambda function that can rotate the secret | `string` | `""` | no | -| [rotation\_rules](#input\_rotation\_rules) | A structure that defines the rotation configuration for this secret | `map(any)` | `{}` | no | -| [secret\_binary](#input\_secret\_binary) | Specifies binary data that you want to encrypt and store in this version of the secret. This is required if `secret_string` is not set. Needs to be encoded to base64 | `string` | `null` | no | -| [secret\_string](#input\_secret\_string) | Specifies text data that you want to encrypt and store in this version of the secret. This is required if `secret_binary` is not set | `string` | `null` | no | +| [rotation\_rules](#input\_rotation\_rules) | A structure that defines the rotation configuration for this secret |
object({
automatically_after_days = optional(number)
duration = optional(string)
schedule_expression = optional(string)
})
| `null` | no | +| [secret\_binary](#input\_secret\_binary) | Specifies binary data that you want to encrypt and store in this version of the secret. This is required if `secret_string` or `secret_string_wo` is not set. Needs to be encoded to base64 | `string` | `null` | no | +| [secret\_string](#input\_secret\_string) | Specifies text data that you want to encrypt and store in this version of the secret. This is required if `secret_binary` or `secret_string_wo` is not set | `string` | `null` | no | +| [secret\_string\_wo](#input\_secret\_string\_wo) | Specifies text data that you want to encrypt and store in this version of the secret. This is required if `secret_binary` or `secret_string` is not set | `string` | `null` | no | +| [secret\_string\_wo\_version](#input\_secret\_string\_wo\_version) | Used together with `secret_string_wo` to trigger an update. Increment this value when an update to `secret_string_wo` is required | `string` | `null` | no | | [source\_policy\_documents](#input\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements must have unique `sid`s | `list(string)` | `[]` | no | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | | [version\_stages](#input\_version\_stages) | Specifies a list of staging labels that are attached to this version of the secret. A staging label must be unique to a single version of the secret | `list(string)` | `null` | no | diff --git a/examples/complete/README.md b/examples/complete/README.md index bdc0c99..24672fb 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -28,8 +28,9 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | +| [terraform](#requirement\_terraform) | >= 1.11 | | [aws](#requirement\_aws) | >= 6.0 | +| [random](#requirement\_random) | >= 3.7 | ## Providers @@ -41,9 +42,8 @@ Note that this example may create resources which will incur monetary charges on | Name | Source | Version | |------|--------|---------| -| [lambda](#module\_lambda) | terraform-aws-modules/lambda/aws | ~> 6.0 | +| [lambda](#module\_lambda) | terraform-aws-modules/lambda/aws | ~> 8.0 | | [secrets\_manager](#module\_secrets\_manager) | ../.. | n/a | -| [secrets\_manager\_another\_region](#module\_secrets\_manager\_another\_region) | ../.. | n/a | | [secrets\_manager\_disabled](#module\_secrets\_manager\_disabled) | ../.. | n/a | | [secrets\_manager\_rotate](#module\_secrets\_manager\_rotate) | ../.. | n/a | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 58a908b..8f96fd7 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -38,8 +38,8 @@ module "secrets_manager" { # Policy create_policy = true block_public_policy = true - policy_statements = { - read = { + policy_statements = [ + { sid = "AllowAccountRead" principals = [{ type = "AWS" @@ -48,12 +48,11 @@ module "secrets_manager" { actions = ["secretsmanager:GetSecretValue"] resources = ["*"] } - } + ] # Version - create_random_password = true - random_password_length = 64 - random_password_override_special = "!@#$%^&*()_+" + secret_string_wo = ephemeral.random_password.password.result + secret_string_wo_version = 1 tags = local.tags } @@ -69,8 +68,8 @@ module "secrets_manager_rotate" { # Policy create_policy = true block_public_policy = true - policy_statements = { - lambda = { + policy_statements = [ + { sid = "LambdaReadWrite" principals = [{ type = "AWS" @@ -83,8 +82,8 @@ module "secrets_manager_rotate" { "secretsmanager:UpdateSecretVersionStage", ] resources = ["*"] - } - account = { + }, + { sid = "AccountDescribe" principals = [{ type = "AWS" @@ -93,7 +92,7 @@ module "secrets_manager_rotate" { actions = ["secretsmanager:DescribeSecret"] resources = ["*"] } - } + ] # Version ignore_secret_changes = true @@ -101,7 +100,7 @@ module "secrets_manager_rotate" { engine = "mariadb", host = "mydb.cluster-123456789012.us-east-1.rds.amazonaws.com", username = "Bill", - password = "ThisIsMySuperSecretString12356!" + password = "ThisIsMySuperSecretString12356!", dbname = "mydb", port = 3306 }) @@ -123,21 +122,16 @@ module "secrets_manager_disabled" { create = false } -module "secrets_manager_another_region" { - source = "../.." - - region = "us-east-1" - name_prefix = local.name - - create_random_password = true - - tags = local.tags -} - ################################################################################ # Supporting Resources ################################################################################ +ephemeral "random_password" "password" { + length = 16 + special = true + override_special = "!#$%&*()-_=+[]{}<>:?" +} + # https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-required-permissions-function.html data "aws_iam_policy_document" "this" { statement { @@ -163,13 +157,13 @@ data "aws_iam_policy_document" "this" { module "lambda" { source = "terraform-aws-modules/lambda/aws" - version = "~> 6.0" + version = "~> 8.0" function_name = local.name description = "Example Secrets Manager secret rotation lambda function" handler = "function.lambda_handler" - runtime = "python3.10" + runtime = "python3.12" timeout = 60 memory_size = 512 source_path = "${path.module}/function.py" diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index aaf26b8..23d9fe0 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -1,10 +1,14 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.11" required_providers { aws = { source = "hashicorp/aws" version = ">= 6.0" } + random = { + source = "hashicorp/random" + version = ">= 3.7" + } } } diff --git a/main.tf b/main.tf index 900c3dd..7062c4d 100644 --- a/main.tf +++ b/main.tf @@ -16,11 +16,11 @@ resource "aws_secretsmanager_secret" "this" { recovery_window_in_days = var.recovery_window_in_days dynamic "replica" { - for_each = var.replica + for_each = var.replica != null ? var.replica : {} content { - kms_key_id = try(replica.value.kms_key_id, null) - region = try(replica.value.region, replica.key) + kms_key_id = replica.value.kms_key_id + region = coalesce(replica.value.region, replica.key) } } @@ -38,18 +38,18 @@ data "aws_iam_policy_document" "this" { override_policy_documents = var.override_policy_documents dynamic "statement" { - for_each = var.policy_statements + for_each = var.policy_statements != null ? var.policy_statements : [] content { - sid = try(statement.value.sid, null) - actions = try(statement.value.actions, null) - not_actions = try(statement.value.not_actions, null) - effect = try(statement.value.effect, null) - resources = try(statement.value.resources, null) - not_resources = try(statement.value.not_resources, null) + sid = statement.value.sid + actions = statement.value.actions + not_actions = statement.value.not_actions + effect = statement.value.effect + resources = statement.value.resources + not_resources = statement.value.not_resources dynamic "principals" { - for_each = try(statement.value.principals, []) + for_each = statement.value.principals != null ? statement.value.principals : [] content { type = principals.value.type @@ -58,7 +58,7 @@ data "aws_iam_policy_document" "this" { } dynamic "not_principals" { - for_each = try(statement.value.not_principals, []) + for_each = statement.value.not_principals != null ? statement.value.not_principals : [] content { type = not_principals.value.type @@ -67,7 +67,7 @@ data "aws_iam_policy_document" "this" { } dynamic "condition" { - for_each = try(statement.value.conditions, []) + for_each = statement.value.condition != null ? statement.value.condition : [] content { test = condition.value.test @@ -84,9 +84,9 @@ resource "aws_secretsmanager_secret_policy" "this" { region = var.region - secret_arn = aws_secretsmanager_secret.this[0].arn - policy = data.aws_iam_policy_document.this[0].json block_public_policy = var.block_public_policy + policy = data.aws_iam_policy_document.this[0].json + secret_arn = aws_secretsmanager_secret.this[0].arn } ################################################################################ @@ -98,10 +98,12 @@ resource "aws_secretsmanager_secret_version" "this" { region = var.region - secret_id = aws_secretsmanager_secret.this[0].id - secret_string = var.create_random_password ? random_password.this[0].result : var.secret_string - secret_binary = var.secret_binary - version_stages = var.version_stages + secret_id = aws_secretsmanager_secret.this[0].id + secret_binary = var.secret_binary + secret_string = var.secret_string + secret_string_wo = var.secret_string_wo + secret_string_wo_version = var.secret_string_wo_version + version_stages = var.version_stages } resource "aws_secretsmanager_secret_version" "ignore_changes" { @@ -109,10 +111,12 @@ resource "aws_secretsmanager_secret_version" "ignore_changes" { region = var.region - secret_id = aws_secretsmanager_secret.this[0].id - secret_string = var.create_random_password ? random_password.this[0].result : var.secret_string - secret_binary = var.secret_binary - version_stages = var.version_stages + secret_id = aws_secretsmanager_secret.this[0].id + secret_binary = var.secret_binary + secret_string = var.secret_string + secret_string_wo = var.secret_string_wo + secret_string_wo_version = var.secret_string_wo_version + version_stages = var.version_stages lifecycle { ignore_changes = [ @@ -123,14 +127,6 @@ resource "aws_secretsmanager_secret_version" "ignore_changes" { } } -resource "random_password" "this" { - count = var.create && var.create_random_password ? 1 : 0 - - length = var.random_password_length - special = true - override_special = var.random_password_override_special -} - ################################################################################ # Rotation ################################################################################ @@ -140,15 +136,16 @@ resource "aws_secretsmanager_secret_rotation" "this" { region = var.region + rotate_immediately = var.rotate_immediately rotation_lambda_arn = var.rotation_lambda_arn dynamic "rotation_rules" { - for_each = [var.rotation_rules] + for_each = var.rotation_rules != null ? [var.rotation_rules] : [] content { - automatically_after_days = try(rotation_rules.value.automatically_after_days, null) - duration = try(rotation_rules.value.duration, null) - schedule_expression = try(rotation_rules.value.schedule_expression, null) + automatically_after_days = rotation_rules.value.automatically_after_days + duration = rotation_rules.value.duration + schedule_expression = rotation_rules.value.schedule_expression } } diff --git a/variables.tf b/variables.tf index 1271a50..0e1d15d 100644 --- a/variables.tf +++ b/variables.tf @@ -58,8 +58,11 @@ variable "recovery_window_in_days" { variable "replica" { description = "Configuration block to support secret replication" - type = map(any) - default = {} + type = map(object({ + kms_key_id = optional(string) + region = optional(string) # will default to the key name + })) + default = null } ################################################################################ @@ -86,8 +89,28 @@ variable "override_policy_documents" { variable "policy_statements" { description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage" - type = map(any) - default = {} + type = list(object({ + sid = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + effect = optional(string) + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + condition = optional(list(object({ + test = string + values = list(string) + variable = string + }))) + })) + default = null } variable "block_public_policy" { @@ -106,40 +129,35 @@ variable "ignore_secret_changes" { default = false } -variable "secret_string" { - description = "Specifies text data that you want to encrypt and store in this version of the secret. This is required if `secret_binary` is not set" +variable "secret_binary" { + description = "Specifies binary data that you want to encrypt and store in this version of the secret. This is required if `secret_string` or `secret_string_wo` is not set. Needs to be encoded to base64" type = string default = null } -variable "secret_binary" { - description = "Specifies binary data that you want to encrypt and store in this version of the secret. This is required if `secret_string` is not set. Needs to be encoded to base64" +variable "secret_string" { + description = "Specifies text data that you want to encrypt and store in this version of the secret. This is required if `secret_binary` or `secret_string_wo` is not set" type = string default = null } -variable "version_stages" { - description = "Specifies a list of staging labels that are attached to this version of the secret. A staging label must be unique to a single version of the secret" - type = list(string) +variable "secret_string_wo" { + description = "Specifies text data that you want to encrypt and store in this version of the secret. This is required if `secret_binary` or `secret_string` is not set" + type = string default = null + ephemeral = true } -variable "create_random_password" { - description = "Determines whether a random password will be generated" - type = bool - default = false -} - -variable "random_password_length" { - description = "The length of the generated random password" - type = number - default = 32 +variable "secret_string_wo_version" { + description = "Used together with `secret_string_wo` to trigger an update. Increment this value when an update to `secret_string_wo` is required" + type = string + default = null } -variable "random_password_override_special" { - description = "Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument" - type = string - default = "!@#$%&*()-_=+[]{}<>:?" +variable "version_stages" { + description = "Specifies a list of staging labels that are attached to this version of the secret. A staging label must be unique to a single version of the secret" + type = list(string) + default = null } ################################################################################ @@ -152,6 +170,12 @@ variable "enable_rotation" { default = false } +variable "rotate_immediately" { + description = "Specifies whether to rotate the secret immediately or wait until the next scheduled rotation window. The rotation schedule is defined in `rotation_rules`" + type = bool + default = null +} + variable "rotation_lambda_arn" { description = "Specifies the ARN of the Lambda function that can rotate the secret" type = string @@ -160,6 +184,10 @@ variable "rotation_lambda_arn" { variable "rotation_rules" { description = "A structure that defines the rotation configuration for this secret" - type = map(any) - default = {} + type = object({ + automatically_after_days = optional(number) + duration = optional(string) + schedule_expression = optional(string) + }) + default = null } diff --git a/versions.tf b/versions.tf index 9740e49..10c8edc 100644 --- a/versions.tf +++ b/versions.tf @@ -1,14 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.11" required_providers { aws = { source = "hashicorp/aws" version = ">= 6.0" } - random = { - source = "hashicorp/random" - version = ">= 3.0" - } } } diff --git a/wrappers/main.tf b/wrappers/main.tf index 5c3e7f7..63cd864 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -3,29 +3,29 @@ module "wrapper" { for_each = var.items - block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, null) - create = try(each.value.create, var.defaults.create, true) - create_policy = try(each.value.create_policy, var.defaults.create_policy, false) - create_random_password = try(each.value.create_random_password, var.defaults.create_random_password, false) - description = try(each.value.description, var.defaults.description, null) - enable_rotation = try(each.value.enable_rotation, var.defaults.enable_rotation, false) - force_overwrite_replica_secret = try(each.value.force_overwrite_replica_secret, var.defaults.force_overwrite_replica_secret, null) - ignore_secret_changes = try(each.value.ignore_secret_changes, var.defaults.ignore_secret_changes, false) - kms_key_id = try(each.value.kms_key_id, var.defaults.kms_key_id, null) - name = try(each.value.name, var.defaults.name, null) - name_prefix = try(each.value.name_prefix, var.defaults.name_prefix, null) - override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) - policy_statements = try(each.value.policy_statements, var.defaults.policy_statements, {}) - random_password_length = try(each.value.random_password_length, var.defaults.random_password_length, 32) - random_password_override_special = try(each.value.random_password_override_special, var.defaults.random_password_override_special, "!@#$%&*()-_=+[]{}<>:?") - recovery_window_in_days = try(each.value.recovery_window_in_days, var.defaults.recovery_window_in_days, null) - region = try(each.value.region, var.defaults.region, null) - replica = try(each.value.replica, var.defaults.replica, {}) - rotation_lambda_arn = try(each.value.rotation_lambda_arn, var.defaults.rotation_lambda_arn, "") - rotation_rules = try(each.value.rotation_rules, var.defaults.rotation_rules, {}) - secret_binary = try(each.value.secret_binary, var.defaults.secret_binary, null) - secret_string = try(each.value.secret_string, var.defaults.secret_string, null) - source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) - tags = try(each.value.tags, var.defaults.tags, {}) - version_stages = try(each.value.version_stages, var.defaults.version_stages, null) + block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, null) + create = try(each.value.create, var.defaults.create, true) + create_policy = try(each.value.create_policy, var.defaults.create_policy, false) + description = try(each.value.description, var.defaults.description, null) + enable_rotation = try(each.value.enable_rotation, var.defaults.enable_rotation, false) + force_overwrite_replica_secret = try(each.value.force_overwrite_replica_secret, var.defaults.force_overwrite_replica_secret, null) + ignore_secret_changes = try(each.value.ignore_secret_changes, var.defaults.ignore_secret_changes, false) + kms_key_id = try(each.value.kms_key_id, var.defaults.kms_key_id, null) + name = try(each.value.name, var.defaults.name, null) + name_prefix = try(each.value.name_prefix, var.defaults.name_prefix, null) + override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) + policy_statements = try(each.value.policy_statements, var.defaults.policy_statements, null) + recovery_window_in_days = try(each.value.recovery_window_in_days, var.defaults.recovery_window_in_days, null) + region = try(each.value.region, var.defaults.region, null) + replica = try(each.value.replica, var.defaults.replica, null) + rotate_immediately = try(each.value.rotate_immediately, var.defaults.rotate_immediately, null) + rotation_lambda_arn = try(each.value.rotation_lambda_arn, var.defaults.rotation_lambda_arn, "") + rotation_rules = try(each.value.rotation_rules, var.defaults.rotation_rules, null) + secret_binary = try(each.value.secret_binary, var.defaults.secret_binary, null) + secret_string = try(each.value.secret_string, var.defaults.secret_string, null) + secret_string_wo = try(each.value.secret_string_wo, var.defaults.secret_string_wo, null) + secret_string_wo_version = try(each.value.secret_string_wo_version, var.defaults.secret_string_wo_version, null) + source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) + tags = try(each.value.tags, var.defaults.tags, {}) + version_stages = try(each.value.version_stages, var.defaults.version_stages, null) } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 9740e49..10c8edc 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -1,14 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.11" required_providers { aws = { source = "hashicorp/aws" version = ">= 6.0" } - random = { - source = "hashicorp/random" - version = ">= 3.0" - } } } From 2b944d0f23c04081fd4bf232934ce76d05c65e10 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Tue, 5 Aug 2025 11:43:03 -0500 Subject: [PATCH 3/5] chore: Remove region output --- README.md | 1 - outputs.tf | 5 ----- 2 files changed, 6 deletions(-) diff --git a/README.md b/README.md index d481692..ccc4c13 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,6 @@ No modules. | [secret\_binary](#output\_secret\_binary) | The secret binary | | [secret\_id](#output\_secret\_id) | The ID of the secret | | [secret\_name](#output\_secret\_name) | The name of the secret | -| [secret\_region](#output\_secret\_region) | The region of the secret | | [secret\_replica](#output\_secret\_replica) | Attributes of the replica created | | [secret\_string](#output\_secret\_string) | The secret string | | [secret\_version\_id](#output\_secret\_version\_id) | The unique identifier of the version of the secret | diff --git a/outputs.tf b/outputs.tf index 9bfcc7d..2f5df47 100644 --- a/outputs.tf +++ b/outputs.tf @@ -34,11 +34,6 @@ output "secret_binary" { value = try(aws_secretsmanager_secret_version.this[0].secret_binary, aws_secretsmanager_secret_version.ignore_changes[0].secret_binary, null) } -output "secret_region" { - description = "The region of the secret" - value = try(aws_secretsmanager_secret.this[0].region, null) -} - ################################################################################ # Version ################################################################################ From 9682e45340bb05af8ddcff6abaf077219e45574b Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 8 Aug 2025 09:28:35 -0500 Subject: [PATCH 4/5] feat: Re-add support for random passwords using ephemeral random password --- .pre-commit-config.yaml | 2 +- README.md | 4 +++ examples/complete/main.tf | 13 +++------- main.tf | 16 +++++++++--- variables.tf | 18 +++++++++++++ versions.tf | 4 +++ wrappers/main.tf | 53 +++++++++++++++++++++------------------ wrappers/versions.tf | 4 +++ 8 files changed, 75 insertions(+), 39 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b784816..7f8a62b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.99.5 + rev: v1.100.0 hooks: - id: terraform_fmt - id: terraform_wrapper_module_for_each diff --git a/README.md b/README.md index ccc4c13..b2bd56f 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module |------|---------| | [terraform](#requirement\_terraform) | >= 1.11 | | [aws](#requirement\_aws) | >= 6.0 | +| [random](#requirement\_random) | >= 3.7 | ## Providers @@ -154,6 +155,7 @@ No modules. | [block\_public\_policy](#input\_block\_public\_policy) | Makes an optional API call to Zelkova to validate the Resource Policy to prevent broad access to your secret | `bool` | `null` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_policy](#input\_create\_policy) | Determines whether a policy will be created | `bool` | `false` | no | +| [create\_random\_password](#input\_create\_random\_password) | Determines whether an ephemeral random password will be generated for `secret_string_wo` | `bool` | `false` | no | | [description](#input\_description) | A description of the secret | `string` | `null` | no | | [enable\_rotation](#input\_enable\_rotation) | Determines whether secret rotation is enabled | `bool` | `false` | no | | [force\_overwrite\_replica\_secret](#input\_force\_overwrite\_replica\_secret) | Accepts boolean value to specify whether to overwrite a secret with the same name in the destination Region | `bool` | `null` | no | @@ -163,6 +165,8 @@ No modules. | [name\_prefix](#input\_name\_prefix) | Creates a unique name beginning with the specified prefix | `string` | `null` | no | | [override\_policy\_documents](#input\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no | | [policy\_statements](#input\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | +| [random\_password\_length](#input\_random\_password\_length) | The length of the generated random password | `number` | `32` | no | +| [random\_password\_override\_special](#input\_random\_password\_override\_special) | Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument | `string` | `"!@#$%&*()-_=+[]{}<>:?"` | no | | [recovery\_window\_in\_days](#input\_recovery\_window\_in\_days) | Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be `0` to force deletion without recovery or range from `7` to `30` days. The default value is `30` | `number` | `null` | no | | [region](#input\_region) | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | `string` | `null` | no | | [replica](#input\_replica) | Configuration block to support secret replication |
map(object({
kms_key_id = optional(string)
region = optional(string) # will default to the key name
}))
| `null` | no | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 8f96fd7..ee6ceb1 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -51,8 +51,9 @@ module "secrets_manager" { ] # Version - secret_string_wo = ephemeral.random_password.password.result - secret_string_wo_version = 1 + create_random_password = true + random_password_length = 64 + random_password_override_special = "!@#$%^&*()_+" tags = local.tags } @@ -126,12 +127,6 @@ module "secrets_manager_disabled" { # Supporting Resources ################################################################################ -ephemeral "random_password" "password" { - length = 16 - special = true - override_special = "!#$%&*()-_=+[]{}<>:?" -} - # https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-required-permissions-function.html data "aws_iam_policy_document" "this" { statement { @@ -163,7 +158,7 @@ module "lambda" { description = "Example Secrets Manager secret rotation lambda function" handler = "function.lambda_handler" - runtime = "python3.12" + runtime = "python3.13" timeout = 60 memory_size = 512 source_path = "${path.module}/function.py" diff --git a/main.tf b/main.tf index 7062c4d..e8888ed 100644 --- a/main.tf +++ b/main.tf @@ -101,8 +101,8 @@ resource "aws_secretsmanager_secret_version" "this" { secret_id = aws_secretsmanager_secret.this[0].id secret_binary = var.secret_binary secret_string = var.secret_string - secret_string_wo = var.secret_string_wo - secret_string_wo_version = var.secret_string_wo_version + secret_string_wo = var.create_random_password ? ephemeral.random_password.this[0].result : var.secret_string_wo + secret_string_wo_version = var.create_random_password ? coalesce(var.secret_string_wo_version, 0) : var.secret_string_wo_version version_stages = var.version_stages } @@ -114,8 +114,8 @@ resource "aws_secretsmanager_secret_version" "ignore_changes" { secret_id = aws_secretsmanager_secret.this[0].id secret_binary = var.secret_binary secret_string = var.secret_string - secret_string_wo = var.secret_string_wo - secret_string_wo_version = var.secret_string_wo_version + secret_string_wo = var.create_random_password ? ephemeral.random_password.this[0].result : var.secret_string_wo + secret_string_wo_version = var.create_random_password ? coalesce(var.secret_string_wo_version, 0) : var.secret_string_wo_version version_stages = var.version_stages lifecycle { @@ -127,6 +127,14 @@ resource "aws_secretsmanager_secret_version" "ignore_changes" { } } +ephemeral "random_password" "this" { + count = var.create && var.create_random_password ? 1 : 0 + + length = var.random_password_length + special = true + override_special = var.random_password_override_special +} + ################################################################################ # Rotation ################################################################################ diff --git a/variables.tf b/variables.tf index 0e1d15d..89c5c70 100644 --- a/variables.tf +++ b/variables.tf @@ -160,6 +160,24 @@ variable "version_stages" { default = null } +variable "create_random_password" { + description = "Determines whether an ephemeral random password will be generated for `secret_string_wo`" + type = bool + default = false +} + +variable "random_password_length" { + description = "The length of the generated random password" + type = number + default = 32 +} + +variable "random_password_override_special" { + description = "Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument" + type = string + default = "!@#$%&*()-_=+[]{}<>:?" +} + ################################################################################ # Rotation ################################################################################ diff --git a/versions.tf b/versions.tf index 10c8edc..23d9fe0 100644 --- a/versions.tf +++ b/versions.tf @@ -6,5 +6,9 @@ terraform { source = "hashicorp/aws" version = ">= 6.0" } + random = { + source = "hashicorp/random" + version = ">= 3.7" + } } } diff --git a/wrappers/main.tf b/wrappers/main.tf index 63cd864..42612fa 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -3,29 +3,32 @@ module "wrapper" { for_each = var.items - block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, null) - create = try(each.value.create, var.defaults.create, true) - create_policy = try(each.value.create_policy, var.defaults.create_policy, false) - description = try(each.value.description, var.defaults.description, null) - enable_rotation = try(each.value.enable_rotation, var.defaults.enable_rotation, false) - force_overwrite_replica_secret = try(each.value.force_overwrite_replica_secret, var.defaults.force_overwrite_replica_secret, null) - ignore_secret_changes = try(each.value.ignore_secret_changes, var.defaults.ignore_secret_changes, false) - kms_key_id = try(each.value.kms_key_id, var.defaults.kms_key_id, null) - name = try(each.value.name, var.defaults.name, null) - name_prefix = try(each.value.name_prefix, var.defaults.name_prefix, null) - override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) - policy_statements = try(each.value.policy_statements, var.defaults.policy_statements, null) - recovery_window_in_days = try(each.value.recovery_window_in_days, var.defaults.recovery_window_in_days, null) - region = try(each.value.region, var.defaults.region, null) - replica = try(each.value.replica, var.defaults.replica, null) - rotate_immediately = try(each.value.rotate_immediately, var.defaults.rotate_immediately, null) - rotation_lambda_arn = try(each.value.rotation_lambda_arn, var.defaults.rotation_lambda_arn, "") - rotation_rules = try(each.value.rotation_rules, var.defaults.rotation_rules, null) - secret_binary = try(each.value.secret_binary, var.defaults.secret_binary, null) - secret_string = try(each.value.secret_string, var.defaults.secret_string, null) - secret_string_wo = try(each.value.secret_string_wo, var.defaults.secret_string_wo, null) - secret_string_wo_version = try(each.value.secret_string_wo_version, var.defaults.secret_string_wo_version, null) - source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) - tags = try(each.value.tags, var.defaults.tags, {}) - version_stages = try(each.value.version_stages, var.defaults.version_stages, null) + block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, null) + create = try(each.value.create, var.defaults.create, true) + create_policy = try(each.value.create_policy, var.defaults.create_policy, false) + create_random_password = try(each.value.create_random_password, var.defaults.create_random_password, false) + description = try(each.value.description, var.defaults.description, null) + enable_rotation = try(each.value.enable_rotation, var.defaults.enable_rotation, false) + force_overwrite_replica_secret = try(each.value.force_overwrite_replica_secret, var.defaults.force_overwrite_replica_secret, null) + ignore_secret_changes = try(each.value.ignore_secret_changes, var.defaults.ignore_secret_changes, false) + kms_key_id = try(each.value.kms_key_id, var.defaults.kms_key_id, null) + name = try(each.value.name, var.defaults.name, null) + name_prefix = try(each.value.name_prefix, var.defaults.name_prefix, null) + override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) + policy_statements = try(each.value.policy_statements, var.defaults.policy_statements, null) + random_password_length = try(each.value.random_password_length, var.defaults.random_password_length, 32) + random_password_override_special = try(each.value.random_password_override_special, var.defaults.random_password_override_special, "!@#$%&*()-_=+[]{}<>:?") + recovery_window_in_days = try(each.value.recovery_window_in_days, var.defaults.recovery_window_in_days, null) + region = try(each.value.region, var.defaults.region, null) + replica = try(each.value.replica, var.defaults.replica, null) + rotate_immediately = try(each.value.rotate_immediately, var.defaults.rotate_immediately, null) + rotation_lambda_arn = try(each.value.rotation_lambda_arn, var.defaults.rotation_lambda_arn, "") + rotation_rules = try(each.value.rotation_rules, var.defaults.rotation_rules, null) + secret_binary = try(each.value.secret_binary, var.defaults.secret_binary, null) + secret_string = try(each.value.secret_string, var.defaults.secret_string, null) + secret_string_wo = try(each.value.secret_string_wo, var.defaults.secret_string_wo, null) + secret_string_wo_version = try(each.value.secret_string_wo_version, var.defaults.secret_string_wo_version, null) + source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) + tags = try(each.value.tags, var.defaults.tags, {}) + version_stages = try(each.value.version_stages, var.defaults.version_stages, null) } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 10c8edc..23d9fe0 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -6,5 +6,9 @@ terraform { source = "hashicorp/aws" version = ">= 6.0" } + random = { + source = "hashicorp/random" + version = ">= 3.7" + } } } From f5ac1405b4dc9bc56cc8af36eb08abe45e3db2f2 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 8 Aug 2025 09:48:21 -0500 Subject: [PATCH 5/5] fix: Revert `policy_statements` back to `map()` --- README.md | 2 +- examples/complete/main.tf | 16 ++++++++-------- main.tf | 2 +- variables.tf | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b2bd56f..d2f92cf 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ No modules. | [name](#input\_name) | Friendly name of the new secret. The secret name can consist of uppercase letters, lowercase letters, digits, and any of the following characters: `/_+=.@-` | `string` | `null` | no | | [name\_prefix](#input\_name\_prefix) | Creates a unique name beginning with the specified prefix | `string` | `null` | no | | [override\_policy\_documents](#input\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no | -| [policy\_statements](#input\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | +| [policy\_statements](#input\_policy\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
map(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | | [random\_password\_length](#input\_random\_password\_length) | The length of the generated random password | `number` | `32` | no | | [random\_password\_override\_special](#input\_random\_password\_override\_special) | Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument | `string` | `"!@#$%&*()-_=+[]{}<>:?"` | no | | [recovery\_window\_in\_days](#input\_recovery\_window\_in\_days) | Number of days that AWS Secrets Manager waits before it can delete the secret. This value can be `0` to force deletion without recovery or range from `7` to `30` days. The default value is `30` | `number` | `null` | no | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index ee6ceb1..8fef555 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -38,8 +38,8 @@ module "secrets_manager" { # Policy create_policy = true block_public_policy = true - policy_statements = [ - { + policy_statements = { + read = { sid = "AllowAccountRead" principals = [{ type = "AWS" @@ -48,7 +48,7 @@ module "secrets_manager" { actions = ["secretsmanager:GetSecretValue"] resources = ["*"] } - ] + } # Version create_random_password = true @@ -69,8 +69,8 @@ module "secrets_manager_rotate" { # Policy create_policy = true block_public_policy = true - policy_statements = [ - { + policy_statements = { + lambda = { sid = "LambdaReadWrite" principals = [{ type = "AWS" @@ -83,8 +83,8 @@ module "secrets_manager_rotate" { "secretsmanager:UpdateSecretVersionStage", ] resources = ["*"] - }, - { + } + account = { sid = "AccountDescribe" principals = [{ type = "AWS" @@ -93,7 +93,7 @@ module "secrets_manager_rotate" { actions = ["secretsmanager:DescribeSecret"] resources = ["*"] } - ] + } # Version ignore_secret_changes = true diff --git a/main.tf b/main.tf index e8888ed..deeff12 100644 --- a/main.tf +++ b/main.tf @@ -38,7 +38,7 @@ data "aws_iam_policy_document" "this" { override_policy_documents = var.override_policy_documents dynamic "statement" { - for_each = var.policy_statements != null ? var.policy_statements : [] + for_each = var.policy_statements != null ? var.policy_statements : {} content { sid = statement.value.sid diff --git a/variables.tf b/variables.tf index 89c5c70..510b0ad 100644 --- a/variables.tf +++ b/variables.tf @@ -89,7 +89,7 @@ variable "override_policy_documents" { variable "policy_statements" { description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage" - type = list(object({ + type = map(object({ sid = optional(string) actions = optional(list(string)) not_actions = optional(list(string))