From 928ed7381b98bf208e581ef0b513d142b2a3ccdd Mon Sep 17 00:00:00 2001 From: Samuel CHNIBER Date: Wed, 18 Jun 2025 22:28:55 +0200 Subject: [PATCH 1/8] feat: addition of enhanced region support --- examples/complete/main.tf | 266 +++++++++++++++++++++++++++++++-- examples/complete/outputs.tf | 277 +++++++++++++++++++++++++++++++++++ main.tf | 6 + outputs.tf | 5 + variables.tf | 6 + versions.tf | 2 +- wrappers/main.tf | 1 + wrappers/versions.tf | 2 +- 8 files changed, 550 insertions(+), 15 deletions(-) diff --git a/examples/complete/main.tf b/examples/complete/main.tf index d03c0bf..8d73bfb 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -4,6 +4,7 @@ provider "aws" { locals { region = "us-east-1" + replica_region = "eu-west-1" name = "kms-ex-${replace(basename(path.cwd), "_", "-")}" current_identity = data.aws_caller_identity.current.arn @@ -16,6 +17,9 @@ locals { data "aws_caller_identity" "current" {} data "aws_region" "current" {} +data "aws_region" "replica" { + region = local.region +} ################################################################################ # KMS Module @@ -57,7 +61,7 @@ module "kms_complete" { principals = [ { type = "Service" - identifiers = ["logs.${data.aws_region.current.name}.amazonaws.com"] + identifiers = ["logs.${data.aws_region.current.region}.amazonaws.com"] } ] @@ -103,6 +107,89 @@ module "kms_complete" { tags = local.tags } +module "kms_complete_other_region" { + source = "../.." + + deletion_window_in_days = 7 + description = "Complete key example showing various configurations available" + enable_key_rotation = false + is_enabled = true + key_usage = "ENCRYPT_DECRYPT" + region = local.replica_region + multi_region = false + + # Policy + enable_default_policy = true + key_owners = [local.current_identity] + key_administrators = [local.current_identity] + key_users = [local.current_identity] + key_service_users = [local.current_identity] + key_service_roles_for_autoscaling = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] + key_symmetric_encryption_users = [local.current_identity] + key_hmac_users = [local.current_identity] + key_asymmetric_public_encryption_users = [local.current_identity] + key_asymmetric_sign_verify_users = [local.current_identity] + key_statements = [ + { + sid = "CloudWatchLogs" + actions = [ + "kms:Encrypt*", + "kms:Decrypt*", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Describe*" + ] + resources = ["*"] + + principals = [ + { + type = "Service" + identifiers = ["logs.${data.aws_region.replica.region}.amazonaws.com"] + } + ] + + conditions = [ + { + test = "ArnLike" + variable = "kms:EncryptionContext:aws:logs:arn" + values = [ + "arn:aws:logs:${local.replica_region}:${data.aws_caller_identity.current.account_id}:log-group:*", + ] + } + ] + } + ] + + # Aliases + aliases = ["one-other", "foo/bar-other"] + computed_aliases = { + ex = { + # Sometimes you want to pass in an upstream attribute as the name and + # that conflicts with using `for_each over a `toset()` since the value is not + # known until after applying. Instead, we can use `computed_aliases` to work + # around this limitation + # Reference: https://github.com/hashicorp/terraform/issues/30937 + name = aws_iam_role.lambda.name + } + } + aliases_use_name_prefix = true + + # Grants + grants = { + lambda = { + grantee_principal = aws_iam_role.lambda.arn + operations = ["Encrypt", "Decrypt", "GenerateDataKey"] + constraints = { + encryption_context_equals = { + Department = "Finance" + } + } + } + } + + tags = local.tags +} + module "kms_external" { source = "../.." @@ -112,7 +199,22 @@ module "kms_external" { is_enabled = true key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" multi_region = false - valid_to = "2023-11-21T23:20:50Z" + valid_to = "2025-11-21T23:20:50Z" + + tags = local.tags +} + +module "kms_external_other_region" { + source = "../.." + + deletion_window_in_days = 7 + description = "External key example" + create_external = true + is_enabled = true + key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" + multi_region = false + valid_to = "2025-11-21T23:20:50Z" + region = local.replica_region tags = local.tags } @@ -139,18 +241,56 @@ module "kms_dnssec_signing" { tags = local.tags } +module "kms_dnssec_signing_other_region" { + source = "../.." + + description = "CMK for Route53 DNSSEC signing" + + key_usage = "SIGN_VERIFY" + customer_master_key_spec = "ECC_NIST_P256" + + enable_route53_dnssec = true + enable_key_rotation = false + route53_dnssec_sources = [ + { + accounts_ids = [data.aws_caller_identity.current.account_id] # can ommit if using current account ID which is default + hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value + } + ] + region = local.replica_region + + aliases = ["route53/dnssec-ex-other"] + + tags = local.tags +} + module "kms_default" { source = "../.." tags = local.tags } +module "kms_default_other_region" { + source = "../.." + + region = local.replica_region + + tags = local.tags +} + module "kms_disabled" { source = "../.." create = false } +module "kms_other_region_disabled" { + source = "../.." + + create = false + region = local.replica_region +} + ################################################################################ # Replica Key Example ################################################################################ @@ -170,11 +310,6 @@ module "kms_primary" { tags = local.tags } -provider "aws" { - region = "eu-west-1" - alias = "replica" -} - module "kms_replica" { source = "../.." @@ -214,11 +349,69 @@ module "kms_replica" { } } + region = local.replica_region + tags = local.tags +} + +module "kms_primary_other_region" { + source = "../.." + + deletion_window_in_days = 7 + description = "Primary key of replica key example" + enable_key_rotation = false + is_enabled = true + key_usage = "ENCRYPT_DECRYPT" + region = local.replica_region + multi_region = true + + aliases = ["primary-standard-other"] - providers = { - aws = aws.replica + tags = local.tags +} + +module "kms_replica_other_region" { + source = "../.." + + deletion_window_in_days = 7 + description = "Replica key example showing various configurations available" + create_replica = true + primary_key_arn = module.kms_primary_other_region.key_arn + enable_default_policy = true + + key_owners = [local.current_identity] + key_administrators = [local.current_identity] + key_users = [local.current_identity] + + # Aliases + aliases = ["replica-standard-other"] + computed_aliases = { + ex = { + # Sometimes you want to pass in an upstream attribute as the name and + # that conflicts with using `for_each over a `toset()` since the value is not + # known until after applying. Instead, we can use `computed_aliases` to work + # around this limitation + # Reference: https://github.com/hashicorp/terraform/issues/30937 + name = aws_iam_role.lambda.name + } } + + # Grants + grants = { + lambda = { + grantee_principal = aws_iam_role.lambda.arn + operations = ["Encrypt", "Decrypt", "GenerateDataKey"] + constraints = { + encryption_context_equals = { + Department = "Finance" + } + } + } + } + + region = local.region + + tags = local.tags } ################################################################################ @@ -234,7 +427,7 @@ module "kms_primary_external" { create_external = true key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" multi_region = true - valid_to = "2023-11-21T23:20:50Z" + valid_to = "2025-11-21T23:20:50Z" aliases = ["primary-external"] @@ -251,7 +444,7 @@ module "kms_replica_external" { # key material must be the same as the primary's key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" primary_external_key_arn = module.kms_primary_external.key_arn - valid_to = "2023-11-21T23:20:50Z" + valid_to = "2025-11-21T23:20:50Z" aliases = ["replica-external"] @@ -268,11 +461,58 @@ module "kms_replica_external" { } } + region = local.replica_region + + tags = local.tags +} + +module "kms_primary_external_other_region" { + source = "../.." + + deletion_window_in_days = 7 + description = "Primary external key of replica external key example" + is_enabled = true + create_external = true + key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" + region = local.replica_region + multi_region = true + valid_to = "2025-11-21T23:20:50Z" + + aliases = ["primary-external-other-region"] + tags = local.tags +} + +module "kms_replica_external_other_region" { + source = "../.." + + deletion_window_in_days = 7 + description = "Replica external key example showing various configurations available" + create_replica_external = true + is_enabled = true + # key material must be the same as the primary's + key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" + primary_external_key_arn = module.kms_primary_external_other_region.key_arn + valid_to = "2025-11-21T23:20:50Z" - providers = { - aws = aws.replica + aliases = ["replica-external-other-region"] + + # Grants + grants = { + lambda = { + grantee_principal = aws_iam_role.lambda.arn + operations = ["Encrypt", "Decrypt", "GenerateDataKey"] + constraints = { + encryption_context_equals = { + Department = "Finance" + } + } + } } + + region = local.region + + tags = local.tags } ################################################################################ diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index a2edbf6..88c841f 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -12,6 +12,11 @@ output "complete_key_id" { value = module.kms_complete.key_id } +output "complete_key_region" { + description = "The region for the key" + value = module.kms_complete.key_region +} + output "complete_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_complete.key_policy @@ -40,6 +45,58 @@ output "complete_aliases" { output "complete_grants" { description = "A map of grants created and their attributes" value = module.kms_complete.grants + sensitive = true +} + +################################################################################ +# Complete other region +################################################################################ + +output "complete_other_region_key_arn" { + description = "The Amazon Resource Name (ARN) of the key" + value = module.kms_complete_other_region.key_arn +} + +output "complete_other_region_key_id" { + description = "The globally unique identifier for the key" + value = module.kms_complete_other_region.key_id +} + +output "complete_other_region_key_region" { + description = "The region for the key" + value = module.kms_complete_other_region.key_region +} + +output "complete_other_region_key_policy" { + description = "The IAM resource policy set on the key" + value = module.kms_complete_other_region.key_policy +} + +output "complete_other_region_external_key_expiration_model" { + description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" + value = module.kms_complete_other_region.external_key_expiration_model +} + +output "complete_other_region_external_key_state" { + description = "The state of the CMK" + value = module.kms_complete_other_region.external_key_state +} + +output "complete_other_region_external_key_usage" { + description = "The cryptographic operations for which you can use the CMK" + value = module.kms_complete_other_region.external_key_usage +} + +output "complete_other_region_aliases" { + description = "A map of aliases created and their attributes" + value = module.kms_complete_other_region.aliases + sensitive = true +} + +output "complete_other_region_grants" { + description = "A map of grants created and their attributes" + value = module.kms_complete_other_region.grants + sensitive = true } ################################################################################ @@ -56,6 +113,11 @@ output "external_key_id" { value = module.kms_external.key_id } +output "external_key_region" { + description = "The region for the key" + value = module.kms_external.key_region +} + output "external_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_external.key_policy @@ -86,6 +148,55 @@ output "external_grants" { value = module.kms_external.grants } +################################################################################ +# External other region +################################################################################ + +output "external_other_region_key_arn" { + description = "The Amazon Resource Name (ARN) of the key" + value = module.kms_external_other_region.key_arn +} + +output "external_other_region_key_id" { + description = "The globally unique identifier for the key" + value = module.kms_external_other_region.key_id +} + +output "external_other_region_key_region" { + description = "The region for the key" + value = module.kms_external_other_region.key_region +} + +output "external_other_region_key_policy" { + description = "The IAM resource policy set on the key" + value = module.kms_external_other_region.key_policy +} + +output "external_other_region_external_key_expiration_model" { + description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" + value = module.kms_external_other_region.external_key_expiration_model +} + +output "external_other_region_external_key_state" { + description = "The state of the CMK" + value = module.kms_external_other_region.external_key_state +} + +output "external_other_region_external_key_usage" { + description = "The cryptographic operations for which you can use the CMK" + value = module.kms_external_other_region.external_key_usage +} + +output "external_other_region_aliases" { + description = "A map of aliases created and their attributes" + value = module.kms_external_other_region.aliases +} + +output "external_other_region_grants" { + description = "A map of grants created and their attributes" + value = module.kms_external_other_region.grants +} + ################################################################################ # Default ################################################################################ @@ -100,6 +211,11 @@ output "default_key_id" { value = module.kms_default.key_id } +output "default_key_region" { + description = "The region for the key" + value = module.kms_default.key_region +} + output "default_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_default.key_policy @@ -130,6 +246,55 @@ output "default_grants" { value = module.kms_default.grants } +################################################################################ +# Default other region +################################################################################ + +output "default_other_region_key_arn" { + description = "The Amazon Resource Name (ARN) of the key" + value = module.kms_default_other_region.key_arn +} + +output "default_other_region_key_id" { + description = "The globally unique identifier for the key" + value = module.kms_default_other_region.key_id +} + +output "default_other_region_key_region" { + description = "The region for the key" + value = module.kms_default_other_region.key_region +} + +output "default_other_region_key_policy" { + description = "The IAM resource policy set on the key" + value = module.kms_default_other_region.key_policy +} + +output "default_other_region_external_key_expiration_model" { + description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" + value = module.kms_default_other_region.external_key_expiration_model +} + +output "default_other_region_external_key_state" { + description = "The state of the CMK" + value = module.kms_default_other_region.external_key_state +} + +output "default_other_region_external_key_usage" { + description = "The cryptographic operations for which you can use the CMK" + value = module.kms_default_other_region.external_key_usage +} + +output "default_other_region_aliases" { + description = "A map of aliases created and their attributes" + value = module.kms_default_other_region.aliases +} + +output "default_other_region_grants" { + description = "A map of grants created and their attributes" + value = module.kms_default_other_region.grants +} + ################################################################################ # Replica @@ -145,6 +310,11 @@ output "replica_key_id" { value = module.kms_replica.key_id } +output "replica_key_region" { + description = "The region for the key" + value = module.kms_replica.key_region +} + output "replica_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_replica.key_policy @@ -173,6 +343,57 @@ output "replica_aliases" { output "replica_grants" { description = "A map of grants created and their attributes" value = module.kms_replica.grants + sensitive = true +} + +################################################################################ +# Replica other region +################################################################################ + +output "replica_other_region_key_arn" { + description = "The Amazon Resource Name (ARN) of the key" + value = module.kms_replica_other_region.key_arn +} + +output "replica_other_region_key_id" { + description = "The globally unique identifier for the key" + value = module.kms_replica_other_region.key_id +} + +output "replica_other_region_key_region" { + description = "The region for the key" + value = module.kms_replica_other_region.key_region +} + +output "replica_other_region_key_policy" { + description = "The IAM resource policy set on the key" + value = module.kms_replica_other_region.key_policy +} + +output "replica_other_region_key_expiration_model" { + description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" + value = module.kms_replica_other_region.external_key_expiration_model +} + +output "replica_other_region_key_state" { + description = "The state of the CMK" + value = module.kms_replica_other_region.external_key_state +} + +output "replica_other_region_key_usage" { + description = "The cryptographic operations for which you can use the CMK" + value = module.kms_replica_other_region.external_key_usage +} + +output "replica_other_region_aliases" { + description = "A map of aliases created and their attributes" + value = module.kms_replica_other_region.aliases +} + +output "replica_other_region_grants" { + description = "A map of grants created and their attributes" + value = module.kms_replica_other_region.grants + sensitive = true } @@ -190,6 +411,11 @@ output "replica_external_key_id" { value = module.kms_replica_external.key_id } +output "replica_external_key_region" { + description = "The region for the key" + value = module.kms_replica_external.key_region +} + output "replica_external_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_replica_external.key_policy @@ -218,4 +444,55 @@ output "replica_external_aliases" { output "replica_external_grants" { description = "A map of grants created and their attributes" value = module.kms_replica_external.grants + sensitive = true +} + +################################################################################ +# Replica External other region +################################################################################ + +output "replica_other_region_external_arn" { + description = "The Amazon Resource Name (ARN) of the key" + value = module.kms_replica_other_region.key_arn +} + +output "replica_other_region_external_key_id" { + description = "The globally unique identifier for the key" + value = module.kms_replica_other_region.key_id +} + +output "replica_other_region_external_key_region" { + description = "The region for the key" + value = module.kms_replica_other_region.key_region +} + +output "replica_other_region_external_key_policy" { + description = "The IAM resource policy set on the key" + value = module.kms_replica_other_region.key_policy +} + +output "replica_other_region_external_key_expiration_model" { + description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" + value = module.kms_replica_other_region.external_key_expiration_model +} + +output "replica_other_region_external_key_state" { + description = "The state of the CMK" + value = module.kms_replica_other_region.external_key_state +} + +output "replica_other_region_external_key_usage" { + description = "The cryptographic operations for which you can use the CMK" + value = module.kms_replica_other_region.external_key_usage +} + +output "replica_other_region_external_aliases" { + description = "A map of aliases created and their attributes" + value = module.kms_replica_other_region.aliases +} + +output "replica_other_region_external_grants" { + description = "A map of grants created and their attributes" + value = module.kms_replica_other_region.grants + sensitive = true } diff --git a/main.tf b/main.tf index 819de11..d2b390c 100644 --- a/main.tf +++ b/main.tf @@ -26,6 +26,7 @@ resource "aws_kms_key" "this" { enable_key_rotation = var.enable_key_rotation is_enabled = var.is_enabled key_usage = var.key_usage + region = var.region multi_region = var.multi_region policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) rotation_period_in_days = var.rotation_period_in_days @@ -45,6 +46,7 @@ resource "aws_kms_external_key" "this" { description = var.description enabled = var.is_enabled key_material_base64 = var.key_material_base64 + region = var.region multi_region = var.multi_region policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) valid_to = var.valid_to @@ -65,6 +67,7 @@ resource "aws_kms_replica_key" "this" { primary_key_arn = var.primary_key_arn enabled = var.is_enabled policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) + region = var.region tags = var.tags } @@ -84,6 +87,7 @@ resource "aws_kms_replica_external_key" "this" { policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) primary_key_arn = var.primary_external_key_arn valid_to = var.valid_to + region = var.region tags = var.tags } @@ -456,6 +460,7 @@ resource "aws_kms_alias" "this" { name = var.aliases_use_name_prefix ? null : "alias/${each.value.name}" name_prefix = var.aliases_use_name_prefix ? "alias/${each.value.name}-" : null target_key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) + region = var.region } ################################################################################ @@ -469,6 +474,7 @@ resource "aws_kms_grant" "this" { key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) grantee_principal = each.value.grantee_principal operations = each.value.operations + region = var.region dynamic "constraints" { for_each = length(lookup(each.value, "constraints", {})) == 0 ? [] : [each.value.constraints] diff --git a/outputs.tf b/outputs.tf index d002a3c..dd73e78 100644 --- a/outputs.tf +++ b/outputs.tf @@ -12,6 +12,11 @@ output "key_id" { value = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id, null) } +output "key_region" { + description = "The region for the key" + value = try(aws_kms_key.this[0].region, aws_kms_external_key.this[0].region, aws_kms_replica_key.this[0].region, aws_kms_replica_external_key.this[0].region, null) +} + output "key_policy" { description = "The IAM resource policy set on the key" value = try(aws_kms_key.this[0].policy, aws_kms_external_key.this[0].policy, aws_kms_replica_key.this[0].policy, aws_kms_replica_external_key.this[0].policy, null) diff --git a/variables.tf b/variables.tf index b66b126..d363201 100644 --- a/variables.tf +++ b/variables.tf @@ -4,6 +4,12 @@ variable "create" { default = true } +variable "region" { + description = "(Optional) Region where the resources 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 f96e1b1..61d65ab 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.49" + version = ">= 6.00" } } } diff --git a/wrappers/main.tf b/wrappers/main.tf index 6e2ebca..36d4791 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -32,6 +32,7 @@ module "wrapper" { key_symmetric_encryption_users = try(each.value.key_symmetric_encryption_users, var.defaults.key_symmetric_encryption_users, []) key_usage = try(each.value.key_usage, var.defaults.key_usage, null) key_users = try(each.value.key_users, var.defaults.key_users, []) + region = try(each.value.region, var.defaults.region, null) multi_region = try(each.value.multi_region, var.defaults.multi_region, false) override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) policy = try(each.value.policy, var.defaults.policy, null) diff --git a/wrappers/versions.tf b/wrappers/versions.tf index f96e1b1..61d65ab 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.49" + version = ">= 6.00" } } } From bf753ca70faa4b20edd81fad464ba4f2a5c6fd95 Mon Sep 17 00:00:00 2001 From: Samuel CHNIBER Date: Wed, 18 Jun 2025 22:31:01 +0200 Subject: [PATCH 2/8] run of pre-commit hooks --- README.md | 6 ++++-- variables.tf | 2 +- wrappers/main.tf | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8616254..e1d86dc 100644 --- a/README.md +++ b/README.md @@ -147,13 +147,13 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.49 | +| [aws](#requirement\_aws) | >= 6.00 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.49 | +| [aws](#provider\_aws) | >= 6.00 | ## Modules @@ -211,6 +211,7 @@ No modules. | [policy](#input\_policy) | A valid policy JSON document. Although this is a key policy, not an IAM policy, an `aws_iam_policy_document`, in the form that designates a principal, can be used | `string` | `null` | no | | [primary\_external\_key\_arn](#input\_primary\_external\_key\_arn) | The primary external key arn of a multi-region replica external key | `string` | `null` | no | | [primary\_key\_arn](#input\_primary\_key\_arn) | The primary key arn of a multi-region replica key | `string` | `null` | no | +| [region](#input\_region) | (Optional) The Region where the resources will be managed. Defaults to the region set in the provider configuration. | `string` | `null` | no | | [rotation\_period\_in\_days](#input\_rotation\_period\_in\_days) | Custom period of time between each rotation date. Must be a number between 90 and 2560 (inclusive) | `number` | `null` | no | | [route53\_dnssec\_sources](#input\_route53\_dnssec\_sources) | A list of maps containing `account_ids` and Route53 `hosted_zone_arn` that will be allowed to sign DNSSEC records | `list(any)` | `[]` | 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 | @@ -229,6 +230,7 @@ No modules. | [key\_arn](#output\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [key\_id](#output\_key\_id) | The globally unique identifier for the key | | [key\_policy](#output\_key\_policy) | The IAM resource policy set on the key | +| [key\_region](#output\_key\_region) | The region for the key | ## License diff --git a/variables.tf b/variables.tf index d363201..bfe0fe1 100644 --- a/variables.tf +++ b/variables.tf @@ -5,7 +5,7 @@ variable "create" { } variable "region" { - description = "(Optional) Region where the resources will be managed. Defaults to the region set in the provider configuration." + description = "(Optional) The Region where the resources will be managed. Defaults to the region set in the provider configuration." type = string default = null } diff --git a/wrappers/main.tf b/wrappers/main.tf index 36d4791..5a7cb3d 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -32,12 +32,12 @@ module "wrapper" { key_symmetric_encryption_users = try(each.value.key_symmetric_encryption_users, var.defaults.key_symmetric_encryption_users, []) key_usage = try(each.value.key_usage, var.defaults.key_usage, null) key_users = try(each.value.key_users, var.defaults.key_users, []) - region = try(each.value.region, var.defaults.region, null) multi_region = try(each.value.multi_region, var.defaults.multi_region, false) override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) policy = try(each.value.policy, var.defaults.policy, null) primary_external_key_arn = try(each.value.primary_external_key_arn, var.defaults.primary_external_key_arn, null) primary_key_arn = try(each.value.primary_key_arn, var.defaults.primary_key_arn, null) + region = try(each.value.region, var.defaults.region, null) rotation_period_in_days = try(each.value.rotation_period_in_days, var.defaults.rotation_period_in_days, null) route53_dnssec_sources = try(each.value.route53_dnssec_sources, var.defaults.route53_dnssec_sources, []) source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) From 2fbfb63205394a82b4e3d62fb97ffb59fb61b4db Mon Sep 17 00:00:00 2001 From: Samuel CHNIBER Date: Wed, 18 Jun 2025 22:33:37 +0200 Subject: [PATCH 3/8] feat: addition of enhanced region support --- examples/complete/README.md | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/examples/complete/README.md b/examples/complete/README.md index 5eb9a53..386e43b 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -38,14 +38,23 @@ Note that this example may create resources which will incur monetary charges on | Name | Source | Version | |------|--------|---------| | [kms\_complete](#module\_kms\_complete) | ../.. | n/a | +| [kms\_complete\_other\_region](#module\_kms\_complete\_other\_region) | ../.. | n/a | | [kms\_default](#module\_kms\_default) | ../.. | n/a | +| [kms\_default\_other\_region](#module\_kms\_default\_other\_region) | ../.. | n/a | | [kms\_disabled](#module\_kms\_disabled) | ../.. | n/a | | [kms\_dnssec\_signing](#module\_kms\_dnssec\_signing) | ../.. | n/a | +| [kms\_dnssec\_signing\_other\_region](#module\_kms\_dnssec\_signing\_other\_region) | ../.. | n/a | | [kms\_external](#module\_kms\_external) | ../.. | n/a | +| [kms\_external\_other\_region](#module\_kms\_external\_other\_region) | ../.. | n/a | +| [kms\_other\_region\_disabled](#module\_kms\_other\_region\_disabled) | ../.. | n/a | | [kms\_primary](#module\_kms\_primary) | ../.. | n/a | | [kms\_primary\_external](#module\_kms\_primary\_external) | ../.. | n/a | +| [kms\_primary\_external\_other\_region](#module\_kms\_primary\_external\_other\_region) | ../.. | n/a | +| [kms\_primary\_other\_region](#module\_kms\_primary\_other\_region) | ../.. | n/a | | [kms\_replica](#module\_kms\_replica) | ../.. | n/a | | [kms\_replica\_external](#module\_kms\_replica\_external) | ../.. | n/a | +| [kms\_replica\_external\_other\_region](#module\_kms\_replica\_external\_other\_region) | ../.. | n/a | +| [kms\_replica\_other\_region](#module\_kms\_replica\_other\_region) | ../.. | n/a | ## Resources @@ -54,6 +63,7 @@ Note that this example may create resources which will incur monetary charges on | [aws_iam_role.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | +| [aws_region.replica](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | ## Inputs @@ -71,6 +81,16 @@ No inputs. | [complete\_key\_arn](#output\_complete\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [complete\_key\_id](#output\_complete\_key\_id) | The globally unique identifier for the key | | [complete\_key\_policy](#output\_complete\_key\_policy) | The IAM resource policy set on the key | +| [complete\_key\_region](#output\_complete\_key\_region) | The region for the key | +| [complete\_other\_region\_aliases](#output\_complete\_other\_region\_aliases) | A map of aliases created and their attributes | +| [complete\_other\_region\_external\_key\_expiration\_model](#output\_complete\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | +| [complete\_other\_region\_external\_key\_state](#output\_complete\_other\_region\_external\_key\_state) | The state of the CMK | +| [complete\_other\_region\_external\_key\_usage](#output\_complete\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | +| [complete\_other\_region\_grants](#output\_complete\_other\_region\_grants) | A map of grants created and their attributes | +| [complete\_other\_region\_key\_arn](#output\_complete\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | +| [complete\_other\_region\_key\_id](#output\_complete\_other\_region\_key\_id) | The globally unique identifier for the key | +| [complete\_other\_region\_key\_policy](#output\_complete\_other\_region\_key\_policy) | The IAM resource policy set on the key | +| [complete\_other\_region\_key\_region](#output\_complete\_other\_region\_key\_region) | The region for the key | | [default\_aliases](#output\_default\_aliases) | A map of aliases created and their attributes | | [default\_external\_key\_expiration\_model](#output\_default\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [default\_external\_key\_state](#output\_default\_external\_key\_state) | The state of the CMK | @@ -79,6 +99,16 @@ No inputs. | [default\_key\_arn](#output\_default\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [default\_key\_id](#output\_default\_key\_id) | The globally unique identifier for the key | | [default\_key\_policy](#output\_default\_key\_policy) | The IAM resource policy set on the key | +| [default\_key\_region](#output\_default\_key\_region) | The region for the key | +| [default\_other\_region\_aliases](#output\_default\_other\_region\_aliases) | A map of aliases created and their attributes | +| [default\_other\_region\_external\_key\_expiration\_model](#output\_default\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | +| [default\_other\_region\_external\_key\_state](#output\_default\_other\_region\_external\_key\_state) | The state of the CMK | +| [default\_other\_region\_external\_key\_usage](#output\_default\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | +| [default\_other\_region\_grants](#output\_default\_other\_region\_grants) | A map of grants created and their attributes | +| [default\_other\_region\_key\_arn](#output\_default\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | +| [default\_other\_region\_key\_id](#output\_default\_other\_region\_key\_id) | The globally unique identifier for the key | +| [default\_other\_region\_key\_policy](#output\_default\_other\_region\_key\_policy) | The IAM resource policy set on the key | +| [default\_other\_region\_key\_region](#output\_default\_other\_region\_key\_region) | The region for the key | | [external\_aliases](#output\_external\_aliases) | A map of aliases created and their attributes | | [external\_external\_key\_expiration\_model](#output\_external\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [external\_external\_key\_state](#output\_external\_external\_key\_state) | The state of the CMK | @@ -87,6 +117,16 @@ No inputs. | [external\_key\_arn](#output\_external\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [external\_key\_id](#output\_external\_key\_id) | The globally unique identifier for the key | | [external\_key\_policy](#output\_external\_key\_policy) | The IAM resource policy set on the key | +| [external\_key\_region](#output\_external\_key\_region) | The region for the key | +| [external\_other\_region\_aliases](#output\_external\_other\_region\_aliases) | A map of aliases created and their attributes | +| [external\_other\_region\_external\_key\_expiration\_model](#output\_external\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | +| [external\_other\_region\_external\_key\_state](#output\_external\_other\_region\_external\_key\_state) | The state of the CMK | +| [external\_other\_region\_external\_key\_usage](#output\_external\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | +| [external\_other\_region\_grants](#output\_external\_other\_region\_grants) | A map of grants created and their attributes | +| [external\_other\_region\_key\_arn](#output\_external\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | +| [external\_other\_region\_key\_id](#output\_external\_other\_region\_key\_id) | The globally unique identifier for the key | +| [external\_other\_region\_key\_policy](#output\_external\_other\_region\_key\_policy) | The IAM resource policy set on the key | +| [external\_other\_region\_key\_region](#output\_external\_other\_region\_key\_region) | The region for the key | | [replica\_aliases](#output\_replica\_aliases) | A map of aliases created and their attributes | | [replica\_external\_aliases](#output\_replica\_external\_aliases) | A map of aliases created and their attributes | | [replica\_external\_arn](#output\_replica\_external\_arn) | The Amazon Resource Name (ARN) of the key | @@ -94,6 +134,7 @@ No inputs. | [replica\_external\_key\_expiration\_model](#output\_replica\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [replica\_external\_key\_id](#output\_replica\_external\_key\_id) | The globally unique identifier for the key | | [replica\_external\_key\_policy](#output\_replica\_external\_key\_policy) | The IAM resource policy set on the key | +| [replica\_external\_key\_region](#output\_replica\_external\_key\_region) | The region for the key | | [replica\_external\_key\_state](#output\_replica\_external\_key\_state) | The state of the CMK | | [replica\_external\_key\_usage](#output\_replica\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | | [replica\_grants](#output\_replica\_grants) | A map of grants created and their attributes | @@ -101,8 +142,27 @@ No inputs. | [replica\_key\_expiration\_model](#output\_replica\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [replica\_key\_id](#output\_replica\_key\_id) | The globally unique identifier for the key | | [replica\_key\_policy](#output\_replica\_key\_policy) | The IAM resource policy set on the key | +| [replica\_key\_region](#output\_replica\_key\_region) | The region for the key | | [replica\_key\_state](#output\_replica\_key\_state) | The state of the CMK | | [replica\_key\_usage](#output\_replica\_key\_usage) | The cryptographic operations for which you can use the CMK | +| [replica\_other\_region\_aliases](#output\_replica\_other\_region\_aliases) | A map of aliases created and their attributes | +| [replica\_other\_region\_external\_aliases](#output\_replica\_other\_region\_external\_aliases) | A map of aliases created and their attributes | +| [replica\_other\_region\_external\_arn](#output\_replica\_other\_region\_external\_arn) | The Amazon Resource Name (ARN) of the key | +| [replica\_other\_region\_external\_grants](#output\_replica\_other\_region\_external\_grants) | A map of grants created and their attributes | +| [replica\_other\_region\_external\_key\_expiration\_model](#output\_replica\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | +| [replica\_other\_region\_external\_key\_id](#output\_replica\_other\_region\_external\_key\_id) | The globally unique identifier for the key | +| [replica\_other\_region\_external\_key\_policy](#output\_replica\_other\_region\_external\_key\_policy) | The IAM resource policy set on the key | +| [replica\_other\_region\_external\_key\_region](#output\_replica\_other\_region\_external\_key\_region) | The region for the key | +| [replica\_other\_region\_external\_key\_state](#output\_replica\_other\_region\_external\_key\_state) | The state of the CMK | +| [replica\_other\_region\_external\_key\_usage](#output\_replica\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | +| [replica\_other\_region\_grants](#output\_replica\_other\_region\_grants) | A map of grants created and their attributes | +| [replica\_other\_region\_key\_arn](#output\_replica\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | +| [replica\_other\_region\_key\_expiration\_model](#output\_replica\_other\_region\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | +| [replica\_other\_region\_key\_id](#output\_replica\_other\_region\_key\_id) | The globally unique identifier for the key | +| [replica\_other\_region\_key\_policy](#output\_replica\_other\_region\_key\_policy) | The IAM resource policy set on the key | +| [replica\_other\_region\_key\_region](#output\_replica\_other\_region\_key\_region) | The region for the key | +| [replica\_other\_region\_key\_state](#output\_replica\_other\_region\_key\_state) | The state of the CMK | +| [replica\_other\_region\_key\_usage](#output\_replica\_other\_region\_key\_usage) | The cryptographic operations for which you can use the CMK | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-kms/blob/master/LICENSE). From 83c604c6071c6f8177ac20ca41202e4a611dbd5d Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sat, 5 Jul 2025 10:06:38 -0500 Subject: [PATCH 4/8] feat: Raise MSV of Terraform --- .pre-commit-config.yaml | 2 +- README.md | 6 +++--- examples/complete/README.md | 8 +++----- examples/complete/main.tf | 36 +++++++++++++++++------------------ examples/complete/versions.tf | 4 ++-- main.tf | 18 ++++++++++++------ versions.tf | 4 ++-- wrappers/versions.tf | 4 ++-- 8 files changed, 42 insertions(+), 40 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e4e7da..b84d048 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.4 hooks: - id: terraform_fmt - id: terraform_wrapper_module_for_each diff --git a/README.md b/README.md index e1d86dc..6742e46 100644 --- a/README.md +++ b/README.md @@ -146,14 +146,14 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 6.00 | +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [aws](#requirement\_aws) | >= 6.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 6.00 | +| [aws](#provider\_aws) | >= 6.0 | ## Modules diff --git a/examples/complete/README.md b/examples/complete/README.md index 386e43b..a1589d0 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -24,14 +24,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.49 | +| [terraform](#requirement\_terraform) | >= 1.5.7 | +| [aws](#requirement\_aws) | >= 6.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.49 | +| [aws](#provider\_aws) | >= 6.0 | ## Modules @@ -62,8 +62,6 @@ Note that this example may create resources which will incur monetary charges on |------|------| | [aws_iam_role.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | -| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | -| [aws_region.replica](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | ## Inputs diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 8d73bfb..d7e0f36 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -2,10 +2,14 @@ provider "aws" { region = local.region } +data "aws_caller_identity" "current" {} + locals { - region = "us-east-1" - replica_region = "eu-west-1" - name = "kms-ex-${replace(basename(path.cwd), "_", "-")}" + region = "us-east-1" + replica_region = "eu-west-1" + name = "kms-ex-${replace(basename(path.cwd), "_", "-")}" + + account_id = data.aws_caller_identity.current.account_id current_identity = data.aws_caller_identity.current.arn tags = { @@ -15,12 +19,6 @@ locals { } } -data "aws_caller_identity" "current" {} -data "aws_region" "current" {} -data "aws_region" "replica" { - region = local.region -} - ################################################################################ # KMS Module ################################################################################ @@ -41,7 +39,7 @@ module "kms_complete" { key_administrators = [local.current_identity] key_users = [local.current_identity] key_service_users = [local.current_identity] - key_service_roles_for_autoscaling = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] + key_service_roles_for_autoscaling = ["arn:aws:iam::${local.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] key_symmetric_encryption_users = [local.current_identity] key_hmac_users = [local.current_identity] key_asymmetric_public_encryption_users = [local.current_identity] @@ -61,7 +59,7 @@ module "kms_complete" { principals = [ { type = "Service" - identifiers = ["logs.${data.aws_region.current.region}.amazonaws.com"] + identifiers = ["logs.${local.region}.amazonaws.com"] } ] @@ -70,7 +68,7 @@ module "kms_complete" { test = "ArnLike" variable = "kms:EncryptionContext:aws:logs:arn" values = [ - "arn:aws:logs:${local.region}:${data.aws_caller_identity.current.account_id}:log-group:*", + "arn:aws:logs:${local.region}:${local.account_id}:log-group:*", ] } ] @@ -124,7 +122,7 @@ module "kms_complete_other_region" { key_administrators = [local.current_identity] key_users = [local.current_identity] key_service_users = [local.current_identity] - key_service_roles_for_autoscaling = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] + key_service_roles_for_autoscaling = ["arn:aws:iam::${local.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] key_symmetric_encryption_users = [local.current_identity] key_hmac_users = [local.current_identity] key_asymmetric_public_encryption_users = [local.current_identity] @@ -144,7 +142,7 @@ module "kms_complete_other_region" { principals = [ { type = "Service" - identifiers = ["logs.${data.aws_region.replica.region}.amazonaws.com"] + identifiers = ["logs.${local.replica_region}.amazonaws.com"] } ] @@ -153,7 +151,7 @@ module "kms_complete_other_region" { test = "ArnLike" variable = "kms:EncryptionContext:aws:logs:arn" values = [ - "arn:aws:logs:${local.replica_region}:${data.aws_caller_identity.current.account_id}:log-group:*", + "arn:aws:logs:${local.replica_region}:${local.account_id}:log-group:*", ] } ] @@ -231,8 +229,8 @@ module "kms_dnssec_signing" { enable_key_rotation = false route53_dnssec_sources = [ { - accounts_ids = [data.aws_caller_identity.current.account_id] # can ommit if using current account ID which is default - hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value + accounts_ids = [local.account_id] # can ommit if using current account ID which is default + hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value } ] @@ -253,8 +251,8 @@ module "kms_dnssec_signing_other_region" { enable_key_rotation = false route53_dnssec_sources = [ { - accounts_ids = [data.aws_caller_identity.current.account_id] # can ommit if using current account ID which is default - hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value + accounts_ids = [local.account_id] # can ommit if using current account ID which is default + hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value } ] region = local.replica_region diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index f96e1b1..db13b0a 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.5.7" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.49" + version = ">= 6.0" } } } diff --git a/main.tf b/main.tf index d2b390c..17b959a 100644 --- a/main.tf +++ b/main.tf @@ -18,6 +18,8 @@ locals { resource "aws_kms_key" "this" { count = var.create && !var.create_external && !var.create_replica && !var.create_replica_external ? 1 : 0 + region = var.region + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check customer_master_key_spec = var.customer_master_key_spec custom_key_store_id = var.custom_key_store_id @@ -26,7 +28,6 @@ resource "aws_kms_key" "this" { enable_key_rotation = var.enable_key_rotation is_enabled = var.is_enabled key_usage = var.key_usage - region = var.region multi_region = var.multi_region policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) rotation_period_in_days = var.rotation_period_in_days @@ -41,12 +42,13 @@ resource "aws_kms_key" "this" { resource "aws_kms_external_key" "this" { count = var.create && var.create_external && !var.create_replica && !var.create_replica_external ? 1 : 0 + region = var.region + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check deletion_window_in_days = var.deletion_window_in_days description = var.description enabled = var.is_enabled key_material_base64 = var.key_material_base64 - region = var.region multi_region = var.multi_region policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) valid_to = var.valid_to @@ -61,13 +63,14 @@ resource "aws_kms_external_key" "this" { resource "aws_kms_replica_key" "this" { count = var.create && var.create_replica && !var.create_external && !var.create_replica_external ? 1 : 0 + region = var.region + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check deletion_window_in_days = var.deletion_window_in_days description = var.description primary_key_arn = var.primary_key_arn enabled = var.is_enabled policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) - region = var.region tags = var.tags } @@ -79,6 +82,8 @@ resource "aws_kms_replica_key" "this" { resource "aws_kms_replica_external_key" "this" { count = var.create && !var.create_replica && !var.create_external && var.create_replica_external ? 1 : 0 + region = var.region + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check deletion_window_in_days = var.deletion_window_in_days description = var.description @@ -87,7 +92,6 @@ resource "aws_kms_replica_external_key" "this" { policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) primary_key_arn = var.primary_external_key_arn valid_to = var.valid_to - region = var.region tags = var.tags } @@ -457,10 +461,11 @@ locals { resource "aws_kms_alias" "this" { for_each = { for k, v in merge(local.aliases, var.computed_aliases) : k => v if var.create } + region = var.region + name = var.aliases_use_name_prefix ? null : "alias/${each.value.name}" name_prefix = var.aliases_use_name_prefix ? "alias/${each.value.name}-" : null target_key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) - region = var.region } ################################################################################ @@ -470,11 +475,12 @@ resource "aws_kms_alias" "this" { resource "aws_kms_grant" "this" { for_each = { for k, v in var.grants : k => v if var.create } + region = var.region + name = try(each.value.name, each.key) key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) grantee_principal = each.value.grantee_principal operations = each.value.operations - region = var.region dynamic "constraints" { for_each = length(lookup(each.value, "constraints", {})) == 0 ? [] : [each.value.constraints] diff --git a/versions.tf b/versions.tf index 61d65ab..db13b0a 100644 --- a/versions.tf +++ b/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.5.7" required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.00" + version = ">= 6.0" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 61d65ab..db13b0a 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.5.7" required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.00" + version = ">= 6.0" } } } From 21e8cdf289fc2d5542ce4912cb04a768a4b05467 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sat, 5 Jul 2025 10:10:16 -0500 Subject: [PATCH 5/8] fix: Remove region examples --- examples/complete/README.md | 54 -------- examples/complete/main.tf | 245 ---------------------------------- examples/complete/outputs.tf | 251 ----------------------------------- 3 files changed, 550 deletions(-) diff --git a/examples/complete/README.md b/examples/complete/README.md index a1589d0..de99b88 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -38,23 +38,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Source | Version | |------|--------|---------| | [kms\_complete](#module\_kms\_complete) | ../.. | n/a | -| [kms\_complete\_other\_region](#module\_kms\_complete\_other\_region) | ../.. | n/a | | [kms\_default](#module\_kms\_default) | ../.. | n/a | -| [kms\_default\_other\_region](#module\_kms\_default\_other\_region) | ../.. | n/a | | [kms\_disabled](#module\_kms\_disabled) | ../.. | n/a | | [kms\_dnssec\_signing](#module\_kms\_dnssec\_signing) | ../.. | n/a | -| [kms\_dnssec\_signing\_other\_region](#module\_kms\_dnssec\_signing\_other\_region) | ../.. | n/a | | [kms\_external](#module\_kms\_external) | ../.. | n/a | -| [kms\_external\_other\_region](#module\_kms\_external\_other\_region) | ../.. | n/a | -| [kms\_other\_region\_disabled](#module\_kms\_other\_region\_disabled) | ../.. | n/a | | [kms\_primary](#module\_kms\_primary) | ../.. | n/a | | [kms\_primary\_external](#module\_kms\_primary\_external) | ../.. | n/a | -| [kms\_primary\_external\_other\_region](#module\_kms\_primary\_external\_other\_region) | ../.. | n/a | -| [kms\_primary\_other\_region](#module\_kms\_primary\_other\_region) | ../.. | n/a | | [kms\_replica](#module\_kms\_replica) | ../.. | n/a | | [kms\_replica\_external](#module\_kms\_replica\_external) | ../.. | n/a | -| [kms\_replica\_external\_other\_region](#module\_kms\_replica\_external\_other\_region) | ../.. | n/a | -| [kms\_replica\_other\_region](#module\_kms\_replica\_other\_region) | ../.. | n/a | ## Resources @@ -80,15 +71,6 @@ No inputs. | [complete\_key\_id](#output\_complete\_key\_id) | The globally unique identifier for the key | | [complete\_key\_policy](#output\_complete\_key\_policy) | The IAM resource policy set on the key | | [complete\_key\_region](#output\_complete\_key\_region) | The region for the key | -| [complete\_other\_region\_aliases](#output\_complete\_other\_region\_aliases) | A map of aliases created and their attributes | -| [complete\_other\_region\_external\_key\_expiration\_model](#output\_complete\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | -| [complete\_other\_region\_external\_key\_state](#output\_complete\_other\_region\_external\_key\_state) | The state of the CMK | -| [complete\_other\_region\_external\_key\_usage](#output\_complete\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | -| [complete\_other\_region\_grants](#output\_complete\_other\_region\_grants) | A map of grants created and their attributes | -| [complete\_other\_region\_key\_arn](#output\_complete\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | -| [complete\_other\_region\_key\_id](#output\_complete\_other\_region\_key\_id) | The globally unique identifier for the key | -| [complete\_other\_region\_key\_policy](#output\_complete\_other\_region\_key\_policy) | The IAM resource policy set on the key | -| [complete\_other\_region\_key\_region](#output\_complete\_other\_region\_key\_region) | The region for the key | | [default\_aliases](#output\_default\_aliases) | A map of aliases created and their attributes | | [default\_external\_key\_expiration\_model](#output\_default\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [default\_external\_key\_state](#output\_default\_external\_key\_state) | The state of the CMK | @@ -98,15 +80,6 @@ No inputs. | [default\_key\_id](#output\_default\_key\_id) | The globally unique identifier for the key | | [default\_key\_policy](#output\_default\_key\_policy) | The IAM resource policy set on the key | | [default\_key\_region](#output\_default\_key\_region) | The region for the key | -| [default\_other\_region\_aliases](#output\_default\_other\_region\_aliases) | A map of aliases created and their attributes | -| [default\_other\_region\_external\_key\_expiration\_model](#output\_default\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | -| [default\_other\_region\_external\_key\_state](#output\_default\_other\_region\_external\_key\_state) | The state of the CMK | -| [default\_other\_region\_external\_key\_usage](#output\_default\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | -| [default\_other\_region\_grants](#output\_default\_other\_region\_grants) | A map of grants created and their attributes | -| [default\_other\_region\_key\_arn](#output\_default\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | -| [default\_other\_region\_key\_id](#output\_default\_other\_region\_key\_id) | The globally unique identifier for the key | -| [default\_other\_region\_key\_policy](#output\_default\_other\_region\_key\_policy) | The IAM resource policy set on the key | -| [default\_other\_region\_key\_region](#output\_default\_other\_region\_key\_region) | The region for the key | | [external\_aliases](#output\_external\_aliases) | A map of aliases created and their attributes | | [external\_external\_key\_expiration\_model](#output\_external\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [external\_external\_key\_state](#output\_external\_external\_key\_state) | The state of the CMK | @@ -116,15 +89,6 @@ No inputs. | [external\_key\_id](#output\_external\_key\_id) | The globally unique identifier for the key | | [external\_key\_policy](#output\_external\_key\_policy) | The IAM resource policy set on the key | | [external\_key\_region](#output\_external\_key\_region) | The region for the key | -| [external\_other\_region\_aliases](#output\_external\_other\_region\_aliases) | A map of aliases created and their attributes | -| [external\_other\_region\_external\_key\_expiration\_model](#output\_external\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | -| [external\_other\_region\_external\_key\_state](#output\_external\_other\_region\_external\_key\_state) | The state of the CMK | -| [external\_other\_region\_external\_key\_usage](#output\_external\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | -| [external\_other\_region\_grants](#output\_external\_other\_region\_grants) | A map of grants created and their attributes | -| [external\_other\_region\_key\_arn](#output\_external\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | -| [external\_other\_region\_key\_id](#output\_external\_other\_region\_key\_id) | The globally unique identifier for the key | -| [external\_other\_region\_key\_policy](#output\_external\_other\_region\_key\_policy) | The IAM resource policy set on the key | -| [external\_other\_region\_key\_region](#output\_external\_other\_region\_key\_region) | The region for the key | | [replica\_aliases](#output\_replica\_aliases) | A map of aliases created and their attributes | | [replica\_external\_aliases](#output\_replica\_external\_aliases) | A map of aliases created and their attributes | | [replica\_external\_arn](#output\_replica\_external\_arn) | The Amazon Resource Name (ARN) of the key | @@ -143,24 +107,6 @@ No inputs. | [replica\_key\_region](#output\_replica\_key\_region) | The region for the key | | [replica\_key\_state](#output\_replica\_key\_state) | The state of the CMK | | [replica\_key\_usage](#output\_replica\_key\_usage) | The cryptographic operations for which you can use the CMK | -| [replica\_other\_region\_aliases](#output\_replica\_other\_region\_aliases) | A map of aliases created and their attributes | -| [replica\_other\_region\_external\_aliases](#output\_replica\_other\_region\_external\_aliases) | A map of aliases created and their attributes | -| [replica\_other\_region\_external\_arn](#output\_replica\_other\_region\_external\_arn) | The Amazon Resource Name (ARN) of the key | -| [replica\_other\_region\_external\_grants](#output\_replica\_other\_region\_external\_grants) | A map of grants created and their attributes | -| [replica\_other\_region\_external\_key\_expiration\_model](#output\_replica\_other\_region\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | -| [replica\_other\_region\_external\_key\_id](#output\_replica\_other\_region\_external\_key\_id) | The globally unique identifier for the key | -| [replica\_other\_region\_external\_key\_policy](#output\_replica\_other\_region\_external\_key\_policy) | The IAM resource policy set on the key | -| [replica\_other\_region\_external\_key\_region](#output\_replica\_other\_region\_external\_key\_region) | The region for the key | -| [replica\_other\_region\_external\_key\_state](#output\_replica\_other\_region\_external\_key\_state) | The state of the CMK | -| [replica\_other\_region\_external\_key\_usage](#output\_replica\_other\_region\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | -| [replica\_other\_region\_grants](#output\_replica\_other\_region\_grants) | A map of grants created and their attributes | -| [replica\_other\_region\_key\_arn](#output\_replica\_other\_region\_key\_arn) | The Amazon Resource Name (ARN) of the key | -| [replica\_other\_region\_key\_expiration\_model](#output\_replica\_other\_region\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | -| [replica\_other\_region\_key\_id](#output\_replica\_other\_region\_key\_id) | The globally unique identifier for the key | -| [replica\_other\_region\_key\_policy](#output\_replica\_other\_region\_key\_policy) | The IAM resource policy set on the key | -| [replica\_other\_region\_key\_region](#output\_replica\_other\_region\_key\_region) | The region for the key | -| [replica\_other\_region\_key\_state](#output\_replica\_other\_region\_key\_state) | The state of the CMK | -| [replica\_other\_region\_key\_usage](#output\_replica\_other\_region\_key\_usage) | The cryptographic operations for which you can use the CMK | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-kms/blob/master/LICENSE). diff --git a/examples/complete/main.tf b/examples/complete/main.tf index d7e0f36..8da4c6f 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -105,89 +105,6 @@ module "kms_complete" { tags = local.tags } -module "kms_complete_other_region" { - source = "../.." - - deletion_window_in_days = 7 - description = "Complete key example showing various configurations available" - enable_key_rotation = false - is_enabled = true - key_usage = "ENCRYPT_DECRYPT" - region = local.replica_region - multi_region = false - - # Policy - enable_default_policy = true - key_owners = [local.current_identity] - key_administrators = [local.current_identity] - key_users = [local.current_identity] - key_service_users = [local.current_identity] - key_service_roles_for_autoscaling = ["arn:aws:iam::${local.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] - key_symmetric_encryption_users = [local.current_identity] - key_hmac_users = [local.current_identity] - key_asymmetric_public_encryption_users = [local.current_identity] - key_asymmetric_sign_verify_users = [local.current_identity] - key_statements = [ - { - sid = "CloudWatchLogs" - actions = [ - "kms:Encrypt*", - "kms:Decrypt*", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:Describe*" - ] - resources = ["*"] - - principals = [ - { - type = "Service" - identifiers = ["logs.${local.replica_region}.amazonaws.com"] - } - ] - - conditions = [ - { - test = "ArnLike" - variable = "kms:EncryptionContext:aws:logs:arn" - values = [ - "arn:aws:logs:${local.replica_region}:${local.account_id}:log-group:*", - ] - } - ] - } - ] - - # Aliases - aliases = ["one-other", "foo/bar-other"] - computed_aliases = { - ex = { - # Sometimes you want to pass in an upstream attribute as the name and - # that conflicts with using `for_each over a `toset()` since the value is not - # known until after applying. Instead, we can use `computed_aliases` to work - # around this limitation - # Reference: https://github.com/hashicorp/terraform/issues/30937 - name = aws_iam_role.lambda.name - } - } - aliases_use_name_prefix = true - - # Grants - grants = { - lambda = { - grantee_principal = aws_iam_role.lambda.arn - operations = ["Encrypt", "Decrypt", "GenerateDataKey"] - constraints = { - encryption_context_equals = { - Department = "Finance" - } - } - } - } - - tags = local.tags -} - module "kms_external" { source = "../.." @@ -202,21 +119,6 @@ module "kms_external" { tags = local.tags } -module "kms_external_other_region" { - source = "../.." - - deletion_window_in_days = 7 - description = "External key example" - create_external = true - is_enabled = true - key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" - multi_region = false - valid_to = "2025-11-21T23:20:50Z" - region = local.replica_region - - tags = local.tags -} - module "kms_dnssec_signing" { source = "../.." @@ -239,56 +141,18 @@ module "kms_dnssec_signing" { tags = local.tags } -module "kms_dnssec_signing_other_region" { - source = "../.." - - description = "CMK for Route53 DNSSEC signing" - - key_usage = "SIGN_VERIFY" - customer_master_key_spec = "ECC_NIST_P256" - - enable_route53_dnssec = true - enable_key_rotation = false - route53_dnssec_sources = [ - { - accounts_ids = [local.account_id] # can ommit if using current account ID which is default - hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value - } - ] - region = local.replica_region - - aliases = ["route53/dnssec-ex-other"] - - tags = local.tags -} - module "kms_default" { source = "../.." tags = local.tags } -module "kms_default_other_region" { - source = "../.." - - region = local.replica_region - - tags = local.tags -} - module "kms_disabled" { source = "../.." create = false } -module "kms_other_region_disabled" { - source = "../.." - - create = false - region = local.replica_region -} - ################################################################################ # Replica Key Example ################################################################################ @@ -352,66 +216,6 @@ module "kms_replica" { tags = local.tags } -module "kms_primary_other_region" { - source = "../.." - - deletion_window_in_days = 7 - description = "Primary key of replica key example" - enable_key_rotation = false - is_enabled = true - key_usage = "ENCRYPT_DECRYPT" - region = local.replica_region - multi_region = true - - aliases = ["primary-standard-other"] - - tags = local.tags -} - -module "kms_replica_other_region" { - source = "../.." - - deletion_window_in_days = 7 - description = "Replica key example showing various configurations available" - create_replica = true - primary_key_arn = module.kms_primary_other_region.key_arn - enable_default_policy = true - - key_owners = [local.current_identity] - key_administrators = [local.current_identity] - key_users = [local.current_identity] - - # Aliases - aliases = ["replica-standard-other"] - computed_aliases = { - ex = { - # Sometimes you want to pass in an upstream attribute as the name and - # that conflicts with using `for_each over a `toset()` since the value is not - # known until after applying. Instead, we can use `computed_aliases` to work - # around this limitation - # Reference: https://github.com/hashicorp/terraform/issues/30937 - name = aws_iam_role.lambda.name - } - } - - # Grants - grants = { - lambda = { - grantee_principal = aws_iam_role.lambda.arn - operations = ["Encrypt", "Decrypt", "GenerateDataKey"] - constraints = { - encryption_context_equals = { - Department = "Finance" - } - } - } - } - - region = local.region - - tags = local.tags -} - ################################################################################ # Replica External Key Example ################################################################################ @@ -464,55 +268,6 @@ module "kms_replica_external" { tags = local.tags } -module "kms_primary_external_other_region" { - source = "../.." - - deletion_window_in_days = 7 - description = "Primary external key of replica external key example" - is_enabled = true - create_external = true - key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" - region = local.replica_region - multi_region = true - valid_to = "2025-11-21T23:20:50Z" - - aliases = ["primary-external-other-region"] - - tags = local.tags -} - -module "kms_replica_external_other_region" { - source = "../.." - - deletion_window_in_days = 7 - description = "Replica external key example showing various configurations available" - create_replica_external = true - is_enabled = true - # key material must be the same as the primary's - key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" - primary_external_key_arn = module.kms_primary_external_other_region.key_arn - valid_to = "2025-11-21T23:20:50Z" - - aliases = ["replica-external-other-region"] - - # Grants - grants = { - lambda = { - grantee_principal = aws_iam_role.lambda.arn - operations = ["Encrypt", "Decrypt", "GenerateDataKey"] - constraints = { - encryption_context_equals = { - Department = "Finance" - } - } - } - } - - region = local.region - - tags = local.tags -} - ################################################################################ # Supporting Resources ################################################################################ diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index 88c841f..24e95d6 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -48,57 +48,6 @@ output "complete_grants" { sensitive = true } -################################################################################ -# Complete other region -################################################################################ - -output "complete_other_region_key_arn" { - description = "The Amazon Resource Name (ARN) of the key" - value = module.kms_complete_other_region.key_arn -} - -output "complete_other_region_key_id" { - description = "The globally unique identifier for the key" - value = module.kms_complete_other_region.key_id -} - -output "complete_other_region_key_region" { - description = "The region for the key" - value = module.kms_complete_other_region.key_region -} - -output "complete_other_region_key_policy" { - description = "The IAM resource policy set on the key" - value = module.kms_complete_other_region.key_policy -} - -output "complete_other_region_external_key_expiration_model" { - description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" - value = module.kms_complete_other_region.external_key_expiration_model -} - -output "complete_other_region_external_key_state" { - description = "The state of the CMK" - value = module.kms_complete_other_region.external_key_state -} - -output "complete_other_region_external_key_usage" { - description = "The cryptographic operations for which you can use the CMK" - value = module.kms_complete_other_region.external_key_usage -} - -output "complete_other_region_aliases" { - description = "A map of aliases created and their attributes" - value = module.kms_complete_other_region.aliases - sensitive = true -} - -output "complete_other_region_grants" { - description = "A map of grants created and their attributes" - value = module.kms_complete_other_region.grants - sensitive = true -} - ################################################################################ # External ################################################################################ @@ -148,55 +97,6 @@ output "external_grants" { value = module.kms_external.grants } -################################################################################ -# External other region -################################################################################ - -output "external_other_region_key_arn" { - description = "The Amazon Resource Name (ARN) of the key" - value = module.kms_external_other_region.key_arn -} - -output "external_other_region_key_id" { - description = "The globally unique identifier for the key" - value = module.kms_external_other_region.key_id -} - -output "external_other_region_key_region" { - description = "The region for the key" - value = module.kms_external_other_region.key_region -} - -output "external_other_region_key_policy" { - description = "The IAM resource policy set on the key" - value = module.kms_external_other_region.key_policy -} - -output "external_other_region_external_key_expiration_model" { - description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" - value = module.kms_external_other_region.external_key_expiration_model -} - -output "external_other_region_external_key_state" { - description = "The state of the CMK" - value = module.kms_external_other_region.external_key_state -} - -output "external_other_region_external_key_usage" { - description = "The cryptographic operations for which you can use the CMK" - value = module.kms_external_other_region.external_key_usage -} - -output "external_other_region_aliases" { - description = "A map of aliases created and their attributes" - value = module.kms_external_other_region.aliases -} - -output "external_other_region_grants" { - description = "A map of grants created and their attributes" - value = module.kms_external_other_region.grants -} - ################################################################################ # Default ################################################################################ @@ -246,56 +146,6 @@ output "default_grants" { value = module.kms_default.grants } -################################################################################ -# Default other region -################################################################################ - -output "default_other_region_key_arn" { - description = "The Amazon Resource Name (ARN) of the key" - value = module.kms_default_other_region.key_arn -} - -output "default_other_region_key_id" { - description = "The globally unique identifier for the key" - value = module.kms_default_other_region.key_id -} - -output "default_other_region_key_region" { - description = "The region for the key" - value = module.kms_default_other_region.key_region -} - -output "default_other_region_key_policy" { - description = "The IAM resource policy set on the key" - value = module.kms_default_other_region.key_policy -} - -output "default_other_region_external_key_expiration_model" { - description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" - value = module.kms_default_other_region.external_key_expiration_model -} - -output "default_other_region_external_key_state" { - description = "The state of the CMK" - value = module.kms_default_other_region.external_key_state -} - -output "default_other_region_external_key_usage" { - description = "The cryptographic operations for which you can use the CMK" - value = module.kms_default_other_region.external_key_usage -} - -output "default_other_region_aliases" { - description = "A map of aliases created and their attributes" - value = module.kms_default_other_region.aliases -} - -output "default_other_region_grants" { - description = "A map of grants created and their attributes" - value = module.kms_default_other_region.grants -} - - ################################################################################ # Replica ################################################################################ @@ -346,57 +196,6 @@ output "replica_grants" { sensitive = true } -################################################################################ -# Replica other region -################################################################################ - -output "replica_other_region_key_arn" { - description = "The Amazon Resource Name (ARN) of the key" - value = module.kms_replica_other_region.key_arn -} - -output "replica_other_region_key_id" { - description = "The globally unique identifier for the key" - value = module.kms_replica_other_region.key_id -} - -output "replica_other_region_key_region" { - description = "The region for the key" - value = module.kms_replica_other_region.key_region -} - -output "replica_other_region_key_policy" { - description = "The IAM resource policy set on the key" - value = module.kms_replica_other_region.key_policy -} - -output "replica_other_region_key_expiration_model" { - description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" - value = module.kms_replica_other_region.external_key_expiration_model -} - -output "replica_other_region_key_state" { - description = "The state of the CMK" - value = module.kms_replica_other_region.external_key_state -} - -output "replica_other_region_key_usage" { - description = "The cryptographic operations for which you can use the CMK" - value = module.kms_replica_other_region.external_key_usage -} - -output "replica_other_region_aliases" { - description = "A map of aliases created and their attributes" - value = module.kms_replica_other_region.aliases -} - -output "replica_other_region_grants" { - description = "A map of grants created and their attributes" - value = module.kms_replica_other_region.grants - sensitive = true -} - - ################################################################################ # Replica External ################################################################################ @@ -446,53 +245,3 @@ output "replica_external_grants" { value = module.kms_replica_external.grants sensitive = true } - -################################################################################ -# Replica External other region -################################################################################ - -output "replica_other_region_external_arn" { - description = "The Amazon Resource Name (ARN) of the key" - value = module.kms_replica_other_region.key_arn -} - -output "replica_other_region_external_key_id" { - description = "The globally unique identifier for the key" - value = module.kms_replica_other_region.key_id -} - -output "replica_other_region_external_key_region" { - description = "The region for the key" - value = module.kms_replica_other_region.key_region -} - -output "replica_other_region_external_key_policy" { - description = "The IAM resource policy set on the key" - value = module.kms_replica_other_region.key_policy -} - -output "replica_other_region_external_key_expiration_model" { - description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" - value = module.kms_replica_other_region.external_key_expiration_model -} - -output "replica_other_region_external_key_state" { - description = "The state of the CMK" - value = module.kms_replica_other_region.external_key_state -} - -output "replica_other_region_external_key_usage" { - description = "The cryptographic operations for which you can use the CMK" - value = module.kms_replica_other_region.external_key_usage -} - -output "replica_other_region_external_aliases" { - description = "A map of aliases created and their attributes" - value = module.kms_replica_other_region.aliases -} - -output "replica_other_region_external_grants" { - description = "A map of grants created and their attributes" - value = module.kms_replica_other_region.grants - sensitive = true -} From 0d4367125173f72cb102ade7c4163849894771af Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sat, 5 Jul 2025 10:15:27 -0500 Subject: [PATCH 6/8] fix: Re-align example --- examples/complete/README.md | 5 ----- examples/complete/main.tf | 28 ++++++++++++++++++---------- examples/complete/outputs.tf | 30 ++---------------------------- 3 files changed, 20 insertions(+), 43 deletions(-) diff --git a/examples/complete/README.md b/examples/complete/README.md index de99b88..e612714 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -70,7 +70,6 @@ No inputs. | [complete\_key\_arn](#output\_complete\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [complete\_key\_id](#output\_complete\_key\_id) | The globally unique identifier for the key | | [complete\_key\_policy](#output\_complete\_key\_policy) | The IAM resource policy set on the key | -| [complete\_key\_region](#output\_complete\_key\_region) | The region for the key | | [default\_aliases](#output\_default\_aliases) | A map of aliases created and their attributes | | [default\_external\_key\_expiration\_model](#output\_default\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [default\_external\_key\_state](#output\_default\_external\_key\_state) | The state of the CMK | @@ -79,7 +78,6 @@ No inputs. | [default\_key\_arn](#output\_default\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [default\_key\_id](#output\_default\_key\_id) | The globally unique identifier for the key | | [default\_key\_policy](#output\_default\_key\_policy) | The IAM resource policy set on the key | -| [default\_key\_region](#output\_default\_key\_region) | The region for the key | | [external\_aliases](#output\_external\_aliases) | A map of aliases created and their attributes | | [external\_external\_key\_expiration\_model](#output\_external\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [external\_external\_key\_state](#output\_external\_external\_key\_state) | The state of the CMK | @@ -88,7 +86,6 @@ No inputs. | [external\_key\_arn](#output\_external\_key\_arn) | The Amazon Resource Name (ARN) of the key | | [external\_key\_id](#output\_external\_key\_id) | The globally unique identifier for the key | | [external\_key\_policy](#output\_external\_key\_policy) | The IAM resource policy set on the key | -| [external\_key\_region](#output\_external\_key\_region) | The region for the key | | [replica\_aliases](#output\_replica\_aliases) | A map of aliases created and their attributes | | [replica\_external\_aliases](#output\_replica\_external\_aliases) | A map of aliases created and their attributes | | [replica\_external\_arn](#output\_replica\_external\_arn) | The Amazon Resource Name (ARN) of the key | @@ -96,7 +93,6 @@ No inputs. | [replica\_external\_key\_expiration\_model](#output\_replica\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [replica\_external\_key\_id](#output\_replica\_external\_key\_id) | The globally unique identifier for the key | | [replica\_external\_key\_policy](#output\_replica\_external\_key\_policy) | The IAM resource policy set on the key | -| [replica\_external\_key\_region](#output\_replica\_external\_key\_region) | The region for the key | | [replica\_external\_key\_state](#output\_replica\_external\_key\_state) | The state of the CMK | | [replica\_external\_key\_usage](#output\_replica\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | | [replica\_grants](#output\_replica\_grants) | A map of grants created and their attributes | @@ -104,7 +100,6 @@ No inputs. | [replica\_key\_expiration\_model](#output\_replica\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | | [replica\_key\_id](#output\_replica\_key\_id) | The globally unique identifier for the key | | [replica\_key\_policy](#output\_replica\_key\_policy) | The IAM resource policy set on the key | -| [replica\_key\_region](#output\_replica\_key\_region) | The region for the key | | [replica\_key\_state](#output\_replica\_key\_state) | The state of the CMK | | [replica\_key\_usage](#output\_replica\_key\_usage) | The cryptographic operations for which you can use the CMK | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 8da4c6f..366e0c4 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -5,9 +5,8 @@ provider "aws" { data "aws_caller_identity" "current" {} locals { - region = "us-east-1" - replica_region = "eu-west-1" - name = "kms-ex-${replace(basename(path.cwd), "_", "-")}" + region = "us-east-1" + name = "kms-ex-${basename(path.cwd)}" account_id = data.aws_caller_identity.current.account_id current_identity = data.aws_caller_identity.current.arn @@ -114,7 +113,7 @@ module "kms_external" { is_enabled = true key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" multi_region = false - valid_to = "2025-11-21T23:20:50Z" + valid_to = "2023-11-21T23:20:50Z" tags = local.tags } @@ -172,9 +171,18 @@ module "kms_primary" { tags = local.tags } +provider "aws" { + region = "eu-west-1" + alias = "replica" +} + module "kms_replica" { source = "../.." + providers = { + aws = aws.replica + } + deletion_window_in_days = 7 description = "Replica key example showing various configurations available" create_replica = true @@ -211,8 +219,6 @@ module "kms_replica" { } } - region = local.replica_region - tags = local.tags } @@ -229,7 +235,7 @@ module "kms_primary_external" { create_external = true key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" multi_region = true - valid_to = "2025-11-21T23:20:50Z" + valid_to = "2023-11-21T23:20:50Z" aliases = ["primary-external"] @@ -239,6 +245,10 @@ module "kms_primary_external" { module "kms_replica_external" { source = "../.." + providers = { + aws = aws.replica + } + deletion_window_in_days = 7 description = "Replica external key example showing various configurations available" create_replica_external = true @@ -246,7 +256,7 @@ module "kms_replica_external" { # key material must be the same as the primary's key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" primary_external_key_arn = module.kms_primary_external.key_arn - valid_to = "2025-11-21T23:20:50Z" + valid_to = "2023-11-21T23:20:50Z" aliases = ["replica-external"] @@ -263,8 +273,6 @@ module "kms_replica_external" { } } - region = local.replica_region - tags = local.tags } diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index 24e95d6..a2edbf6 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -12,11 +12,6 @@ output "complete_key_id" { value = module.kms_complete.key_id } -output "complete_key_region" { - description = "The region for the key" - value = module.kms_complete.key_region -} - output "complete_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_complete.key_policy @@ -45,7 +40,6 @@ output "complete_aliases" { output "complete_grants" { description = "A map of grants created and their attributes" value = module.kms_complete.grants - sensitive = true } ################################################################################ @@ -62,11 +56,6 @@ output "external_key_id" { value = module.kms_external.key_id } -output "external_key_region" { - description = "The region for the key" - value = module.kms_external.key_region -} - output "external_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_external.key_policy @@ -111,11 +100,6 @@ output "default_key_id" { value = module.kms_default.key_id } -output "default_key_region" { - description = "The region for the key" - value = module.kms_default.key_region -} - output "default_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_default.key_policy @@ -146,6 +130,7 @@ output "default_grants" { value = module.kms_default.grants } + ################################################################################ # Replica ################################################################################ @@ -160,11 +145,6 @@ output "replica_key_id" { value = module.kms_replica.key_id } -output "replica_key_region" { - description = "The region for the key" - value = module.kms_replica.key_region -} - output "replica_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_replica.key_policy @@ -193,9 +173,9 @@ output "replica_aliases" { output "replica_grants" { description = "A map of grants created and their attributes" value = module.kms_replica.grants - sensitive = true } + ################################################################################ # Replica External ################################################################################ @@ -210,11 +190,6 @@ output "replica_external_key_id" { value = module.kms_replica_external.key_id } -output "replica_external_key_region" { - description = "The region for the key" - value = module.kms_replica_external.key_region -} - output "replica_external_key_policy" { description = "The IAM resource policy set on the key" value = module.kms_replica_external.key_policy @@ -243,5 +218,4 @@ output "replica_external_aliases" { output "replica_external_grants" { description = "A map of grants created and their attributes" value = module.kms_replica_external.grants - sensitive = true } From 571f2bae52dc00640d11db6818f6288b6caab6ac Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sat, 5 Jul 2025 10:47:22 -0500 Subject: [PATCH 7/8] feat: Add variable definitions to replace `any` --- README.md | 10 ++++----- main.tf | 51 ++++++++++++++++++++++----------------------- variables.tf | 54 ++++++++++++++++++++++++++++++++++++++++-------- wrappers/main.tf | 6 +++--- 4 files changed, 78 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 6742e46..67368a6 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ No modules. | [aliases](#input\_aliases) | A list of aliases to create. Note - due to the use of `toset()`, values must be static strings and not computed values | `list(string)` | `[]` | no | | [aliases\_use\_name\_prefix](#input\_aliases\_use\_name\_prefix) | Determines whether the alias name is used as a prefix | `bool` | `false` | no | | [bypass\_policy\_lockout\_safety\_check](#input\_bypass\_policy\_lockout\_safety\_check) | A flag to indicate whether to bypass the key policy lockout safety check. Setting this value to true increases the risk that the KMS key becomes unmanageable | `bool` | `null` | no | -| [computed\_aliases](#input\_computed\_aliases) | A map of aliases to create. Values provided via the `name` key of the map can be computed from upstream resources | `any` | `{}` | no | +| [computed\_aliases](#input\_computed\_aliases) | A map of aliases to create. Values provided via the `name` key of the map can be computed from upstream resources |
map(object({
name = string
}))
| `{}` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_external](#input\_create\_external) | Determines whether an external CMK (externally provided material) will be created or a standard CMK (AWS provided material) | `bool` | `false` | no | | [create\_replica](#input\_create\_replica) | Determines whether a replica standard CMK will be created (AWS provided material) | `bool` | `false` | no | @@ -192,7 +192,7 @@ No modules. | [enable\_default\_policy](#input\_enable\_default\_policy) | Specifies whether to enable the default key policy. Defaults to `true` | `bool` | `true` | no | | [enable\_key\_rotation](#input\_enable\_key\_rotation) | Specifies whether key rotation is enabled. Defaults to `true` | `bool` | `true` | no | | [enable\_route53\_dnssec](#input\_enable\_route53\_dnssec) | Determines whether the KMS policy used for Route53 DNSSEC signing is enabled | `bool` | `false` | no | -| [grants](#input\_grants) | A map of grant definitions to create | `any` | `{}` | no | +| [grants](#input\_grants) | A map of grant definitions to create |
map(object({
constraints = optional(object({
encryption_context_equals = optional(map(string))
encryption_context_subset = optional(map(string))
}))
grant_creation_tokens = optional(string)
grantee_principal = string
name = optional(string) # Will fall back to use map key
operations = list(string)
retire_on_delete = optional(bool)
retiring_principal = optional(string)
}))
| `null` | no | | [is\_enabled](#input\_is\_enabled) | Specifies whether the key is enabled. Defaults to `true` | `bool` | `null` | no | | [key\_administrators](#input\_key\_administrators) | A list of IAM ARNs for [key administrators](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-administrators) | `list(string)` | `[]` | no | | [key\_asymmetric\_public\_encryption\_users](#input\_key\_asymmetric\_public\_encryption\_users) | A list of IAM ARNs for [key asymmetric public encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | @@ -202,7 +202,7 @@ No modules. | [key\_owners](#input\_key\_owners) | A list of IAM ARNs for those who will have full key permissions (`kms:*`) | `list(string)` | `[]` | no | | [key\_service\_roles\_for\_autoscaling](#input\_key\_service\_roles\_for\_autoscaling) | A list of IAM ARNs for [AWSServiceRoleForAutoScaling roles](https://docs.aws.amazon.com/autoscaling/ec2/userguide/key-policy-requirements-EBS-encryption.html#policy-example-cmk-access) | `list(string)` | `[]` | no | | [key\_service\_users](#input\_key\_service\_users) | A list of IAM ARNs for [key service users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-service-integration) | `list(string)` | `[]` | no | -| [key\_statements](#input\_key\_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 | `any` | `{}` | no | +| [key\_statements](#input\_key\_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 | | [key\_symmetric\_encryption\_users](#input\_key\_symmetric\_encryption\_users) | A list of IAM ARNs for [key symmetric encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | | [key\_usage](#input\_key\_usage) | Specifies the intended use of the key. Valid values: `ENCRYPT_DECRYPT` or `SIGN_VERIFY`. Defaults to `ENCRYPT_DECRYPT` | `string` | `null` | no | | [key\_users](#input\_key\_users) | A list of IAM ARNs for [key users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-users) | `list(string)` | `[]` | no | @@ -211,9 +211,9 @@ No modules. | [policy](#input\_policy) | A valid policy JSON document. Although this is a key policy, not an IAM policy, an `aws_iam_policy_document`, in the form that designates a principal, can be used | `string` | `null` | no | | [primary\_external\_key\_arn](#input\_primary\_external\_key\_arn) | The primary external key arn of a multi-region replica external key | `string` | `null` | no | | [primary\_key\_arn](#input\_primary\_key\_arn) | The primary key arn of a multi-region replica key | `string` | `null` | no | -| [region](#input\_region) | (Optional) The Region where the resources will be managed. Defaults to the region set in the provider configuration. | `string` | `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 | | [rotation\_period\_in\_days](#input\_rotation\_period\_in\_days) | Custom period of time between each rotation date. Must be a number between 90 and 2560 (inclusive) | `number` | `null` | no | -| [route53\_dnssec\_sources](#input\_route53\_dnssec\_sources) | A list of maps containing `account_ids` and Route53 `hosted_zone_arn` that will be allowed to sign DNSSEC records | `list(any)` | `[]` | no | +| [route53\_dnssec\_sources](#input\_route53\_dnssec\_sources) | A list of maps containing `account_ids` and Route53 `hosted_zone_arn` that will be allowed to sign DNSSEC records |
list(object({
account_ids = optional(list(string))
hosted_zone_arn = optional(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 | | [valid\_to](#input\_valid\_to) | Time at which the imported key material expires. When the key material expires, AWS KMS deletes the key material and the CMK becomes unusable. If not specified, key material does not expire | `string` | `null` | no | diff --git a/main.tf b/main.tf index 17b959a..77e3eb8 100644 --- a/main.tf +++ b/main.tf @@ -387,40 +387,40 @@ data "aws_iam_policy_document" "this" { } dynamic "condition" { - for_each = var.route53_dnssec_sources + for_each = var.route53_dnssec_sources != null ? var.route53_dnssec_sources : [] content { test = "StringEquals" variable = "aws:SourceAccount" - values = try(condition.value.account_ids, [local.account_id]) + values = coalescelist(condition.value.account_ids, [local.account_id]) } } dynamic "condition" { - for_each = var.route53_dnssec_sources + for_each = var.route53_dnssec_sources != null ? var.route53_dnssec_sources : [] content { test = "ArnLike" variable = "aws:SourceArn" - values = [try(condition.value.hosted_zone_arn, "arn:${local.partition}:route53:::hostedzone/*")] + values = [coalesce(condition.value.hosted_zone_arn, "arn:${local.partition}:route53:::hostedzone/*")] } } } } dynamic "statement" { - for_each = var.key_statements + for_each = var.key_statements != null ? var.key_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 @@ -429,7 +429,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 @@ -438,7 +438,7 @@ data "aws_iam_policy_document" "this" { } dynamic "condition" { - for_each = try(statement.value.conditions, []) + for_each = statement.value.conditions != null ? statement.value.conditions : [] content { test = condition.value.test @@ -473,25 +473,24 @@ resource "aws_kms_alias" "this" { ################################################################################ resource "aws_kms_grant" "this" { - for_each = { for k, v in var.grants : k => v if var.create } + for_each = var.create && var.grants != null ? var.grants : {} region = var.region - name = try(each.value.name, each.key) - key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) - grantee_principal = each.value.grantee_principal - operations = each.value.operations - dynamic "constraints" { - for_each = length(lookup(each.value, "constraints", {})) == 0 ? [] : [each.value.constraints] + for_each = each.value.constraints != null ? each.value.constraints : [] content { - encryption_context_equals = try(constraints.value.encryption_context_equals, null) - encryption_context_subset = try(constraints.value.encryption_context_subset, null) + encryption_context_equals = constraints.value.encryption_context_equals + encryption_context_subset = constraints.value.encryption_context_subset } } - retiring_principal = try(each.value.retiring_principal, null) - grant_creation_tokens = try(each.value.grant_creation_tokens, null) - retire_on_delete = try(each.value.retire_on_delete, null) + grant_creation_tokens = each.value.grant_creation_tokens + grantee_principal = each.value.grantee_principal + key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) + name = coalesce(each.value.name, each.key) + operations = each.value.operations + retire_on_delete = each.value.retire_on_delete + retiring_principal = each.value.retiring_principal } diff --git a/variables.tf b/variables.tf index bfe0fe1..dac0de2 100644 --- a/variables.tf +++ b/variables.tf @@ -5,7 +5,7 @@ variable "create" { } variable "region" { - description = "(Optional) The Region where the resources will be managed. Defaults to the region set in the provider configuration." + description = "Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration" type = string default = null } @@ -160,8 +160,28 @@ variable "key_asymmetric_sign_verify_users" { variable "key_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 = 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 "source_policy_documents" { @@ -184,8 +204,11 @@ variable "enable_route53_dnssec" { variable "route53_dnssec_sources" { description = "A list of maps containing `account_ids` and Route53 `hosted_zone_arn` that will be allowed to sign DNSSEC records" - type = list(any) - default = [] + type = list(object({ + account_ids = optional(list(string)) + hosted_zone_arn = optional(string) + })) + default = null } variable "rotation_period_in_days" { @@ -238,8 +261,10 @@ variable "aliases" { variable "computed_aliases" { description = "A map of aliases to create. Values provided via the `name` key of the map can be computed from upstream resources" - type = any - default = {} + type = map(object({ + name = string + })) + default = {} } variable "aliases_use_name_prefix" { @@ -254,6 +279,17 @@ variable "aliases_use_name_prefix" { variable "grants" { description = "A map of grant definitions to create" - type = any - default = {} + type = map(object({ + constraints = optional(object({ + encryption_context_equals = optional(map(string)) + encryption_context_subset = optional(map(string)) + })) + grant_creation_tokens = optional(string) + grantee_principal = string + name = optional(string) # Will fall back to use map key + operations = list(string) + retire_on_delete = optional(bool) + retiring_principal = optional(string) + })) + default = null } diff --git a/wrappers/main.tf b/wrappers/main.tf index 5a7cb3d..2a5e231 100644 --- a/wrappers/main.tf +++ b/wrappers/main.tf @@ -18,7 +18,7 @@ module "wrapper" { enable_default_policy = try(each.value.enable_default_policy, var.defaults.enable_default_policy, true) enable_key_rotation = try(each.value.enable_key_rotation, var.defaults.enable_key_rotation, true) enable_route53_dnssec = try(each.value.enable_route53_dnssec, var.defaults.enable_route53_dnssec, false) - grants = try(each.value.grants, var.defaults.grants, {}) + grants = try(each.value.grants, var.defaults.grants, null) is_enabled = try(each.value.is_enabled, var.defaults.is_enabled, null) key_administrators = try(each.value.key_administrators, var.defaults.key_administrators, []) key_asymmetric_public_encryption_users = try(each.value.key_asymmetric_public_encryption_users, var.defaults.key_asymmetric_public_encryption_users, []) @@ -28,7 +28,7 @@ module "wrapper" { key_owners = try(each.value.key_owners, var.defaults.key_owners, []) key_service_roles_for_autoscaling = try(each.value.key_service_roles_for_autoscaling, var.defaults.key_service_roles_for_autoscaling, []) key_service_users = try(each.value.key_service_users, var.defaults.key_service_users, []) - key_statements = try(each.value.key_statements, var.defaults.key_statements, {}) + key_statements = try(each.value.key_statements, var.defaults.key_statements, null) key_symmetric_encryption_users = try(each.value.key_symmetric_encryption_users, var.defaults.key_symmetric_encryption_users, []) key_usage = try(each.value.key_usage, var.defaults.key_usage, null) key_users = try(each.value.key_users, var.defaults.key_users, []) @@ -39,7 +39,7 @@ module "wrapper" { primary_key_arn = try(each.value.primary_key_arn, var.defaults.primary_key_arn, null) region = try(each.value.region, var.defaults.region, null) rotation_period_in_days = try(each.value.rotation_period_in_days, var.defaults.rotation_period_in_days, null) - route53_dnssec_sources = try(each.value.route53_dnssec_sources, var.defaults.route53_dnssec_sources, []) + route53_dnssec_sources = try(each.value.route53_dnssec_sources, var.defaults.route53_dnssec_sources, null) source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) tags = try(each.value.tags, var.defaults.tags, {}) valid_to = try(each.value.valid_to, var.defaults.valid_to, null) From 4d85ad84ab0e35353153242d3b1402dd7e33243f Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sat, 5 Jul 2025 11:18:13 -0500 Subject: [PATCH 8/8] chore: Updates from testing --- README.md | 2 +- examples/complete/main.tf | 41 ++++++++++++++++-------------------- examples/complete/outputs.tf | 7 ++++-- main.tf | 2 +- variables.tf | 6 +++--- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 67368a6..e2f734e 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ No modules. | [enable\_default\_policy](#input\_enable\_default\_policy) | Specifies whether to enable the default key policy. Defaults to `true` | `bool` | `true` | no | | [enable\_key\_rotation](#input\_enable\_key\_rotation) | Specifies whether key rotation is enabled. Defaults to `true` | `bool` | `true` | no | | [enable\_route53\_dnssec](#input\_enable\_route53\_dnssec) | Determines whether the KMS policy used for Route53 DNSSEC signing is enabled | `bool` | `false` | no | -| [grants](#input\_grants) | A map of grant definitions to create |
map(object({
constraints = optional(object({
encryption_context_equals = optional(map(string))
encryption_context_subset = optional(map(string))
}))
grant_creation_tokens = optional(string)
grantee_principal = string
name = optional(string) # Will fall back to use map key
operations = list(string)
retire_on_delete = optional(bool)
retiring_principal = optional(string)
}))
| `null` | no | +| [grants](#input\_grants) | A map of grant definitions to create |
map(object({
constraints = optional(list(object({
encryption_context_equals = optional(map(string))
encryption_context_subset = optional(map(string))
})))
grant_creation_tokens = optional(list(string))
grantee_principal = string
name = optional(string) # Will fall back to use map key
operations = list(string)
retire_on_delete = optional(bool)
retiring_principal = optional(string)
}))
| `null` | no | | [is\_enabled](#input\_is\_enabled) | Specifies whether the key is enabled. Defaults to `true` | `bool` | `null` | no | | [key\_administrators](#input\_key\_administrators) | A list of IAM ARNs for [key administrators](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-administrators) | `list(string)` | `[]` | no | | [key\_asymmetric\_public\_encryption\_users](#input\_key\_asymmetric\_public\_encryption\_users) | A list of IAM ARNs for [key asymmetric public encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 366e0c4..34b5c40 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -5,12 +5,16 @@ provider "aws" { data "aws_caller_identity" "current" {} locals { - region = "us-east-1" - name = "kms-ex-${basename(path.cwd)}" + region = "us-east-1" + region_secondary = "eu-west-1" + name = "kms-ex-${basename(path.cwd)}" account_id = data.aws_caller_identity.current.account_id current_identity = data.aws_caller_identity.current.arn + # Removes noise from hh:mm:ss in the timestamp + valid_to = replace(timeadd(plantimestamp(), "4380h"), "/T.*/", "T00:00:00Z") # 6 months + tags = { Name = local.name Example = "complete" @@ -62,7 +66,7 @@ module "kms_complete" { } ] - conditions = [ + condition = [ { test = "ArnLike" variable = "kms:EncryptionContext:aws:logs:arn" @@ -93,11 +97,11 @@ module "kms_complete" { lambda = { grantee_principal = aws_iam_role.lambda.arn operations = ["Encrypt", "Decrypt", "GenerateDataKey"] - constraints = { + constraints = [{ encryption_context_equals = { Department = "Finance" } - } + }] } } @@ -113,7 +117,7 @@ module "kms_external" { is_enabled = true key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" multi_region = false - valid_to = "2023-11-21T23:20:50Z" + valid_to = local.valid_to tags = local.tags } @@ -171,17 +175,10 @@ module "kms_primary" { tags = local.tags } -provider "aws" { - region = "eu-west-1" - alias = "replica" -} - module "kms_replica" { source = "../.." - providers = { - aws = aws.replica - } + region = local.region_secondary deletion_window_in_days = 7 description = "Replica key example showing various configurations available" @@ -211,11 +208,11 @@ module "kms_replica" { lambda = { grantee_principal = aws_iam_role.lambda.arn operations = ["Encrypt", "Decrypt", "GenerateDataKey"] - constraints = { + constraints = [{ encryption_context_equals = { Department = "Finance" } - } + }] } } @@ -235,7 +232,7 @@ module "kms_primary_external" { create_external = true key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" multi_region = true - valid_to = "2023-11-21T23:20:50Z" + valid_to = local.valid_to aliases = ["primary-external"] @@ -245,9 +242,7 @@ module "kms_primary_external" { module "kms_replica_external" { source = "../.." - providers = { - aws = aws.replica - } + region = local.region_secondary deletion_window_in_days = 7 description = "Replica external key example showing various configurations available" @@ -256,7 +251,7 @@ module "kms_replica_external" { # key material must be the same as the primary's key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" primary_external_key_arn = module.kms_primary_external.key_arn - valid_to = "2023-11-21T23:20:50Z" + valid_to = local.valid_to aliases = ["replica-external"] @@ -265,11 +260,11 @@ module "kms_replica_external" { lambda = { grantee_principal = aws_iam_role.lambda.arn operations = ["Encrypt", "Decrypt", "GenerateDataKey"] - constraints = { + constraints = [{ encryption_context_equals = { Department = "Finance" } - } + }] } } diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index a2edbf6..ee5047e 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -40,6 +40,7 @@ output "complete_aliases" { output "complete_grants" { description = "A map of grants created and their attributes" value = module.kms_complete.grants + sensitive = true } ################################################################################ @@ -84,6 +85,7 @@ output "external_aliases" { output "external_grants" { description = "A map of grants created and their attributes" value = module.kms_external.grants + sensitive = true } ################################################################################ @@ -128,9 +130,9 @@ output "default_aliases" { output "default_grants" { description = "A map of grants created and their attributes" value = module.kms_default.grants + sensitive = true } - ################################################################################ # Replica ################################################################################ @@ -173,9 +175,9 @@ output "replica_aliases" { output "replica_grants" { description = "A map of grants created and their attributes" value = module.kms_replica.grants + sensitive = true } - ################################################################################ # Replica External ################################################################################ @@ -218,4 +220,5 @@ output "replica_external_aliases" { output "replica_external_grants" { description = "A map of grants created and their attributes" value = module.kms_replica_external.grants + sensitive = true } diff --git a/main.tf b/main.tf index 77e3eb8..e724cb8 100644 --- a/main.tf +++ b/main.tf @@ -438,7 +438,7 @@ data "aws_iam_policy_document" "this" { } dynamic "condition" { - for_each = statement.value.conditions != null ? statement.value.conditions : [] + for_each = statement.value.condition != null ? statement.value.condition : [] content { test = condition.value.test diff --git a/variables.tf b/variables.tf index dac0de2..60e7983 100644 --- a/variables.tf +++ b/variables.tf @@ -280,11 +280,11 @@ variable "aliases_use_name_prefix" { variable "grants" { description = "A map of grant definitions to create" type = map(object({ - constraints = optional(object({ + constraints = optional(list(object({ encryption_context_equals = optional(map(string)) encryption_context_subset = optional(map(string)) - })) - grant_creation_tokens = optional(string) + }))) + grant_creation_tokens = optional(list(string)) grantee_principal = string name = optional(string) # Will fall back to use map key operations = list(string)