Skip to content

Commit

Permalink
feat: Add support for external key using externally provided material
Browse files Browse the repository at this point in the history
  • Loading branch information
bryantbiggs committed Jun 25, 2022
1 parent 5a01134 commit 2726c25
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 4 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ No modules.
| Name | Type |
|------|------|
| [aws_kms_alias.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
| [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_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
Expand All @@ -60,6 +61,7 @@ No modules.
| <a name="input_aliases_use_name_prefix"></a> [aliases\_use\_name\_prefix](#input\_aliases\_use\_name\_prefix) | Determines whether the alias name is used as a prefix | `bool` | `false` | no |
| <a name="input_bypass_policy_lockout_safety_check"></a> [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 |
| <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_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 @@ -71,6 +73,7 @@ No modules.
| <a name="input_key_asymmetric_public_encryption_users"></a> [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 |
| <a name="input_key_asymmetric_sign_verify_users"></a> [key\_asymmetric\_sign\_verify\_users](#input\_key\_asymmetric\_sign\_verify\_users) | A list of IAM ARNs for [key asymmetric sign and verify users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no |
| <a name="input_key_hmac_users"></a> [key\_hmac\_users](#input\_key\_hmac\_users) | A list of IAM ARNs for [key HMAC users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no |
| <a name="input_key_material_base64"></a> [key\_material\_base64](#input\_key\_material\_base64) | Base64 encoded 256-bit symmetric encryption key material to import. The CMK is permanently associated with this key material. External key only | `string` | `null` | no |
| <a name="input_key_owners"></a> [key\_owners](#input\_key\_owners) | A list of IAM ARNs for those who will have full key permissions (`kms:*`). `enable_default_policy` must be `true` to utilize | `list(string)` | `[]` | no |
| <a name="input_key_service_users"></a> [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 |
| <a name="input_key_symmetric_encryption_users"></a> [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 |
Expand All @@ -81,12 +84,16 @@ No modules.
| <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_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 |
| <a name="input_valid_to"></a> [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 |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_aliases"></a> [aliases](#output\_aliases) | A map of aliases created and their attributes |
| <a name="output_external_key_expiration_model"></a> [external\_key\_expiration\_model](#output\_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_external_key_state"></a> [external\_key\_state](#output\_external\_key\_state) | The state of the CMK |
| <a name="output_external_key_usage"></a> [external\_key\_usage](#output\_external\_key\_usage) | The cryptographic operations for which you can use the CMK |
| <a name="output_grants"></a> [grants](#output\_grants) | A map of grants created and their attributes |
| <a name="output_key_arn"></a> [key\_arn](#output\_key\_arn) | The Amazon Resource Name (ARN) of the key |
| <a name="output_key_id"></a> [key\_id](#output\_key\_id) | The globally unique identifier for the key |
Expand Down
15 changes: 15 additions & 0 deletions examples/complete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Note that this example may create resources which will incur monetary charges on
| <a name="module_kms_complete"></a> [kms\_complete](#module\_kms\_complete) | ../.. | n/a |
| <a name="module_kms_default"></a> [kms\_default](#module\_kms\_default) | ../.. | n/a |
| <a name="module_kms_disabled"></a> [kms\_disabled](#module\_kms\_disabled) | ../.. | n/a |
| <a name="module_kms_external"></a> [kms\_external](#module\_kms\_external) | ../.. | n/a |

## Resources

Expand All @@ -54,15 +55,29 @@ No inputs.
| Name | Description |
|------|-------------|
| <a name="output_complete_aliases"></a> [complete\_aliases](#output\_complete\_aliases) | A map of aliases created and their attributes |
| <a name="output_complete_external_key_expiration_model"></a> [complete\_external\_key\_expiration\_model](#output\_complete\_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_complete_external_key_state"></a> [complete\_external\_key\_state](#output\_complete\_external\_key\_state) | The state of the CMK |
| <a name="output_complete_external_key_usage"></a> [complete\_external\_key\_usage](#output\_complete\_external\_key\_usage) | The cryptographic operations for which you can use the CMK |
| <a name="output_complete_grants"></a> [complete\_grants](#output\_complete\_grants) | A map of grants created and their attributes |
| <a name="output_complete_key_arn"></a> [complete\_key\_arn](#output\_complete\_key\_arn) | The Amazon Resource Name (ARN) of the key |
| <a name="output_complete_key_id"></a> [complete\_key\_id](#output\_complete\_key\_id) | The globally unique identifier for the key |
| <a name="output_complete_key_policy"></a> [complete\_key\_policy](#output\_complete\_key\_policy) | The IAM resource policy set on the key |
| <a name="output_default_aliases"></a> [default\_aliases](#output\_default\_aliases) | A map of aliases created and their attributes |
| <a name="output_default_external_key_expiration_model"></a> [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` |
| <a name="output_default_external_key_state"></a> [default\_external\_key\_state](#output\_default\_external\_key\_state) | The state of the CMK |
| <a name="output_default_external_key_usage"></a> [default\_external\_key\_usage](#output\_default\_external\_key\_usage) | The cryptographic operations for which you can use the CMK |
| <a name="output_default_grants"></a> [default\_grants](#output\_default\_grants) | A map of grants created and their attributes |
| <a name="output_default_key_arn"></a> [default\_key\_arn](#output\_default\_key\_arn) | The Amazon Resource Name (ARN) of the key |
| <a name="output_default_key_id"></a> [default\_key\_id](#output\_default\_key\_id) | The globally unique identifier for the key |
| <a name="output_default_key_policy"></a> [default\_key\_policy](#output\_default\_key\_policy) | The IAM resource policy set on the key |
| <a name="output_external_aliases"></a> [external\_aliases](#output\_external\_aliases) | A map of aliases created and their attributes |
| <a name="output_external_external_key_expiration_model"></a> [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` |
| <a name="output_external_external_key_state"></a> [external\_external\_key\_state](#output\_external\_external\_key\_state) | The state of the CMK |
| <a name="output_external_external_key_usage"></a> [external\_external\_key\_usage](#output\_external\_external\_key\_usage) | The cryptographic operations for which you can use the CMK |
| <a name="output_external_grants"></a> [external\_grants](#output\_external\_grants) | A map of grants created and their attributes |
| <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 |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

Apache-2.0 Licensed. See [LICENSE](https://github.com/clowdhaus/terraform-aws-kms/blob/main/LICENSE).
13 changes: 13 additions & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ module "kms_complete" {
tags = local.tags
}

module "kms_external" {
source = "../.."

deletion_window_in_days = 7
description = "External key example"
is_enabled = true
key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY="
multi_region = false
valid_to = "2085-04-12T23:20:50.52Z"

tags = local.tags
}

module "kms_default" {
source = "../.."

Expand Down
74 changes: 74 additions & 0 deletions examples/complete/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ output "complete_key_policy" {
value = module.kms_complete.key_policy
}

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

output "complete_external_key_state" {
description = "The state of the CMK"
value = module.kms_complete.external_key_state
}

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

output "complete_aliases" {
description = "A map of aliases created and their attributes"
value = module.kms_complete.aliases
Expand All @@ -27,6 +42,50 @@ output "complete_grants" {
value = module.kms_complete.grants
}

################################################################################
# External
################################################################################

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

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

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

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

output "external_external_key_state" {
description = "The state of the CMK"
value = module.kms_external.external_key_state
}

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

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

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

################################################################################
# Default
################################################################################
Expand All @@ -46,6 +105,21 @@ output "default_key_policy" {
value = module.kms_default.key_policy
}

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

output "default_external_key_state" {
description = "The state of the CMK"
value = module.kms_default.external_key_state
}

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

output "default_aliases" {
description = "A map of aliases created and their attributes"
value = module.kms_default.aliases
Expand Down
25 changes: 24 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ data "aws_caller_identity" "current" {}
################################################################################

resource "aws_kms_key" "this" {
count = var.create ? 1 : 0
count = var.create && !var.create_external ? 1 : 0

bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check
customer_master_key_spec = var.customer_master_key_spec
Expand All @@ -21,6 +21,29 @@ resource "aws_kms_key" "this" {
tags = var.tags
}

################################################################################
# External Key
################################################################################

resource "aws_kms_external_key" "this" {
count = var.create && var.create_external ? 1 : 0

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
multi_region = var.multi_region
policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json)
valid_to = var.valid_to

tags = var.tags
}

################################################################################
# Policy
################################################################################

data "aws_iam_policy_document" "this" {
count = var.create ? 1 : 0

Expand Down
21 changes: 18 additions & 3 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,32 @@

output "key_arn" {
description = "The Amazon Resource Name (ARN) of the key"
value = try(aws_kms_key.this[0].arn, null)
value = try(aws_kms_key.this[0].arn, aws_kms_external_key.this[0].arn, null)
}

output "key_id" {
description = "The globally unique identifier for the key"
value = try(aws_kms_key.this[0].key_id, null)
value = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, null)
}

output "key_policy" {
description = "The IAM resource policy set on the key"
value = try(aws_kms_key.this[0].policy, null)
value = try(aws_kms_key.this[0].policy, aws_kms_external_key.this[0].policy, null)
}

output "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 = try(aws_kms_external_key.this[0].expiration_model, null)
}

output "external_key_state" {
description = "The state of the CMK"
value = try(aws_kms_external_key.this[0].key_state, null)
}

output "external_key_usage" {
description = "The cryptographic operations for which you can use the CMK"
value = try(aws_kms_external_key.this[0].key_usage, null)
}

################################################################################
Expand Down
18 changes: 18 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ variable "tags" {
# Key
################################################################################

variable "create_external" {
description = "Determines whether an external CMK (externally provided material) will be created or a standard CMK (AWS provided material)"
type = bool
default = false
}

variable "bypass_policy_lockout_safety_check" {
description = "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"
type = bool
Expand Down Expand Up @@ -50,6 +56,12 @@ variable "is_enabled" {
default = null
}

variable "key_material_base64" {
description = "Base64 encoded 256-bit symmetric encryption key material to import. The CMK is permanently associated with this key material. External key only"
type = string
default = null
}

variable "key_usage" {
description = "Specifies the intended use of the key. Valid values: `ENCRYPT_DECRYPT` or `SIGN_VERIFY`. Defaults to `ENCRYPT_DECRYPT`"
type = string
Expand All @@ -68,6 +80,12 @@ variable "policy" {
default = null
}

variable "valid_to" {
description = "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"
type = string
default = null
}

variable "enable_default_policy" {
description = "Specifies whether to enable the default key policy. Defaults to `true`"
type = bool
Expand Down

0 comments on commit 2726c25

Please sign in to comment.