Skip to content

Commit

Permalink
feat: Support adding KMS replica keys (#9)
Browse files Browse the repository at this point in the history
* adding kms replica keys

* adding further example parameters

* format

* adjusting comments in example

* variable description adjustments and typo fix

* adjusting readme

* fix external key examples, add outputs, adjust conditional to use try function

* reorder variables

* dnssec signing cant have rotation enabled

---------

Co-authored-by: magreenbaum <magreenbaum>
Co-authored-by: Bryant Biggs <[email protected]>
  • Loading branch information
magreenbaum and bryantbiggs authored Jan 28, 2023
1 parent 9b1cd43 commit 9a7080b
Show file tree
Hide file tree
Showing 7 changed files with 321 additions and 11 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ No modules.
| [aws_kms_external_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_external_key) | resource |
| [aws_kms_grant.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_grant) | resource |
| [aws_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
| [aws_kms_replica_external_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_external_key) | resource |
| [aws_kms_replica_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_key) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
Expand All @@ -182,6 +184,8 @@ No modules.
| <a name="input_computed_aliases"></a> [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 |
| <a name="input_create"></a> [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no |
| <a name="input_create_external"></a> [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 |
| <a name="input_create_replica"></a> [create\_replica](#input\_create\_replica) | Determines whether a replica standard CMK will be created (AWS provided material) | `bool` | `false` | no |
| <a name="input_create_replica_external"></a> [create\_replica\_external](#input\_create\_replica\_external) | Determines whether a replica external CMK will be created (externally provided material) | `bool` | `false` | no |
| <a name="input_customer_master_key_spec"></a> [customer\_master\_key\_spec](#input\_customer\_master\_key\_spec) | Specifies whether the key contains a symmetric key or an asymmetric key pair and the encryption algorithms or signing algorithms that the key supports. Valid values: `SYMMETRIC_DEFAULT`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `HMAC_256`, `ECC_NIST_P256`, `ECC_NIST_P384`, `ECC_NIST_P521`, or `ECC_SECG_P256K1`. Defaults to `SYMMETRIC_DEFAULT` | `string` | `null` | no |
| <a name="input_deletion_window_in_days"></a> [deletion\_window\_in\_days](#input\_deletion\_window\_in\_days) | The waiting period, specified in number of days. After the waiting period ends, AWS KMS deletes the KMS key. If you specify a value, it must be between `7` and `30`, inclusive. If you do not specify a value, it defaults to `30` | `number` | `null` | no |
| <a name="input_description"></a> [description](#input\_description) | The description of the key as viewed in AWS console | `string` | `null` | no |
Expand All @@ -204,6 +208,8 @@ No modules.
| <a name="input_multi_region"></a> [multi\_region](#input\_multi\_region) | Indicates whether the KMS key is a multi-Region (`true`) or regional (`false`) key. Defaults to `false` | `bool` | `false` | no |
| <a name="input_override_policy_documents"></a> [override\_policy\_documents](#input\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no |
| <a name="input_policy"></a> [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 |
| <a name="input_primary_external_key_arn"></a> [primary\_external\_key\_arn](#input\_primary\_external\_key\_arn) | The primary external key arn of a multi-region replica external key | `string` | `null` | no |
| <a name="input_primary_key_arn"></a> [primary\_key\_arn](#input\_primary\_key\_arn) | The primary key arn of a multi-region replica key | `string` | `null` | no |
| <a name="input_route53_dnssec_sources"></a> [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 |
| <a name="input_source_policy_documents"></a> [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 |
| <a name="input_tags"></a> [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no |
Expand Down
20 changes: 20 additions & 0 deletions examples/complete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ Note that this example may create resources which will incur monetary charges on
| <a name="module_kms_disabled"></a> [kms\_disabled](#module\_kms\_disabled) | ../.. | n/a |
| <a name="module_kms_dnssec_signing"></a> [kms\_dnssec\_signing](#module\_kms\_dnssec\_signing) | ../.. | n/a |
| <a name="module_kms_external"></a> [kms\_external](#module\_kms\_external) | ../.. | n/a |
| <a name="module_kms_primary"></a> [kms\_primary](#module\_kms\_primary) | ../.. | n/a |
| <a name="module_kms_primary_external"></a> [kms\_primary\_external](#module\_kms\_primary\_external) | ../.. | n/a |
| <a name="module_kms_replica"></a> [kms\_replica](#module\_kms\_replica) | ../.. | n/a |
| <a name="module_kms_replica_external"></a> [kms\_replica\_external](#module\_kms\_replica\_external) | ../.. | n/a |

## Resources

Expand Down Expand Up @@ -83,6 +87,22 @@ No inputs.
| <a name="output_external_key_arn"></a> [external\_key\_arn](#output\_external\_key\_arn) | The Amazon Resource Name (ARN) of the key |
| <a name="output_external_key_id"></a> [external\_key\_id](#output\_external\_key\_id) | The globally unique identifier for the key |
| <a name="output_external_key_policy"></a> [external\_key\_policy](#output\_external\_key\_policy) | The IAM resource policy set on the key |
| <a name="output_replica_aliases"></a> [replica\_aliases](#output\_replica\_aliases) | A map of aliases created and their attributes |
| <a name="output_replica_external_aliases"></a> [replica\_external\_aliases](#output\_replica\_external\_aliases) | A map of aliases created and their attributes |
| <a name="output_replica_external_arn"></a> [replica\_external\_arn](#output\_replica\_external\_arn) | The Amazon Resource Name (ARN) of the key |
| <a name="output_replica_external_grants"></a> [replica\_external\_grants](#output\_replica\_external\_grants) | A map of grants created and their attributes |
| <a name="output_replica_external_key_expiration_model"></a> [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` |
| <a name="output_replica_external_key_id"></a> [replica\_external\_key\_id](#output\_replica\_external\_key\_id) | The globally unique identifier for the key |
| <a name="output_replica_external_key_policy"></a> [replica\_external\_key\_policy](#output\_replica\_external\_key\_policy) | The IAM resource policy set on the key |
| <a name="output_replica_external_key_state"></a> [replica\_external\_key\_state](#output\_replica\_external\_key\_state) | The state of the CMK |
| <a name="output_replica_external_key_usage"></a> [replica\_external\_key\_usage](#output\_replica\_external\_key\_usage) | The cryptographic operations for which you can use the CMK |
| <a name="output_replica_grants"></a> [replica\_grants](#output\_replica\_grants) | A map of grants created and their attributes |
| <a name="output_replica_key_arn"></a> [replica\_key\_arn](#output\_replica\_key\_arn) | The Amazon Resource Name (ARN) of the key |
| <a name="output_replica_key_expiration_model"></a> [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` |
| <a name="output_replica_key_id"></a> [replica\_key\_id](#output\_replica\_key\_id) | The globally unique identifier for the key |
| <a name="output_replica_key_policy"></a> [replica\_key\_policy](#output\_replica\_key\_policy) | The IAM resource policy set on the key |
| <a name="output_replica_key_state"></a> [replica\_key\_state](#output\_replica\_key\_state) | The state of the CMK |
| <a name="output_replica_key_usage"></a> [replica\_key\_usage](#output\_replica\_key\_usage) | The cryptographic operations for which you can use the CMK |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-kms/blob/master/LICENSE).
128 changes: 127 additions & 1 deletion examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,11 @@ module "kms_external" {

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 = "2085-04-12T23:20:50.52Z"
valid_to = "2023-11-21T23:20:50Z"

tags = local.tags
}
Expand All @@ -124,6 +125,7 @@ module "kms_dnssec_signing" {
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
Expand All @@ -148,6 +150,130 @@ module "kms_disabled" {
create = false
}

################################################################################
# Replica Key Example
################################################################################

module "kms_primary" {
source = "../.."

deletion_window_in_days = 7
description = "Primary key of replica key example"
enable_key_rotation = false
is_enabled = true
key_usage = "ENCRYPT_DECRYPT"
multi_region = true

aliases = ["primary-standard"]

tags = local.tags
}

provider "aws" {
region = "eu-west-1"
alias = "replica"
}

module "kms_replica" {
source = "../.."

deletion_window_in_days = 7
description = "Replica key example showing various configurations available"
create_replica = true
primary_key_arn = module.kms_primary.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"]
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"
}
}
}
}

tags = local.tags

providers = {
aws = aws.replica
}
}

################################################################################
# Replica External Key Example
################################################################################

module "kms_primary_external" {
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="
multi_region = true
valid_to = "2023-11-21T23:20:50Z"

aliases = ["primary-external"]

tags = local.tags
}

module "kms_replica_external" {
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.key_arn
valid_to = "2023-11-21T23:20:50Z"

aliases = ["replica-external"]

# Grants
grants = {
lambda = {
grantee_principal = aws_iam_role.lambda.arn
operations = ["Encrypt", "Decrypt", "GenerateDataKey"]
constraints = {
encryption_context_equals = {
Department = "Finance"
}
}
}
}

tags = local.tags

providers = {
aws = aws.replica
}
}

################################################################################
# Supporting Resources
################################################################################
Expand Down
90 changes: 90 additions & 0 deletions examples/complete/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,93 @@ output "default_grants" {
description = "A map of grants created and their attributes"
value = module.kms_default.grants
}


################################################################################
# Replica
################################################################################

output "replica_key_arn" {
description = "The Amazon Resource Name (ARN) of the key"
value = module.kms_replica.key_arn
}

output "replica_key_id" {
description = "The globally unique identifier for the key"
value = module.kms_replica.key_id
}

output "replica_key_policy" {
description = "The IAM resource policy set on the key"
value = module.kms_replica.key_policy
}

output "replica_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.external_key_expiration_model
}

output "replica_key_state" {
description = "The state of the CMK"
value = module.kms_replica.external_key_state
}

output "replica_key_usage" {
description = "The cryptographic operations for which you can use the CMK"
value = module.kms_replica.external_key_usage
}

output "replica_aliases" {
description = "A map of aliases created and their attributes"
value = module.kms_replica.aliases
}

output "replica_grants" {
description = "A map of grants created and their attributes"
value = module.kms_replica.grants
}


################################################################################
# Replica External
################################################################################

output "replica_external_arn" {
description = "The Amazon Resource Name (ARN) of the key"
value = module.kms_replica_external.key_arn
}

output "replica_external_key_id" {
description = "The globally unique identifier for the key"
value = module.kms_replica_external.key_id
}

output "replica_external_key_policy" {
description = "The IAM resource policy set on the key"
value = module.kms_replica_external.key_policy
}

output "replica_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_external.external_key_expiration_model
}

output "replica_external_key_state" {
description = "The state of the CMK"
value = module.kms_replica_external.external_key_state
}

output "replica_external_key_usage" {
description = "The cryptographic operations for which you can use the CMK"
value = module.kms_replica_external.external_key_usage
}

output "replica_external_aliases" {
description = "A map of aliases created and their attributes"
value = module.kms_replica_external.aliases
}

output "replica_external_grants" {
description = "A map of grants created and their attributes"
value = module.kms_replica_external.grants
}
Loading

0 comments on commit 9a7080b

Please sign in to comment.