Skip to content

Commit 9a7080b

Browse files
feat: Support adding KMS replica keys (#9)
* 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 <bryantbiggs@gmail.com>
1 parent 9b1cd43 commit 9a7080b

File tree

7 files changed

+321
-11
lines changed

7 files changed

+321
-11
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ No modules.
168168
| [aws_kms_external_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_external_key) | resource |
169169
| [aws_kms_grant.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_grant) | resource |
170170
| [aws_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
171+
| [aws_kms_replica_external_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_external_key) | resource |
172+
| [aws_kms_replica_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_key) | resource |
171173
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
172174
| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
173175
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
@@ -182,6 +184,8 @@ No modules.
182184
| <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 |
183185
| <a name="input_create"></a> [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no |
184186
| <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 |
187+
| <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 |
188+
| <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 |
185189
| <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 |
186190
| <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 |
187191
| <a name="input_description"></a> [description](#input\_description) | The description of the key as viewed in AWS console | `string` | `null` | no |
@@ -204,6 +208,8 @@ No modules.
204208
| <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 |
205209
| <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 |
206210
| <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 |
211+
| <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 |
212+
| <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 |
207213
| <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 |
208214
| <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 |
209215
| <a name="input_tags"></a> [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no |

examples/complete/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ Note that this example may create resources which will incur monetary charges on
4242
| <a name="module_kms_disabled"></a> [kms\_disabled](#module\_kms\_disabled) | ../.. | n/a |
4343
| <a name="module_kms_dnssec_signing"></a> [kms\_dnssec\_signing](#module\_kms\_dnssec\_signing) | ../.. | n/a |
4444
| <a name="module_kms_external"></a> [kms\_external](#module\_kms\_external) | ../.. | n/a |
45+
| <a name="module_kms_primary"></a> [kms\_primary](#module\_kms\_primary) | ../.. | n/a |
46+
| <a name="module_kms_primary_external"></a> [kms\_primary\_external](#module\_kms\_primary\_external) | ../.. | n/a |
47+
| <a name="module_kms_replica"></a> [kms\_replica](#module\_kms\_replica) | ../.. | n/a |
48+
| <a name="module_kms_replica_external"></a> [kms\_replica\_external](#module\_kms\_replica\_external) | ../.. | n/a |
4549

4650
## Resources
4751

@@ -83,6 +87,22 @@ No inputs.
8387
| <a name="output_external_key_arn"></a> [external\_key\_arn](#output\_external\_key\_arn) | The Amazon Resource Name (ARN) of the key |
8488
| <a name="output_external_key_id"></a> [external\_key\_id](#output\_external\_key\_id) | The globally unique identifier for the key |
8589
| <a name="output_external_key_policy"></a> [external\_key\_policy](#output\_external\_key\_policy) | The IAM resource policy set on the key |
90+
| <a name="output_replica_aliases"></a> [replica\_aliases](#output\_replica\_aliases) | A map of aliases created and their attributes |
91+
| <a name="output_replica_external_aliases"></a> [replica\_external\_aliases](#output\_replica\_external\_aliases) | A map of aliases created and their attributes |
92+
| <a name="output_replica_external_arn"></a> [replica\_external\_arn](#output\_replica\_external\_arn) | The Amazon Resource Name (ARN) of the key |
93+
| <a name="output_replica_external_grants"></a> [replica\_external\_grants](#output\_replica\_external\_grants) | A map of grants created and their attributes |
94+
| <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` |
95+
| <a name="output_replica_external_key_id"></a> [replica\_external\_key\_id](#output\_replica\_external\_key\_id) | The globally unique identifier for the key |
96+
| <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 |
97+
| <a name="output_replica_external_key_state"></a> [replica\_external\_key\_state](#output\_replica\_external\_key\_state) | The state of the CMK |
98+
| <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 |
99+
| <a name="output_replica_grants"></a> [replica\_grants](#output\_replica\_grants) | A map of grants created and their attributes |
100+
| <a name="output_replica_key_arn"></a> [replica\_key\_arn](#output\_replica\_key\_arn) | The Amazon Resource Name (ARN) of the key |
101+
| <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` |
102+
| <a name="output_replica_key_id"></a> [replica\_key\_id](#output\_replica\_key\_id) | The globally unique identifier for the key |
103+
| <a name="output_replica_key_policy"></a> [replica\_key\_policy](#output\_replica\_key\_policy) | The IAM resource policy set on the key |
104+
| <a name="output_replica_key_state"></a> [replica\_key\_state](#output\_replica\_key\_state) | The state of the CMK |
105+
| <a name="output_replica_key_usage"></a> [replica\_key\_usage](#output\_replica\_key\_usage) | The cryptographic operations for which you can use the CMK |
86106
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
87107

88108
Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-kms/blob/master/LICENSE).

examples/complete/main.tf

+127-1
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,11 @@ module "kms_external" {
107107

108108
deletion_window_in_days = 7
109109
description = "External key example"
110+
create_external = true
110111
is_enabled = true
111112
key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY="
112113
multi_region = false
113-
valid_to = "2085-04-12T23:20:50.52Z"
114+
valid_to = "2023-11-21T23:20:50Z"
114115

115116
tags = local.tags
116117
}
@@ -124,6 +125,7 @@ module "kms_dnssec_signing" {
124125
customer_master_key_spec = "ECC_NIST_P256"
125126

126127
enable_route53_dnssec = true
128+
enable_key_rotation = false
127129
route53_dnssec_sources = [
128130
{
129131
accounts_ids = [data.aws_caller_identity.current.account_id] # can ommit if using current account ID which is default
@@ -148,6 +150,130 @@ module "kms_disabled" {
148150
create = false
149151
}
150152

153+
################################################################################
154+
# Replica Key Example
155+
################################################################################
156+
157+
module "kms_primary" {
158+
source = "../.."
159+
160+
deletion_window_in_days = 7
161+
description = "Primary key of replica key example"
162+
enable_key_rotation = false
163+
is_enabled = true
164+
key_usage = "ENCRYPT_DECRYPT"
165+
multi_region = true
166+
167+
aliases = ["primary-standard"]
168+
169+
tags = local.tags
170+
}
171+
172+
provider "aws" {
173+
region = "eu-west-1"
174+
alias = "replica"
175+
}
176+
177+
module "kms_replica" {
178+
source = "../.."
179+
180+
deletion_window_in_days = 7
181+
description = "Replica key example showing various configurations available"
182+
create_replica = true
183+
primary_key_arn = module.kms_primary.key_arn
184+
enable_default_policy = true
185+
186+
key_owners = [local.current_identity]
187+
key_administrators = [local.current_identity]
188+
key_users = [local.current_identity]
189+
190+
# Aliases
191+
aliases = ["replica-standard"]
192+
computed_aliases = {
193+
ex = {
194+
# Sometimes you want to pass in an upstream attribute as the name and
195+
# that conflicts with using `for_each over a `toset()` since the value is not
196+
# known until after applying. Instead, we can use `computed_aliases` to work
197+
# around this limitation
198+
# Reference: https://github.com/hashicorp/terraform/issues/30937
199+
name = aws_iam_role.lambda.name
200+
}
201+
}
202+
203+
# Grants
204+
grants = {
205+
lambda = {
206+
grantee_principal = aws_iam_role.lambda.arn
207+
operations = ["Encrypt", "Decrypt", "GenerateDataKey"]
208+
constraints = {
209+
encryption_context_equals = {
210+
Department = "Finance"
211+
}
212+
}
213+
}
214+
}
215+
216+
tags = local.tags
217+
218+
providers = {
219+
aws = aws.replica
220+
}
221+
}
222+
223+
################################################################################
224+
# Replica External Key Example
225+
################################################################################
226+
227+
module "kms_primary_external" {
228+
source = "../.."
229+
230+
deletion_window_in_days = 7
231+
description = "Primary external key of replica external key example"
232+
is_enabled = true
233+
create_external = true
234+
key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY="
235+
multi_region = true
236+
valid_to = "2023-11-21T23:20:50Z"
237+
238+
aliases = ["primary-external"]
239+
240+
tags = local.tags
241+
}
242+
243+
module "kms_replica_external" {
244+
source = "../.."
245+
246+
deletion_window_in_days = 7
247+
description = "Replica external key example showing various configurations available"
248+
create_replica_external = true
249+
is_enabled = true
250+
# key material must be the same as the primary's
251+
key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY="
252+
primary_external_key_arn = module.kms_primary_external.key_arn
253+
valid_to = "2023-11-21T23:20:50Z"
254+
255+
aliases = ["replica-external"]
256+
257+
# Grants
258+
grants = {
259+
lambda = {
260+
grantee_principal = aws_iam_role.lambda.arn
261+
operations = ["Encrypt", "Decrypt", "GenerateDataKey"]
262+
constraints = {
263+
encryption_context_equals = {
264+
Department = "Finance"
265+
}
266+
}
267+
}
268+
}
269+
270+
tags = local.tags
271+
272+
providers = {
273+
aws = aws.replica
274+
}
275+
}
276+
151277
################################################################################
152278
# Supporting Resources
153279
################################################################################

examples/complete/outputs.tf

+90
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,93 @@ output "default_grants" {
129129
description = "A map of grants created and their attributes"
130130
value = module.kms_default.grants
131131
}
132+
133+
134+
################################################################################
135+
# Replica
136+
################################################################################
137+
138+
output "replica_key_arn" {
139+
description = "The Amazon Resource Name (ARN) of the key"
140+
value = module.kms_replica.key_arn
141+
}
142+
143+
output "replica_key_id" {
144+
description = "The globally unique identifier for the key"
145+
value = module.kms_replica.key_id
146+
}
147+
148+
output "replica_key_policy" {
149+
description = "The IAM resource policy set on the key"
150+
value = module.kms_replica.key_policy
151+
}
152+
153+
output "replica_key_expiration_model" {
154+
description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`"
155+
value = module.kms_replica.external_key_expiration_model
156+
}
157+
158+
output "replica_key_state" {
159+
description = "The state of the CMK"
160+
value = module.kms_replica.external_key_state
161+
}
162+
163+
output "replica_key_usage" {
164+
description = "The cryptographic operations for which you can use the CMK"
165+
value = module.kms_replica.external_key_usage
166+
}
167+
168+
output "replica_aliases" {
169+
description = "A map of aliases created and their attributes"
170+
value = module.kms_replica.aliases
171+
}
172+
173+
output "replica_grants" {
174+
description = "A map of grants created and their attributes"
175+
value = module.kms_replica.grants
176+
}
177+
178+
179+
################################################################################
180+
# Replica External
181+
################################################################################
182+
183+
output "replica_external_arn" {
184+
description = "The Amazon Resource Name (ARN) of the key"
185+
value = module.kms_replica_external.key_arn
186+
}
187+
188+
output "replica_external_key_id" {
189+
description = "The globally unique identifier for the key"
190+
value = module.kms_replica_external.key_id
191+
}
192+
193+
output "replica_external_key_policy" {
194+
description = "The IAM resource policy set on the key"
195+
value = module.kms_replica_external.key_policy
196+
}
197+
198+
output "replica_external_key_expiration_model" {
199+
description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`"
200+
value = module.kms_replica_external.external_key_expiration_model
201+
}
202+
203+
output "replica_external_key_state" {
204+
description = "The state of the CMK"
205+
value = module.kms_replica_external.external_key_state
206+
}
207+
208+
output "replica_external_key_usage" {
209+
description = "The cryptographic operations for which you can use the CMK"
210+
value = module.kms_replica_external.external_key_usage
211+
}
212+
213+
output "replica_external_aliases" {
214+
description = "A map of aliases created and their attributes"
215+
value = module.kms_replica_external.aliases
216+
}
217+
218+
output "replica_external_grants" {
219+
description = "A map of grants created and their attributes"
220+
value = module.kms_replica_external.grants
221+
}

0 commit comments

Comments
 (0)