Skip to content

Commit

Permalink
feat: Added KMIP (Key Management Interoperability Protocol support). …
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewLemmond authored Dec 17, 2024
1 parent 7bb7ee4 commit f6b1da8
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 6 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ You need the following permissions to run this module.

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.49.0, < 2.0.0 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.69.0, < 2.0.0 |

### Modules

Expand All @@ -77,6 +77,8 @@ No modules.
| [ibm_kms_key.key](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_key) | resource |
| [ibm_kms_key_policies.root_key_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_key_policies) | resource |
| [ibm_kms_key_policies.standard_key_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_key_policies) | resource |
| [ibm_kms_kmip_adapter.kmip_adapter](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_kmip_adapter) | resource |
| [ibm_kms_kmip_client_cert.kmip_cert](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/kms_kmip_client_cert) | resource |

### Inputs

Expand All @@ -86,6 +88,7 @@ No modules.
| <a name="input_endpoint_type"></a> [endpoint\_type](#input\_endpoint\_type) | Endpoint to use when creating the Key | `string` | `"public"` | no |
| <a name="input_force_delete"></a> [force\_delete](#input\_force\_delete) | Set as true to enable forcing deletion even if key is in use | `bool` | `false` | no |
| <a name="input_key_name"></a> [key\_name](#input\_key\_name) | Name to give the key | `string` | n/a | yes |
| <a name="input_kmip"></a> [kmip](#input\_kmip) | Allows a key to utilize the key management interoperability protocol (KMIP), for more information see https://cloud.ibm.com/docs/key-protect?topic=key-protect-kmip | <pre>list(object({<br/> name = string<br/> description = optional(string)<br/> certificates = optional(list(object({<br/> name = optional(string)<br/> certificate = string<br/> })))<br/> }))</pre> | `[]` | no |
| <a name="input_kms_instance_id"></a> [kms\_instance\_id](#input\_kms\_instance\_id) | ID or GUID of KMS Instance | `string` | n/a | yes |
| <a name="input_kms_key_ring_id"></a> [kms\_key\_ring\_id](#input\_kms\_key\_ring\_id) | The ID of the key ring where you want to add your KMS key | `string` | `"default"` | no |
| <a name="input_rotation_interval_month"></a> [rotation\_interval\_month](#input\_rotation\_interval\_month) | The key rotation time interval in months. Rotation policy cannot be set for standard key, so value is ignored if var.standard\_key is true | `number` | `1` | no |
Expand All @@ -95,6 +98,8 @@ No modules.

| Name | Description |
|------|-------------|
| <a name="output_adapter_ids"></a> [adapter\_ids](#output\_adapter\_ids) | KMIP Adapter IDs of the associated root key |
| <a name="output_cert_ids"></a> [cert\_ids](#output\_cert\_ids) | KMIP Cert IDs |
| <a name="output_crn"></a> [crn](#output\_crn) | Key CRN |
| <a name="output_dual_auth_delete"></a> [dual\_auth\_delete](#output\_dual\_auth\_delete) | Is Dual Auth Delete Enabled |
| <a name="output_key_id"></a> [key\_id](#output\_key\_id) | Key ID |
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ terraform {
# module's version.tf (basic example), and 1 example that will always use the latest provider version (complete example).
ibm = {
source = "IBM-Cloud/ibm"
version = "1.49.0"
version = "1.69.0"
}
}
}
66 changes: 66 additions & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,62 @@ module "resource_group" {
existing_resource_group_name = var.resource_group
}

##############################################################################
# Secrets Manager Certificate Setup
##############################################################################

module "secrets_manager" {
count = var.existing_secrets_manager_crn == null ? 1 : 0
source = "terraform-ibm-modules/secrets-manager/ibm"
version = "1.18.14"
secrets_manager_name = "${var.prefix}-secrets-manager"
sm_service_plan = "trial"
resource_group_id = module.resource_group.resource_group_id
region = var.region
}

module "sm_crn" {
source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
version = "1.1.0"
crn = var.existing_secrets_manager_crn == null ? module.secrets_manager[0].secrets_manager_crn : var.existing_secrets_manager_crn
}

locals {
certificate_template_name = var.existing_cert_template_name == null ? "${var.prefix}-template" : var.existing_cert_template_name
}

module "secrets_manager_private_cert_engine" {
count = var.existing_secrets_manager_crn == null && var.existing_cert_template_name == null ? 1 : 0
source = "terraform-ibm-modules/secrets-manager-private-cert-engine/ibm"
version = "1.3.4"
secrets_manager_guid = module.sm_crn.service_instance
region = var.region
root_ca_name = "${var.prefix}-ca"
root_ca_common_name = "*.cloud.ibm.com"
intermediate_ca_name = "${var.prefix}-int-ca"
certificate_template_name = local.certificate_template_name
root_ca_max_ttl = "8760h"
}

module "secrets_manager_cert" {
# explicit depends on because the cert engine must complete creating the template before the cert is created
# no outputs from the private cert engine to reference in this module call
depends_on = [module.secrets_manager_private_cert_engine]
source = "terraform-ibm-modules/secrets-manager-private-cert/ibm"
version = "1.3.2"
secrets_manager_guid = module.sm_crn.service_instance
secrets_manager_region = module.sm_crn.region
cert_name = "${var.prefix}-kmip-cert"
cert_common_name = "*.cloud.ibm.com"
cert_template = local.certificate_template_name
}

data "ibm_sm_private_certificate" "kmip_cert" {
instance_id = module.sm_crn.service_instance
region = module.sm_crn.region
secret_id = module.secrets_manager_cert.secret_id
}

##############################################################################
# KMS (Key Protect) instance
##############################################################################
Expand All @@ -31,6 +87,16 @@ module "kms_root_key" {
source = "../.."
kms_instance_id = ibm_resource_instance.key_protect_instance.guid
key_name = "${var.prefix}-root-key"
kmip = [
{
name = "${var.prefix}-kmip-adapter"
certificates = [
{
certificate = data.ibm_sm_private_certificate.kmip_cert.certificate
}
]
}
]
}

##############################################################################
Expand Down
10 changes: 10 additions & 0 deletions examples/complete/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,13 @@ output "resource_group_id" {
description = "Resource group ID"
value = module.resource_group.resource_group_id
}

output "root_key_adapter_ids" {
description = "Root Key KMIP adapter IDs"
value = module.kms_root_key.adapter_ids
}

output "root_key_cert_ids" {
description = "Root Key KMIP cert IDs"
value = module.kms_root_key.cert_ids
}
12 changes: 12 additions & 0 deletions examples/complete/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ variable "resource_tags" {
description = "Optional list of tags to be added to created resources"
default = []
}

variable "existing_secrets_manager_crn" {
type = string
description = "CRN of an existing Secrets Manager instance"
default = null
}

variable "existing_cert_template_name" {
type = string
description = "Name of an existing Private Certificate template to use, required if providing a value for `existing_secrets_manager_crn`"
default = null
}
2 changes: 1 addition & 1 deletion examples/complete/version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ terraform {
# module's version.tf (basic example), and 1 example that will always use the latest provider version (complete example).
ibm = {
source = "IBM-Cloud/ibm"
version = ">= 1.49.0"
version = ">= 1.69.0"
}
}
}
49 changes: 49 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,52 @@ resource "ibm_kms_key_policies" "standard_key_policy" {
enabled = var.dual_auth_delete_enabled
}
}

locals {
# tflint-ignore: terraform_unused_declarations
kmip_root_key_validation = (length(var.kmip) > 0 && var.standard_key) ? tobool("When providing a value for `kmip`, the key being created must be a root key.") : true

kmip_certs = flatten([
[
for adapter in var.kmip : [
for certificate in adapter.certificates : {
adapter_name = adapter.name
certificate_name = try(certificate.name, null)
certificate = certificate.certificate
# Check if filepath string is given, used in ibm_kms_kmip_client_cert call
cert_is_file = length(regexall("^.+\\.pem$", certificate.certificate)) > 0
}
]
]
])

kmip_adapter_id_output = {
for idx, _ in ibm_kms_kmip_adapter.kmip_adapter :
idx => ibm_kms_kmip_adapter.kmip_adapter[idx].adapter_id
}
kmip_cert_id_output = {
for idx, _ in ibm_kms_kmip_client_cert.kmip_cert :
idx => ibm_kms_kmip_client_cert.kmip_cert[idx].cert_id
}
}

resource "ibm_kms_kmip_adapter" "kmip_adapter" {
for_each = { for adapter in var.kmip : adapter.name => adapter }
instance_id = var.kms_instance_id
profile = "native_1.0"
profile_data = {
"crk_id" = ibm_kms_key.key.key_id
}
name = each.key
description = each.value.description
endpoint_type = var.endpoint_type
}

resource "ibm_kms_kmip_client_cert" "kmip_cert" {
for_each = { for idx, obj in local.kmip_certs : "${obj.adapter_name}-${idx}" => obj }
endpoint_type = var.endpoint_type
instance_id = var.kms_instance_id
adapter_id = ibm_kms_kmip_adapter.kmip_adapter[each.value.adapter_name].adapter_id
certificate = each.value.cert_is_file ? file(each.value.certificate) : each.value.certificate
name = each.value.certificate_name
}
10 changes: 10 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ output "dual_auth_delete" {
description = "Is Dual Auth Delete Enabled"
value = var.standard_key ? ibm_kms_key_policies.standard_key_policy[0].dual_auth_delete : ibm_kms_key_policies.root_key_policy[0].dual_auth_delete
}

output "adapter_ids" {
description = "KMIP Adapter IDs of the associated root key"
value = local.kmip_adapter_id_output
}

output "cert_ids" {
description = "KMIP Cert IDs"
value = local.kmip_cert_id_output
}
8 changes: 8 additions & 0 deletions tests/pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ func TestRunCompleteExample(t *testing.T) {
t.Parallel()

options := setupOptions(t, "kms-key")

options.TerraformVars = map[string]interface{}{
"existing_secrets_manager_crn": permanentResources["secretsManagerCRN"],
"existing_cert_template_name": permanentResources["privateCertTemplateName"],
"prefix": options.Prefix,
"region": permanentResources["secretsManagerRegion"],
}

output, err := options.RunTestConsistency()
assert.Nil(t, err, "This should not have errored")
assert.NotNil(t, output, "Expected some output")
Expand Down
37 changes: 37 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,40 @@ variable "force_delete" {
description = "Set as true to enable forcing deletion even if key is in use"
default = false
}

variable "kmip" {
type = list(object({
name = string
description = optional(string)
certificates = optional(list(object({
name = optional(string)
certificate = string
})))
}))
description = "Allows a key to utilize the key management interoperability protocol (KMIP), for more information see https://cloud.ibm.com/docs/key-protect?topic=key-protect-kmip"
default = []

validation {
condition = alltrue([for adapter in var.kmip :
length(adapter.name) >= 2 && length(adapter.name) <= 40
])
error_message = "`kmip[*].name` must be between 2 and 40 characters."
}

validation {
condition = alltrue([for adapter in var.kmip :
adapter.description == null ? true :
length(adapter.description) >= 2 && length(adapter.description) <= 240
])
error_message = "`kmip[*].description` must be between 2 and 240 characters."
}

validation {
condition = alltrue([
for adapter in var.kmip :
adapter.certificates == null ? true :
length(adapter.certificates) <= 200
])
error_message = "Each adapter can contain up to 200 certificates, current length exceeds this limit."
}
}
4 changes: 2 additions & 2 deletions version.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
terraform {
required_version = ">= 1.0.0"
required_version = ">= 1.3.0"
required_providers {
ibm = {
source = "IBM-Cloud/ibm"
# Use "greater than or equal to" range in modules
version = ">= 1.49.0, < 2.0.0"
version = ">= 1.69.0, < 2.0.0"
}
}
}

0 comments on commit f6b1da8

Please sign in to comment.