-value` format. . | `string` | `"secrets-manager-key-ring"` | no |
+| [prefix](#input\_prefix) | The prefix to add to all resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes |
+| [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints). | `string` | `"private"` | no |
+| [region](#input\_region) | The region to provision resources to. | `string` | `"us-south"` | no |
+| [secrets\_manager\_cbr\_rules](#input\_secrets\_manager\_cbr\_rules) | (Optional, list) List of CBR rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/fully-configurable/DA-cbr_rules.md) | list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no |
+| [secrets\_manager\_endpoint\_type](#input\_secrets\_manager\_endpoint\_type) | The type of endpoint (public or private) to connect to the Secrets Manager API. The Terraform provider uses this endpoint type to interact with the Secrets Manager API and configure Event Notifications. | `string` | `"private"` | no |
+| [secrets\_manager\_instance\_name](#input\_secrets\_manager\_instance\_name) | The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format. Applies only if `existing_secrets_manager_crn` is not provided. | `string` | `"secrets-manager"` | no |
+| [secrets\_manager\_resource\_tags](#input\_secrets\_manager\_resource\_tags) | The list of resource tags you want to associate with your Secrets Manager instance. Applies only if `existing_secrets_manager_crn` is not provided. | `list(any)` | `[]` | no |
+| [service\_plan](#input\_service\_plan) | The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. | `string` | `"standard"` | no |
+| [skip\_event\_notifications\_iam\_authorization\_policy](#input\_skip\_event\_notifications\_iam\_authorization\_policy) | If set to true, this skips the creation of a service to service authorization from Secrets Manager to Event Notifications. If false, the service to service authorization is created. | `bool` | `false` | no |
+| [skip\_sm\_ce\_iam\_authorization\_policy](#input\_skip\_sm\_ce\_iam\_authorization\_policy) | Whether to skip the creation of the IAM authorization policies required to enable the IAM credentials engine. If set to false, policies will be created that grants the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manage' access to the IAM groups service. | `bool` | `false` | no |
+| [skip\_sm\_kms\_iam\_authorization\_policy](#input\_skip\_sm\_kms\_iam\_authorization\_policy) | Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. | `bool` | `false` | no |
+
+### Outputs
+
+| Name | Description |
+|------|-------------|
+| [resource\_group\_id](#output\_resource\_group\_id) | Resource group ID |
+| [resource\_group\_name](#output\_resource\_group\_name) | Resource group name |
+| [secrets\_manager\_crn](#output\_secrets\_manager\_crn) | CRN of the Secrets Manager instance |
+| [secrets\_manager\_guid](#output\_secrets\_manager\_guid) | GUID of Secrets Manager instance |
+| [secrets\_manager\_id](#output\_secrets\_manager\_id) | ID of Secrets Manager instance. |
+| [secrets\_manager\_name](#output\_secrets\_manager\_name) | Name of the Secrets Manager instance |
+| [secrets\_manager\_region](#output\_secrets\_manager\_region) | Region of the Secrets Manager instance |
+
diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template
new file mode 100644
index 00000000..2adb0113
--- /dev/null
+++ b/solutions/fully-configurable/catalogValidationValues.json.template
@@ -0,0 +1,9 @@
+{
+ "ibmcloud_api_key": $VALIDATION_APIKEY,
+ "existing_resource_group_name": "geretain-test-secrets-manager",
+ "prefix": $PREFIX,
+ "service_plan": "trial",
+ "kms_encryption_enabled": true,
+ "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN,
+ "region": "eu-de"
+}
diff --git a/solutions/standard/main.tf b/solutions/fully-configurable/main.tf
similarity index 59%
rename from solutions/standard/main.tf
rename to solutions/fully-configurable/main.tf
index da932fdb..94b74d59 100644
--- a/solutions/standard/main.tf
+++ b/solutions/fully-configurable/main.tf
@@ -2,45 +2,37 @@
# Resource Group
########################################################################################################################
locals {
- # tflint-ignore: terraform_unused_declarations
- validate_resource_group = (var.existing_secrets_manager_crn == null && var.resource_group_name == null) ? tobool("Resource group name can not be null if existing secrets manager CRN is not set.") : true
- # tflint-ignore: terraform_unused_declarations
- validate_event_notifications = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? tobool("To enable event notifications, an existing event notifications CRN must be set.") : true
- prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null
+ prefix = var.prefix != null ? trimspace(var.prefix) != "" ? "${var.prefix}-" : "" : ""
}
module "resource_group" {
- count = var.existing_secrets_manager_crn == null ? 1 : 0
source = "terraform-ibm-modules/resource-group/ibm"
version = "1.1.6"
- resource_group_name = var.use_existing_resource_group == false ? try("${local.prefix}-${var.resource_group_name}", var.resource_group_name) : null
- existing_resource_group_name = var.use_existing_resource_group == true ? var.resource_group_name : null
+ existing_resource_group_name = var.existing_resource_group_name
}
#######################################################################################################################
# KMS Key
#######################################################################################################################
locals {
- kms_key_crn = var.existing_secrets_manager_crn == null ? (var.existing_secrets_manager_kms_key_crn != null ? var.existing_secrets_manager_kms_key_crn : module.kms[0].keys[format("%s.%s", local.kms_key_ring_name, local.kms_key_name)].crn) : var.existing_secrets_manager_kms_key_crn
- kms_key_ring_name = try("${local.prefix}-${var.kms_key_ring_name}", var.kms_key_ring_name)
- kms_key_name = try("${local.prefix}-${var.kms_key_name}", var.kms_key_name)
+ kms_key_crn = var.existing_secrets_manager_crn == null ? (var.existing_secrets_manager_kms_key_crn != null ? var.existing_secrets_manager_kms_key_crn : (var.kms_encryption_enabled == true ? module.kms[0].keys[format("%s.%s", local.kms_key_ring_name, local.kms_key_name)].crn : null)) : var.existing_secrets_manager_kms_key_crn
+ kms_key_ring_name = "${local.prefix}${var.kms_key_ring_name}"
+ kms_key_name = "${local.prefix}${var.kms_key_name}"
- parsed_existing_kms_instance_crn = var.existing_kms_instance_crn != null ? split(":", var.existing_kms_instance_crn) : []
- kms_region = length(local.parsed_existing_kms_instance_crn) > 0 ? local.parsed_existing_kms_instance_crn[5] : null
+ kms_region = var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].region : null
- parsed_service_name = var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_name : module.kms_key_crn_parser[0].service_name
+ parsed_service_name = var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_name : (var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : null)
is_hpcs_key = local.parsed_service_name == "hs-crypto" ? true : false
- create_cross_account_auth_policy = var.existing_secrets_manager_crn == null && !var.skip_kms_iam_authorization_policy && var.ibmcloud_kms_api_key != null
+ create_cross_account_auth_policy = var.existing_secrets_manager_crn == null && !var.skip_sm_kms_iam_authorization_policy && var.ibmcloud_kms_api_key != null
create_cross_account_hpcs_auth_policy = local.create_cross_account_auth_policy == true && local.is_hpcs_key ? 1 : 0
- kms_service_name = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : module.kms_instance_crn_parser[0].service_name
- kms_key_id = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].resource : module.kms_instance_crn_parser[0].resource
- kms_instance_guid = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].service_instance : module.kms_instance_crn_parser[0].service_instance
- kms_account_id = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : module.kms_instance_crn_parser[0].account_id
-
+ kms_service_name = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : (var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_name : null)
+ kms_key_id = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].resource : (var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].resource : null)
+ kms_instance_guid = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].service_instance : (var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_instance : null)
+ kms_account_id = var.existing_secrets_manager_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : (var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].account_id : null)
}
-# Lookup account ID
+
data "ibm_iam_account_settings" "iam_account_settings" {
count = local.create_cross_account_auth_policy ? 1 : 0
}
@@ -71,7 +63,7 @@ resource "ibm_iam_authorization_policy" "kms_policy" {
source_service_name = "secrets-manager"
source_resource_group_id = module.resource_group[0].resource_group_id
roles = ["Reader"]
- description = "Allow all Secrets Manager instances in the resource group ${module.resource_group[0].resource_group_id} in the account ${data.ibm_iam_account_settings.iam_account_settings[0].account_id} to read the ${local.kms_service_name} key ${local.kms_key_id} from the instance GUID ${local.kms_instance_guid}"
+ description = "Allow all Secrets Manager instances in the resource group ${local.kms_account_id} to read the ${local.kms_service_name} key ${local.kms_key_id} from the instance GUID ${local.kms_instance_guid}"
resource_attributes {
name = "serviceName"
operator = "stringEquals"
@@ -121,7 +113,7 @@ resource "ibm_iam_authorization_policy" "secrets_manager_hpcs_policy" {
target_service_name = local.kms_service_name
target_resource_instance_id = local.kms_instance_guid
roles = ["Viewer"]
- description = "Allow all Secrets Manager instances in the resource group ${module.resource_group[0].resource_group_id} in the account ${data.ibm_iam_account_settings.iam_account_settings[0].account_id} to view from the ${local.kms_service_name} instance GUID ${local.kms_instance_guid}"
+ description = "Allow all Secrets Manager instances in the resource group ${module.resource_group[0].resource_group_id} in the account ${local.kms_account_id} to view from the ${local.kms_service_name} instance GUID ${local.kms_instance_guid}"
}
# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
@@ -131,15 +123,14 @@ resource "time_sleep" "wait_for_sm_hpcs_authorization_policy" {
create_duration = "30s"
}
-
# KMS root key for Secrets Manager secret encryption
module "kms" {
providers = {
ibm = ibm.kms
}
- count = var.existing_secrets_manager_crn != null || var.existing_secrets_manager_kms_key_crn != null ? 0 : 1 # no need to create any KMS resources if passing an existing key, or bucket
+ count = var.existing_secrets_manager_crn == null && var.kms_encryption_enabled && var.existing_secrets_manager_kms_key_crn == null ? 1 : 0 # no need to create any KMS resources if passing an existing key
source = "terraform-ibm-modules/kms-all-inclusive/ibm"
- version = "4.21.3"
+ version = "4.20.0"
create_key_protect_instance = false
region = local.kms_region
existing_kms_instance_crn = var.existing_kms_instance_crn
@@ -155,7 +146,7 @@ module "kms" {
standard_key = false
rotation_interval_month = 3
dual_auth_delete_enabled = false
- force_delete = true
+ force_delete = true # Force delete must be set to true, or the terraform destroy will fail since the service does not de-register itself from the key until the reclamation period has expired.
}
]
}
@@ -171,73 +162,31 @@ locals {
secrets_manager_guid = var.existing_secrets_manager_crn != null ? (length(local.parsed_existing_secrets_manager_crn) > 0 ? local.parsed_existing_secrets_manager_crn[7] : null) : module.secrets_manager.secrets_manager_guid
secrets_manager_crn = var.existing_secrets_manager_crn != null ? var.existing_secrets_manager_crn : module.secrets_manager.secrets_manager_crn
secrets_manager_region = var.existing_secrets_manager_crn != null ? (length(local.parsed_existing_secrets_manager_crn) > 0 ? local.parsed_existing_secrets_manager_crn[5] : null) : module.secrets_manager.secrets_manager_region
+ enable_event_notifications = var.existing_event_notifications_instance_crn != null ? true : false
}
module "secrets_manager" {
- depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_sm_hpcs_authorization_policy]
- source = "../../modules/fscloud"
- existing_sm_instance_crn = var.existing_secrets_manager_crn
- resource_group_id = var.existing_secrets_manager_crn == null ? module.resource_group[0].resource_group_id : data.ibm_resource_instance.existing_sm[0].resource_group_id
- region = var.region
- secrets_manager_name = try("${local.prefix}-${var.secrets_manager_instance_name}", var.secrets_manager_instance_name)
- service_plan = var.service_plan
- sm_tags = var.secrets_manager_tags
- is_hpcs_key = local.is_hpcs_key
+ depends_on = [time_sleep.wait_for_authorization_policy]
+ source = "../.."
+ existing_sm_instance_crn = var.existing_secrets_manager_crn
+ resource_group_id = module.resource_group.resource_group_id
+ region = var.region
+ secrets_manager_name = "${local.prefix}${var.secrets_manager_instance_name}"
+ sm_service_plan = var.service_plan
+ sm_tags = var.secrets_manager_resource_tags
+ skip_iam_authorization_policy = var.skip_sm_ce_iam_authorization_policy
# kms dependency
+ is_hpcs_key = local.is_hpcs_key
+ kms_encryption_enabled = var.kms_encryption_enabled
kms_key_crn = local.kms_key_crn
- skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy || local.create_cross_account_auth_policy
+ skip_kms_iam_authorization_policy = var.skip_sm_kms_iam_authorization_policy || local.create_cross_account_auth_policy
# event notifications dependency
- enable_event_notification = var.enable_event_notifications
+ enable_event_notification = local.enable_event_notifications
existing_en_instance_crn = var.existing_event_notifications_instance_crn
skip_en_iam_authorization_policy = var.skip_event_notifications_iam_authorization_policy
- cbr_rules = var.cbr_rules
-}
-
-# Configure an IBM Secrets Manager IAM credentials engine for an existing IBM Secrets Manager instance.
-module "iam_secrets_engine" {
- count = var.iam_engine_enabled ? 1 : 0
- source = "terraform-ibm-modules/secrets-manager-iam-engine/ibm"
- version = "1.2.10"
- region = local.secrets_manager_region
- iam_engine_name = try("${local.prefix}-${var.iam_engine_name}", var.iam_engine_name)
- secrets_manager_guid = local.secrets_manager_guid
- endpoint_type = "private"
-}
-
-
-# Configure an IBM Secrets Manager public certificate engine for an existing IBM Secrets Manager instance.
-module "secrets_manager_public_cert_engine" {
- count = var.public_cert_engine_enabled ? 1 : 0
- source = "terraform-ibm-modules/secrets-manager-public-cert-engine/ibm"
- version = "1.0.3"
- providers = {
- ibm = ibm
- ibm.secret-store = ibm
- }
- secrets_manager_guid = local.secrets_manager_guid
- region = local.secrets_manager_region
- internet_services_crn = var.public_cert_engine_internet_services_crn
- ibmcloud_cis_api_key = var.ibmcloud_api_key
- dns_config_name = var.public_cert_engine_dns_provider_config_name
- ca_config_name = var.public_cert_engine_lets_encrypt_config_ca_name
- acme_letsencrypt_private_key = var.acme_letsencrypt_private_key
- service_endpoints = "private"
-}
-
-
-# Configure an IBM Secrets Manager private certificate engine for an existing IBM Secrets Manager instance.
-module "private_secret_engine" {
- count = var.private_cert_engine_enabled ? 1 : 0
- source = "terraform-ibm-modules/secrets-manager-private-cert-engine/ibm"
- version = "1.3.5"
- secrets_manager_guid = local.secrets_manager_guid
- region = var.region
- root_ca_name = var.private_cert_engine_config_root_ca_name
- root_ca_common_name = var.private_cert_engine_config_root_ca_common_name
- root_ca_max_ttl = var.private_cert_engine_config_root_ca_max_ttl
- intermediate_ca_name = var.private_cert_engine_config_intermediate_ca_name
- certificate_template_name = var.private_cert_engine_config_template_name
- endpoint_type = "private"
+ cbr_rules = var.secrets_manager_cbr_rules
+ endpoint_type = var.secrets_manager_endpoint_type
+ allowed_network = var.allowed_network
}
data "ibm_resource_instance" "existing_sm" {
@@ -256,14 +205,14 @@ locals {
data "ibm_en_destinations" "en_destinations" {
# if existing SM instance CRN is passed (!= null), then never do data lookup for EN destinations
- count = var.existing_secrets_manager_crn == null && var.enable_event_notifications ? 1 : 0
+ count = var.existing_secrets_manager_crn == null && local.enable_event_notifications ? 1 : 0
instance_guid = local.existing_en_guid
}
# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5533
resource "time_sleep" "wait_for_secrets_manager" {
# if existing SM instance CRN is passed (!= null), then never work with EN
- count = var.existing_secrets_manager_crn == null && var.enable_event_notifications ? 1 : 0
+ count = var.existing_secrets_manager_crn == null && local.enable_event_notifications ? 1 : 0
depends_on = [module.secrets_manager]
create_duration = "30s"
@@ -271,10 +220,10 @@ resource "time_sleep" "wait_for_secrets_manager" {
resource "ibm_en_topic" "en_topic" {
# if existing SM instance CRN is passed (!= null), then never create EN topic
- count = var.existing_secrets_manager_crn == null && var.enable_event_notifications ? 1 : 0
+ count = var.existing_secrets_manager_crn == null && local.enable_event_notifications ? 1 : 0
depends_on = [time_sleep.wait_for_secrets_manager]
instance_guid = local.existing_en_guid
- name = "Secrets Manager Topic"
+ name = "Topic for SCC instance ${module.secrets_manager.secrets_manager_guid}"
description = "Topic for Secrets Manager events routing"
sources {
id = local.secrets_manager_crn
@@ -287,7 +236,7 @@ resource "ibm_en_topic" "en_topic" {
resource "ibm_en_subscription_email" "email_subscription" {
# if existing SM instance CRN is passed (!= null), then never create EN email subscription
- count = var.existing_secrets_manager_crn == null && var.enable_event_notifications && length(var.event_notifications_email_list) > 0 ? 1 : 0
+ count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && length(var.event_notifications_email_list) > 0 ? 1 : 0
instance_guid = local.existing_en_guid
name = "Email for Secrets Manager Subscription"
description = "Subscription for Secret Manager Events"
diff --git a/solutions/standard/outputs.tf b/solutions/fully-configurable/outputs.tf
similarity index 69%
rename from solutions/standard/outputs.tf
rename to solutions/fully-configurable/outputs.tf
index 9c4d0c8f..52332205 100644
--- a/solutions/standard/outputs.tf
+++ b/solutions/fully-configurable/outputs.tf
@@ -1,11 +1,11 @@
output "resource_group_name" {
description = "Resource group name"
- value = var.existing_secrets_manager_crn == null ? module.resource_group[0].resource_group_name : data.ibm_resource_instance.existing_sm[0].resource_group_name
+ value = module.resource_group.resource_group_name
}
output "resource_group_id" {
description = "Resource group ID"
- value = var.existing_secrets_manager_crn == null ? module.resource_group[0].resource_group_id : data.ibm_resource_instance.existing_sm[0].resource_group_id
+ value = module.resource_group.resource_group_id
}
output "secrets_manager_guid" {
@@ -14,7 +14,7 @@ output "secrets_manager_guid" {
}
output "secrets_manager_id" {
- description = "ID of Secrets Manager instance. Same value as secrets_manager_guid"
+ description = "ID of Secrets Manager instance."
value = var.existing_secrets_manager_crn == null ? module.secrets_manager.secrets_manager_id : local.secrets_manager_guid
}
diff --git a/solutions/standard/provider.tf b/solutions/fully-configurable/provider.tf
similarity index 100%
rename from solutions/standard/provider.tf
rename to solutions/fully-configurable/provider.tf
diff --git a/solutions/standard/variables.tf b/solutions/fully-configurable/variables.tf
similarity index 61%
rename from solutions/standard/variables.tf
rename to solutions/fully-configurable/variables.tf
index de0173c2..55df6bb1 100644
--- a/solutions/standard/variables.tf
+++ b/solutions/fully-configurable/variables.tf
@@ -4,7 +4,7 @@
variable "ibmcloud_api_key" {
type = string
- description = "The API Key to use for IBM Cloud."
+ description = "The IBM Cloud API key used to provision resources."
sensitive = true
}
@@ -19,16 +19,11 @@ variable "provider_visibility" {
}
}
-variable "use_existing_resource_group" {
- type = bool
- description = "Whether to use an existing resource group."
- default = false
-}
-
-variable "resource_group_name" {
+variable "existing_resource_group_name" {
type = string
- description = "The name of a new or existing resource group to provision resources to. If a prefix input variable is specified, it's added to the value in the `-value` format. Optional if `existing_secrets_manager_crn` is not specified."
- default = null
+ description = "The name of an existing resource group to provision resource in."
+ default = "Default"
+ nullable = false
}
variable "region" {
@@ -40,7 +35,16 @@ variable "region" {
variable "prefix" {
type = string
description = "The prefix to add to all resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string."
- default = "dev"
+
+ validation {
+ condition = (var.prefix == null ? true :
+ alltrue([
+ can(regex("^[a-z]{0,1}[-a-z0-9]{0,14}[a-z0-9]{0,1}$", var.prefix)),
+ length(regexall("^.*--.*", var.prefix)) == 0
+ ])
+ )
+ error_message = "Prefix must begin with a lowercase letter, contain only lowercase letters, numbers, and - characters. Prefixes must end with a lowercase letter or number and be 16 or fewer characters."
+ }
}
########################################################################################################################
@@ -49,7 +53,7 @@ variable "prefix" {
variable "secrets_manager_instance_name" {
type = string
- description = "The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format."
+ description = "The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format. Applies only if `existing_secrets_manager_crn` is not provided."
default = "secrets-manager"
}
@@ -69,132 +73,106 @@ variable "service_plan" {
}
}
-variable "secrets_manager_tags" {
- type = list(any)
- description = "The list of resource tags you want to associate with your Secrets Manager instance."
- default = []
-}
-
-########################################################################################################################
-# Public cert engine config
-########################################################################################################################
-
-variable "public_cert_engine_enabled" {
+variable "skip_sm_ce_iam_authorization_policy" {
type = bool
- description = "Set this to true to configure a Secrets Manager public certificate engine for an existing Secrets Manager instance. If set to false, no public certificate engine will be configured for your instance."
+ description = "Whether to skip the creation of the IAM authorization policies required to enable the IAM credentials engine. If set to false, policies will be created that grants the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manage' access to the IAM groups service."
default = false
}
-variable "public_cert_engine_internet_services_crn" {
- type = string
- description = "Cloud Internet Service ID."
- default = null
-}
-
-variable "public_cert_engine_dns_provider_config_name" {
- type = string
- description = "The name of the DNS provider for the public certificate secrets engine configuration."
- default = "certificate-dns"
+variable "secrets_manager_resource_tags" {
+ type = list(any)
+ description = "The list of resource tags you want to associate with your Secrets Manager instance. Applies only if `existing_secrets_manager_crn` is not provided."
+ default = []
}
-variable "public_cert_engine_lets_encrypt_config_ca_name" {
+variable "secrets_manager_endpoint_type" {
type = string
- description = "The name of the certificate authority for Secrets Manager."
- default = "cert-auth"
+ description = "The type of endpoint (public or private) to connect to the Secrets Manager API. The Terraform provider uses this endpoint type to interact with the Secrets Manager API and configure Event Notifications."
+ default = "private"
+ validation {
+ condition = contains(["public", "private"], var.secrets_manager_endpoint_type)
+ error_message = "The specified service endpoint is not a valid selection!"
+ }
}
-variable "acme_letsencrypt_private_key" {
+variable "allowed_network" {
type = string
- description = "The private key generated by the ACME account creation tool."
- sensitive = true
- default = null
+ description = "The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`."
+ default = "private-only"
+ validation {
+ condition = contains(["private-only", "public-and-private"], var.allowed_network)
+ error_message = "The specified allowed_network is not a valid selection!"
+ }
}
########################################################################################################################
-# Private cert engine config
+# Key Protect
########################################################################################################################
-variable "private_cert_engine_enabled" {
+variable "skip_sm_kms_iam_authorization_policy" {
type = bool
- description = "Set this to true to configure a Secrets Manager private certificate engine for an existing instance. If set to false, no private certificate engine will be configured for your instance."
+ description = "Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account."
default = false
}
-variable "private_cert_engine_config_root_ca_name" {
- type = string
- description = "The name of the root certificate authority associated with the private_cert secret engine."
- default = "root-ca"
-}
-
-variable "private_cert_engine_config_root_ca_common_name" {
- type = string
- description = "The fully qualified domain name or host domain name for the certificate that will be created."
- default = "terraform-modules.ibm.com"
-}
-
-variable "private_cert_engine_config_root_ca_max_ttl" {
- type = string
- description = "The maximum time-to-live value for the root certificate authority."
- default = "87600h"
-}
-
-variable "private_cert_engine_config_intermediate_ca_name" {
- type = string
- description = "A human-readable unique name to assign to the intermediate certificate authority configuration."
- default = "intermediate-ca"
-}
-
-variable "private_cert_engine_config_template_name" {
+variable "existing_secrets_manager_kms_key_crn" {
type = string
- description = "The name of the certificate template."
- default = "default-cert-template"
+ description = "The CRN of a Key Protect or Hyper Protect Crypto Services key to use for Secrets Manager. If not specified, a key ring and key are created."
+ default = null
}
########################################################################################################################
-# IAM engine config
+# KMS properties required when creating an encryption key, rather than passing an existing key CRN.
########################################################################################################################
-variable "iam_engine_enabled" {
+variable "kms_encryption_enabled" {
type = bool
- description = "Set this to true to to configure a Secrets Manager IAM credentials engine. If set to false, no IAM engine will be configured for your instance."
+ description = "Set to true to enable Secrets Manager Secrets Encryption using customer managed keys. When set to true, a value must be passed for either `existing_kms_instance_crn` or `existing_secrets_manager_kms_key_crn`. Cannot be set to true if passing a value for `existing_secrets_manager_crn`."
default = false
-}
-variable "iam_engine_name" {
- type = string
- description = "The name of the IAM engine used to configure a Secrets Manager IAM credentials engine. If the prefix input variable is passed it is attached before the value in the format of '-value'."
- default = "iam-engine"
-}
+ validation {
+ condition = var.kms_encryption_enabled ? var.existing_secrets_manager_crn == null : true
+ error_message = "'kms_encryption_enabled' should be false if passing a value for 'existing_secrets_manager_crn'."
+ }
-########################################################################################################################
-# Key Protect
-########################################################################################################################
+ validation {
+ condition = var.existing_secrets_manager_kms_key_crn != null ? var.kms_encryption_enabled : true
+ error_message = "If passing a value for 'existing_secrets_manager_kms_key_crn', you should set 'kms_encryption_enabled' to true."
+ }
-variable "skip_kms_iam_authorization_policy" {
- type = bool
- description = "Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account."
- default = false
-}
+ validation {
+ condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled : true
+ error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled' to true."
+ }
-variable "existing_secrets_manager_kms_key_crn" {
- type = string
- description = "The CRN of a Key Protect or Hyper Protect Crypto Services key to use for Secrets Manager. If not specified, a key ring and key are created."
- default = null
+ validation {
+ condition = var.kms_encryption_enabled ? ((var.existing_kms_instance_crn != null || var.existing_secrets_manager_kms_key_crn != null) ? true : false) : true
+ error_message = "Either 'existing_kms_instance_crn' or `existing_secrets_manager_kms_key_crn` is required if 'kms_encryption_enabled' is set to true."
+ }
}
-########################################################################################################################
-# KMS properties required when creating an encryption key, rather than passing an existing key CRN.
-########################################################################################################################
-
variable "existing_kms_instance_crn" {
type = string
default = null
description = "The CRN of the KMS instance (Hyper Protect Crypto Services or Key Protect). Required only if `existing_secrets_manager_crn` or `existing_secrets_manager_kms_key_crn` is not specified. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`."
+
+ validation {
+ condition = anytrue([
+ can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.existing_kms_instance_crn)),
+ var.existing_kms_instance_crn == null,
+ ])
+ error_message = "The provided KMS instance CRN in the input 'existing_kms_instance_crn' in not valid."
+ }
+
+ validation {
+ condition = var.existing_kms_instance_crn != null ? var.existing_secrets_manager_crn == null : true
+ error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing secrets manager instance using the 'existing_secrets_manager_crn' input."
+ }
}
variable "kms_endpoint_type" {
type = string
- description = "The type of endpoint to use for communicating with the Key Protect or Hyper Protect Crypto Services instance. Possible values: `public`, `private`. Applies only if `existing_secrets_manager_kms_key_crn` is not specified."
+ description = "The endpoint for communicating with the Key Protect or Hyper Protect Crypto Services instance. Possible values: `public`, `private`. Applies only if `existing_secrets_manager_kms_key_crn` is not specified."
default = "private"
validation {
condition = can(regex("public|private", var.kms_endpoint_type))
@@ -225,12 +203,6 @@ variable "ibmcloud_kms_api_key" {
# Event Notifications
########################################################################################################################
-variable "enable_event_notifications" {
- type = bool
- default = false
- description = "Set this to true to enable lifecycle notifications for your Secrets Manager instance by connecting an Event Notifications service. When setting this to true, a value must be passed for `existing_event_notification_instance_crn`"
-}
-
variable "existing_event_notifications_instance_crn" {
type = string
description = "The CRN of the Event Notifications service used to enable lifecycle notifications for your Secrets Manager instance."
@@ -265,7 +237,7 @@ variable "event_notifications_reply_to_email" {
# Context-based restriction (CBR)
##############################################################
-variable "cbr_rules" {
+variable "secrets_manager_cbr_rules" {
type = list(object({
description = string
account_id = string
@@ -281,7 +253,7 @@ variable "cbr_rules" {
}))
})))
}))
- description = "(Optional, list) List of CBR rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/standard/DA-cbr_rules.md)"
+ description = "(Optional, list) List of CBR rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/fully-configurable/DA-cbr_rules.md)"
default = []
# Validation happens in the rule module
}
diff --git a/solutions/standard/version.tf b/solutions/fully-configurable/version.tf
similarity index 89%
rename from solutions/standard/version.tf
rename to solutions/fully-configurable/version.tf
index 8f470172..1230d4d2 100644
--- a/solutions/standard/version.tf
+++ b/solutions/fully-configurable/version.tf
@@ -1,5 +1,5 @@
terraform {
- required_version = ">= 1.3.0"
+ required_version = ">= 1.9.0"
# Lock DA into an exact provider version - renovate automation will keep it updated
required_providers {
ibm = {
diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md
new file mode 100644
index 00000000..0932c4e6
--- /dev/null
+++ b/solutions/security-enforced/README.md
@@ -0,0 +1,62 @@
+# Secrets Manager security-enforced solution
+
+This solution supports the following:
+- Taking in an existing resource group.
+- Provisioning and configuring of a Secrets Manager instance.
+- Configuring KMS encryption using a newly created key, or passing an existing key.
+
+**NB:** This solution is not intended to be called by one or more other modules since it contains a provider configurations, meaning it is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers)
+
+
+### Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.9.0 |
+
+### Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [secrets\_manager](#module\_secrets\_manager) | ../fully-configurable | n/a |
+
+### Resources
+
+No resources.
+
+### Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [event\_notifications\_email\_list](#input\_event\_notifications\_email\_list) | The list of email address to target out when Secrets Manager triggers an event | `list(string)` | `[]` | no |
+| [event\_notifications\_from\_email](#input\_event\_notifications\_from\_email) | The email address used to send any Secrets Manager event coming via Event Notifications | `string` | `"compliancealert@ibm.com"` | no |
+| [event\_notifications\_reply\_to\_email](#input\_event\_notifications\_reply\_to\_email) | The email address specified in the 'reply\_to' section for any Secret Manager event coming via Event Notifications | `string` | `"no-reply@ibm.com"` | no |
+| [existing\_event\_notifications\_instance\_crn](#input\_existing\_event\_notifications\_instance\_crn) | The CRN of the Event Notifications service used to enable lifecycle notifications for your Secrets Manager instance. | `string` | `null` | no |
+| [existing\_kms\_instance\_crn](#input\_existing\_kms\_instance\_crn) | The CRN of the KMS instance (Hyper Protect Crypto Services or Key Protect). Required only if `existing_secrets_manager_crn` or `existing_secrets_manager_kms_key_crn` is not specified. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. | `string` | `null` | no |
+| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision resource in. | `string` | `"Default"` | no |
+| [existing\_secrets\_manager\_crn](#input\_existing\_secrets\_manager\_crn) | The CRN of an existing Secrets Manager instance. If not supplied, a new instance is created. | `string` | `null` | no |
+| [existing\_secrets\_manager\_kms\_key\_crn](#input\_existing\_secrets\_manager\_kms\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services key to use for Secrets Manager. If not specified, a key ring and key are created. | `string` | `null` | no |
+| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key used to provision resources. | `string` | n/a | yes |
+| [ibmcloud\_kms\_api\_key](#input\_ibmcloud\_kms\_api\_key) | The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud\_api\_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Secrets Manager instance. Leave this input empty if the same account owns both instances. | `string` | `null` | no |
+| [kms\_key\_name](#input\_kms\_key\_name) | The name for the new root key. Applies only if `existing_secrets_manager_kms_key_crn` is not specified. If a prefix input variable is passed, it is added to the value in the `-value` format. | `string` | `"secrets-manager-key"` | no |
+| [kms\_key\_ring\_name](#input\_kms\_key\_ring\_name) | The name for the new key ring to store the key. Applies only if `existing_secrets_manager_kms_key_crn` is not specified. If a prefix input variable is passed, it is added to the value in the `-value` format. . | `string` | `"secrets-manager-key-ring"` | no |
+| [prefix](#input\_prefix) | The prefix to add to all resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes |
+| [region](#input\_region) | The region to provision resources to. | `string` | `"us-south"` | no |
+| [secrets\_manager\_cbr\_rules](#input\_secrets\_manager\_cbr\_rules) | (Optional, list) List of CBR rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/fully-configurable/DA-cbr_rules.md) | list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no |
+| [secrets\_manager\_instance\_name](#input\_secrets\_manager\_instance\_name) | The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format. Applies only if `existing_secrets_manager_crn` is not provided. | `string` | `"secrets-manager"` | no |
+| [secrets\_manager\_resource\_tags](#input\_secrets\_manager\_resource\_tags) | The list of resource tags you want to associate with your Secrets Manager instance. Applies only if `existing_secrets_manager_crn` is not provided. | `list(any)` | `[]` | no |
+| [service\_plan](#input\_service\_plan) | The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. | `string` | `"standard"` | no |
+| [skip\_event\_notifications\_iam\_authorization\_policy](#input\_skip\_event\_notifications\_iam\_authorization\_policy) | If set to true, this skips the creation of a service to service authorization from Secrets Manager to Event Notifications. If false, the service to service authorization is created. | `bool` | `false` | no |
+| [skip\_sm\_ce\_iam\_authorization\_policy](#input\_skip\_sm\_ce\_iam\_authorization\_policy) | Whether to skip the creation of the IAM authorization policies required to enable the IAM credentials engine. If set to false, policies will be created that grants the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manage' access to the IAM groups service. | `bool` | `false` | no |
+| [skip\_sm\_kms\_iam\_authorization\_policy](#input\_skip\_sm\_kms\_iam\_authorization\_policy) | Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. | `bool` | `false` | no |
+
+### Outputs
+
+| Name | Description |
+|------|-------------|
+| [resource\_group\_id](#output\_resource\_group\_id) | Resource group ID |
+| [resource\_group\_name](#output\_resource\_group\_name) | Resource group name |
+| [secrets\_manager\_crn](#output\_secrets\_manager\_crn) | CRN of Secrets Manager instance. |
+| [secrets\_manager\_guid](#output\_secrets\_manager\_guid) | GUID of Secrets Manager instance |
+| [secrets\_manager\_id](#output\_secrets\_manager\_id) | ID of Secrets Manager instance. |
+
diff --git a/solutions/standard/catalogValidationValues.json.template b/solutions/security-enforced/catalogValidationValues.json.template
similarity index 62%
rename from solutions/standard/catalogValidationValues.json.template
rename to solutions/security-enforced/catalogValidationValues.json.template
index 5a9fe734..c5b44365 100644
--- a/solutions/standard/catalogValidationValues.json.template
+++ b/solutions/security-enforced/catalogValidationValues.json.template
@@ -1,6 +1,7 @@
{
"ibmcloud_api_key": $VALIDATION_APIKEY,
- "resource_group_name": $PREFIX,
+ "existing_resource_group_name": "geretain-test-secrets-manager",
+ "prefix": $PREFIX,
"service_plan": "trial",
"existing_kms_instance_crn": $HPCS_US_SOUTH_CRN,
"region": "eu-de"
diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf
new file mode 100644
index 00000000..b7174343
--- /dev/null
+++ b/solutions/security-enforced/main.tf
@@ -0,0 +1,29 @@
+module "secrets_manager" {
+ source = "../fully-configurable"
+ ibmcloud_api_key = var.ibmcloud_api_key
+ existing_resource_group_name = var.existing_resource_group_name
+ prefix = var.prefix
+ provider_visibility = "private"
+ region = var.region
+ secrets_manager_instance_name = var.secrets_manager_instance_name
+ existing_secrets_manager_crn = var.existing_secrets_manager_crn
+ service_plan = var.service_plan
+ skip_sm_ce_iam_authorization_policy = var.skip_sm_ce_iam_authorization_policy
+ secrets_manager_resource_tags = var.secrets_manager_resource_tags
+ secrets_manager_endpoint_type = "private"
+ allowed_network = "private-only"
+ skip_sm_kms_iam_authorization_policy = var.skip_sm_kms_iam_authorization_policy
+ existing_secrets_manager_kms_key_crn = var.existing_secrets_manager_kms_key_crn
+ kms_encryption_enabled = true
+ existing_kms_instance_crn = var.existing_kms_instance_crn
+ kms_endpoint_type = "private"
+ kms_key_ring_name = var.kms_key_ring_name
+ kms_key_name = var.kms_key_name
+ ibmcloud_kms_api_key = var.ibmcloud_kms_api_key
+ existing_event_notifications_instance_crn = var.existing_event_notifications_instance_crn
+ skip_event_notifications_iam_authorization_policy = var.skip_event_notifications_iam_authorization_policy
+ event_notifications_email_list = var.event_notifications_email_list
+ event_notifications_from_email = var.event_notifications_from_email
+ event_notifications_reply_to_email = var.event_notifications_reply_to_email
+ secrets_manager_cbr_rules = var.secrets_manager_cbr_rules
+}
diff --git a/solutions/security-enforced/outputs.tf b/solutions/security-enforced/outputs.tf
new file mode 100644
index 00000000..d10dfacc
--- /dev/null
+++ b/solutions/security-enforced/outputs.tf
@@ -0,0 +1,24 @@
+output "resource_group_name" {
+ description = "Resource group name"
+ value = module.secrets_manager.resource_group_name
+}
+
+output "resource_group_id" {
+ description = "Resource group ID"
+ value = module.secrets_manager.resource_group_id
+}
+
+output "secrets_manager_guid" {
+ description = "GUID of Secrets Manager instance"
+ value = module.secrets_manager.secrets_manager_guid
+}
+
+output "secrets_manager_id" {
+ description = "ID of Secrets Manager instance."
+ value = module.secrets_manager.secrets_manager_id
+}
+
+output "secrets_manager_crn" {
+ description = "CRN of Secrets Manager instance."
+ value = module.secrets_manager.secrets_manager_crn
+}
diff --git a/solutions/security-enforced/provider.tf b/solutions/security-enforced/provider.tf
new file mode 100644
index 00000000..4c6add22
--- /dev/null
+++ b/solutions/security-enforced/provider.tf
@@ -0,0 +1 @@
+# Explicit provider config not required here as provider config in fully-configurable is used
diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf
new file mode 100644
index 00000000..ad308e4a
--- /dev/null
+++ b/solutions/security-enforced/variables.tf
@@ -0,0 +1,192 @@
+########################################################################################################################
+# Common variables
+########################################################################################################################
+
+variable "ibmcloud_api_key" {
+ type = string
+ description = "The IBM Cloud API key used to provision resources."
+ sensitive = true
+}
+
+variable "existing_resource_group_name" {
+ type = string
+ description = "The name of an existing resource group to provision resource in."
+ default = "Default"
+ nullable = false
+}
+
+variable "region" {
+ type = string
+ description = "The region to provision resources to."
+ default = "us-south"
+}
+
+variable "prefix" {
+ type = string
+ description = "The prefix to add to all resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string."
+
+ validation {
+ condition = (var.prefix == null ? true :
+ alltrue([
+ can(regex("^[a-z]{0,1}[-a-z0-9]{0,14}[a-z0-9]{0,1}$", var.prefix)),
+ length(regexall("^.*--.*", var.prefix)) == 0
+ ])
+ )
+ error_message = "Prefix must begin with a lowercase letter, contain only lowercase letters, numbers, and - characters. Prefixes must end with a lowercase letter or number and be 16 or fewer characters."
+ }
+}
+
+########################################################################################################################
+# Secrets Manager
+########################################################################################################################
+
+variable "secrets_manager_instance_name" {
+ type = string
+ description = "The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format. Applies only if `existing_secrets_manager_crn` is not provided."
+ default = "secrets-manager"
+}
+
+variable "existing_secrets_manager_crn" {
+ type = string
+ description = "The CRN of an existing Secrets Manager instance. If not supplied, a new instance is created."
+ default = null
+}
+
+variable "service_plan" {
+ type = string
+ description = "The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`."
+ default = "standard"
+ validation {
+ condition = contains(["standard", "trial"], var.service_plan)
+ error_message = "Only \"standard\" and \"trial\" are allowed values for secrets_manager_service_plan.Applies only if not providing a value for the `existing_secrets_manager_crn` input."
+ }
+}
+
+variable "skip_sm_ce_iam_authorization_policy" {
+ type = bool
+ description = "Whether to skip the creation of the IAM authorization policies required to enable the IAM credentials engine. If set to false, policies will be created that grants the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manage' access to the IAM groups service."
+ default = false
+}
+
+variable "secrets_manager_resource_tags" {
+ type = list(any)
+ description = "The list of resource tags you want to associate with your Secrets Manager instance. Applies only if `existing_secrets_manager_crn` is not provided."
+ default = []
+}
+
+########################################################################################################################
+# Key Protect
+########################################################################################################################
+
+variable "skip_sm_kms_iam_authorization_policy" {
+ type = bool
+ description = "Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account."
+ default = false
+}
+
+variable "existing_secrets_manager_kms_key_crn" {
+ type = string
+ description = "The CRN of a Key Protect or Hyper Protect Crypto Services key to use for Secrets Manager. If not specified, a key ring and key are created."
+ default = null
+}
+
+########################################################################################################################
+# KMS properties required when creating an encryption key, rather than passing an existing key CRN.
+########################################################################################################################
+
+variable "existing_kms_instance_crn" {
+ type = string
+ default = null
+ description = "The CRN of the KMS instance (Hyper Protect Crypto Services or Key Protect). Required only if `existing_secrets_manager_crn` or `existing_secrets_manager_kms_key_crn` is not specified. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`."
+
+ validation {
+ condition = anytrue([
+ can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.existing_kms_instance_crn)),
+ var.existing_kms_instance_crn == null,
+ ])
+ error_message = "The provided KMS instance CRN in the input 'existing_kms_instance_crn' in not valid."
+ }
+
+ validation {
+ condition = var.existing_kms_instance_crn != null ? var.existing_secrets_manager_crn == null : true
+ error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing secrets manager instance using the 'existing_secrets_manager_crn' input."
+ }
+}
+
+variable "kms_key_ring_name" {
+ type = string
+ default = "secrets-manager-key-ring"
+ description = "The name for the new key ring to store the key. Applies only if `existing_secrets_manager_kms_key_crn` is not specified. If a prefix input variable is passed, it is added to the value in the `-value` format. ."
+}
+
+variable "kms_key_name" {
+ type = string
+ default = "secrets-manager-key"
+ description = "The name for the new root key. Applies only if `existing_secrets_manager_kms_key_crn` is not specified. If a prefix input variable is passed, it is added to the value in the `-value` format."
+}
+
+variable "ibmcloud_kms_api_key" {
+ type = string
+ description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Secrets Manager instance. Leave this input empty if the same account owns both instances."
+ sensitive = true
+ default = null
+}
+
+########################################################################################################################
+# Event Notifications
+########################################################################################################################
+
+variable "existing_event_notifications_instance_crn" {
+ type = string
+ description = "The CRN of the Event Notifications service used to enable lifecycle notifications for your Secrets Manager instance."
+ default = null
+}
+
+variable "skip_event_notifications_iam_authorization_policy" {
+ type = bool
+ description = "If set to true, this skips the creation of a service to service authorization from Secrets Manager to Event Notifications. If false, the service to service authorization is created."
+ default = false
+}
+
+variable "event_notifications_email_list" {
+ type = list(string)
+ description = "The list of email address to target out when Secrets Manager triggers an event"
+ default = []
+}
+
+variable "event_notifications_from_email" {
+ type = string
+ description = "The email address used to send any Secrets Manager event coming via Event Notifications"
+ default = "compliancealert@ibm.com"
+}
+
+variable "event_notifications_reply_to_email" {
+ type = string
+ description = "The email address specified in the 'reply_to' section for any Secret Manager event coming via Event Notifications"
+ default = "no-reply@ibm.com"
+}
+
+##############################################################
+# Context-based restriction (CBR)
+##############################################################
+
+variable "secrets_manager_cbr_rules" {
+ type = list(object({
+ description = string
+ account_id = string
+ rule_contexts = list(object({
+ attributes = optional(list(object({
+ name = string
+ value = string
+ }))) }))
+ enforcement_mode = string
+ operations = optional(list(object({
+ api_types = list(object({
+ api_type_id = string
+ }))
+ })))
+ }))
+ description = "(Optional, list) List of CBR rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/fully-configurable/DA-cbr_rules.md)"
+ default = []
+ # Validation happens in the rule module
+}
diff --git a/solutions/security-enforced/version.tf b/solutions/security-enforced/version.tf
new file mode 100644
index 00000000..70b38b5b
--- /dev/null
+++ b/solutions/security-enforced/version.tf
@@ -0,0 +1,6 @@
+terraform {
+ required_version = ">= 1.9.0"
+ # Lock DA into an exact provider version - renovate automation will keep it updated
+ required_providers {
+ }
+}
diff --git a/solutions/standard/README.md b/solutions/standard/README.md
deleted file mode 100644
index a34dc2f7..00000000
--- a/solutions/standard/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Secrets Manager solution
-
-This solution supports the following:
-- Creating a new resource group, or taking in an existing one.
-- Provisioning and configuring of a Secrets Manager instance.
-- Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance.
-- Configuring KMS encryption using a newly created key, or passing an existing key.
-
-
-
-**NB:** This solution is not intended to be called by one or more other modules since it contains a provider configurations, meaning it is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers)
diff --git a/solutions/standard/moved.tf b/solutions/standard/moved.tf
deleted file mode 100644
index 4064d8b9..00000000
--- a/solutions/standard/moved.tf
+++ /dev/null
@@ -1,14 +0,0 @@
-moved {
- from = module.secrets_manager.ibm_resource_instance.secrets_manager_instance
- to = module.secrets_manager.module.secrets_manager.ibm_resource_instance.secrets_manager_instance
-}
-
-moved {
- from = module.secrets_manager.ibm_iam_authorization_policy.kms_policy
- to = module.secrets_manager.module.secrets_manager.ibm_iam_authorization_policy.kms_policy
-}
-
-moved {
- from = module.secrets_manager.time_sleep.wait_for_authorization_policy
- to = module.secrets_manager.module.secrets_manager.time_sleep.wait_for_authorization_policy
-}
diff --git a/tests/pr_test.go b/tests/pr_test.go
index 02678123..d2300c18 100644
--- a/tests/pr_test.go
+++ b/tests/pr_test.go
@@ -9,8 +9,6 @@ import (
"strings"
"testing"
- "github.com/IBM/go-sdk-core/v5/core"
- "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2"
"github.com/gruntwork-io/terratest/modules/files"
"github.com/gruntwork-io/terratest/modules/logger"
"github.com/gruntwork-io/terratest/modules/random"
@@ -24,9 +22,10 @@ import (
const completeExampleTerraformDir = "examples/complete"
const fscloudExampleTerraformDir = "examples/fscloud"
-const solutionsTerraformDir = "solutions/standard"
+const fullyConfigurableTerraformDir = "solutions/fully-configurable"
+const securityEnforcedTerraformDir = "solutions/security-enforced"
-const resourceGroup = "geretain-test-scc-module"
+const resourceGroup = "geretain-test-secrets-manager"
// Define a struct with fields that match the structure of the YAML data
const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml"
@@ -70,28 +69,21 @@ func setupOptions(t *testing.T, prefix string, checkApplyResultForUpgrade bool)
return options
}
-func TestRunDASolutionSchematics(t *testing.T) {
- t.Parallel()
-
- acme_letsencrypt_private_key := GetSecretsManagerKey( // pragma: allowlist secret
- permanentResources["acme_letsencrypt_private_key_sm_id"].(string),
- permanentResources["acme_letsencrypt_private_key_sm_region"].(string),
- permanentResources["acme_letsencrypt_private_key_secret_id"].(string),
- )
+func TestRunFullyConfigurableSchematics(t *testing.T) {
// Set up a schematics test
options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{
Testing: t,
TarIncludePatterns: []string{
"*.tf",
- fmt.Sprintf("%s/*.tf", solutionsTerraformDir),
+ fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir),
fmt.Sprintf("%s/*.tf", fscloudExampleTerraformDir),
fmt.Sprintf("%s/*.tf", "modules/secrets"),
fmt.Sprintf("%s/*.tf", "modules/fscloud"),
},
- TemplateFolder: solutionsTerraformDir,
+ TemplateFolder: fullyConfigurableTerraformDir,
ResourceGroup: resourceGroup,
- Prefix: "sm-da",
+ Prefix: "sm-fc",
Tags: []string{"test-schematic"},
DeleteWorkspaceOnFail: false,
WaitJobCompleteMinutes: 60,
@@ -101,53 +93,22 @@ func TestRunDASolutionSchematics(t *testing.T) {
{Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
{Name: "prefix", Value: options.Prefix, DataType: "string"},
{Name: "region", Value: validRegions[rand.Intn(len(validRegions))], DataType: "string"},
- {Name: "resource_group_name", Value: options.Prefix, DataType: "string"},
+ {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"},
{Name: "service_plan", Value: "trial", DataType: "string"},
- {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
- {Name: "iam_engine_enabled", Value: true, DataType: "bool"},
- {Name: "public_engine_enabled", Value: true, DataType: "bool"},
- {Name: "private_engine_enabled", Value: true, DataType: "bool"},
- {Name: "cis_id", Value: permanentResources["cisInstanceId"], DataType: "string"},
- {Name: "ca_name", Value: permanentResources["certificateAuthorityName"], DataType: "string"},
- {Name: "dns_provider_name", Value: permanentResources["dnsProviderName"], DataType: "string"},
- {Name: "acme_letsencrypt_private_key", Value: *acme_letsencrypt_private_key, DataType: "string"},
}
err := options.RunSchematicTest()
assert.NoError(t, err, "Schematic Test had unexpected error")
}
-func GetSecretsManagerKey(sm_id string, sm_region string, sm_key_id string) *string {
- secretsManagerService, err := secretsmanagerv2.NewSecretsManagerV2(&secretsmanagerv2.SecretsManagerV2Options{
- URL: fmt.Sprintf("https://%s.%s.secrets-manager.appdomain.cloud", sm_id, sm_region),
- Authenticator: &core.IamAuthenticator{
- ApiKey: os.Getenv("TF_VAR_ibmcloud_api_key"),
- },
- })
- if err != nil {
- panic(err)
- }
-
- getSecretOptions := secretsManagerService.NewGetSecretOptions(
- sm_key_id,
- )
-
- secret, _, err := secretsManagerService.GetSecret(getSecretOptions)
- if err != nil {
- panic(err)
- }
- return secret.(*secretsmanagerv2.ArbitrarySecret).Payload
-}
-
-// A test to pass existing resources to the SM DA
-func TestRunExistingResourcesInstances(t *testing.T) {
+func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) {
t.Parallel()
// ------------------------------------------------------------------------------------
// Provision Event Notification, KMS key and resource group first
// ------------------------------------------------------------------------------------
region := validRegions[rand.Intn(len(validRegions))]
- prefix := fmt.Sprintf("scc-exist-%s", strings.ToLower(random.UniqueId()))
+ prefix := fmt.Sprintf("sm-exist-%s", strings.ToLower(random.UniqueId()))
realTerraformDir := ".."
tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId())))
tags := common.GetTagsFromTravis()
@@ -183,12 +144,13 @@ func TestRunExistingResourcesInstances(t *testing.T) {
Testing: t,
TarIncludePatterns: []string{
"*.tf",
- fmt.Sprintf("%s/*.tf", solutionsTerraformDir),
+ fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir),
fmt.Sprintf("%s/*.tf", "modules/secrets"),
fmt.Sprintf("%s/*.tf", "modules/fscloud"),
},
- TemplateFolder: solutionsTerraformDir,
+ TemplateFolder: fullyConfigurableTerraformDir,
ResourceGroup: resourceGroup,
+ Prefix: "ex-fc",
Tags: []string{"test-schematic"},
DeleteWorkspaceOnFail: false,
WaitJobCompleteMinutes: 60,
@@ -196,17 +158,13 @@ func TestRunExistingResourcesInstances(t *testing.T) {
options.TerraformVars = []testschematic.TestSchematicTerraformVar{
{Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
+ {Name: "prefix", Value: options.Prefix, DataType: "string"},
{Name: "region", Value: region, DataType: "string"},
- {Name: "resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"},
- {Name: "use_existing_resource_group", Value: true, DataType: "bool"},
- {Name: "enable_event_notification", Value: true, DataType: "bool"},
+ {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"},
{Name: "existing_event_notification_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "event_notification_instance_crn"), DataType: "string"},
{Name: "existing_secrets_manager_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"},
- {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
+ {Name: "kms_encryption_enabled", Value: true, DataType: "bool"},
{Name: "service_plan", Value: "trial", DataType: "string"},
- {Name: "iam_engine_enabled", Value: true, DataType: "bool"},
- {Name: "private_engine_enabled", Value: true, DataType: "bool"},
- {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
}
err := options.RunSchematicTest()
@@ -226,28 +184,85 @@ func TestRunExistingResourcesInstances(t *testing.T) {
}
}
-func TestRunSecretsManagerSolutionUpgradeSchematic(t *testing.T) {
- t.Parallel()
+func TestRunExistingSMInstanceFullyConfigurable(t *testing.T) {
+ options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{
+ Testing: t,
+ TarIncludePatterns: []string{
+ "*.tf",
+ fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir),
+ fmt.Sprintf("%s/*.tf", "modules/secrets"),
+ fmt.Sprintf("%s/*.tf", "modules/fscloud"),
+ },
+ TemplateFolder: fullyConfigurableTerraformDir,
+ ResourceGroup: resourceGroup,
+ Prefix: "ex-scm",
+ Tags: []string{"test-schematic"},
+ DeleteWorkspaceOnFail: false,
+ WaitJobCompleteMinutes: 60,
+ })
+
+ options.TerraformVars = []testschematic.TestSchematicTerraformVar{
+ {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
+ {Name: "prefix", Value: options.Prefix, DataType: "string"},
+ {Name: "region", Value: validRegions[rand.Intn(len(validRegions))], DataType: "string"},
+ {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"},
+ {Name: "existing_secrets_manager_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"},
+ {Name: "service_plan", Value: "trial", DataType: "string"},
+ }
+
+ err := options.RunSchematicTest()
+ assert.NoError(t, err, "Schematic Test had unexpected error")
+}
- acme_letsencrypt_private_key := GetSecretsManagerKey( // pragma: allowlist secret
- permanentResources["acme_letsencrypt_private_key_sm_id"].(string),
- permanentResources["acme_letsencrypt_private_key_sm_region"].(string),
- permanentResources["acme_letsencrypt_private_key_secret_id"].(string),
- )
+func TestRunSecurityEnforcedSchematics(t *testing.T) {
// Set up a schematics test
options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{
Testing: t,
TarIncludePatterns: []string{
"*.tf",
- fmt.Sprintf("%s/*.tf", solutionsTerraformDir),
+ fmt.Sprintf("%s/*.tf", securityEnforcedTerraformDir),
+ fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir),
fmt.Sprintf("%s/*.tf", fscloudExampleTerraformDir),
fmt.Sprintf("%s/*.tf", "modules/secrets"),
fmt.Sprintf("%s/*.tf", "modules/fscloud"),
},
- TemplateFolder: solutionsTerraformDir,
+ TemplateFolder: securityEnforcedTerraformDir,
+ ResourceGroup: resourceGroup,
+ Prefix: "sm-se",
+ Tags: []string{"test-schematic"},
+ DeleteWorkspaceOnFail: false,
+ WaitJobCompleteMinutes: 60,
+ })
+
+ options.TerraformVars = []testschematic.TestSchematicTerraformVar{
+ {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
+ {Name: "prefix", Value: options.Prefix, DataType: "string"},
+ {Name: "region", Value: validRegions[rand.Intn(len(validRegions))], DataType: "string"},
+ {Name: "existing_resource_group_name", Value: "geretain-test-secrets-manager", DataType: "string"},
+ {Name: "service_plan", Value: "trial", DataType: "string"},
+ {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
+ }
+
+ err := options.RunSchematicTest()
+ assert.NoError(t, err, "Schematic Test had unexpected error")
+}
+
+func TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(t *testing.T) {
+
+ // Set up a schematics test
+ options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{
+ Testing: t,
+ TarIncludePatterns: []string{
+ "*.tf",
+ fmt.Sprintf("%s/*.tf", securityEnforcedTerraformDir),
+ fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir),
+ fmt.Sprintf("%s/*.tf", "modules/secrets"),
+ fmt.Sprintf("%s/*.tf", "modules/fscloud"),
+ },
+ TemplateFolder: securityEnforcedTerraformDir,
ResourceGroup: resourceGroup,
- Prefix: "sm-da",
+ Prefix: "sm-se-ug",
Tags: []string{"test-schematic"},
DeleteWorkspaceOnFail: false,
WaitJobCompleteMinutes: 60,
@@ -257,16 +272,9 @@ func TestRunSecretsManagerSolutionUpgradeSchematic(t *testing.T) {
{Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true},
{Name: "prefix", Value: options.Prefix, DataType: "string"},
{Name: "region", Value: validRegions[rand.Intn(len(validRegions))], DataType: "string"},
- {Name: "resource_group_name", Value: options.Prefix, DataType: "string"},
+ {Name: "existing_resource_group_name", Value: "geretain-test-secrets-manager", DataType: "string"},
{Name: "service_plan", Value: "trial", DataType: "string"},
{Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"},
- {Name: "iam_engine_enabled", Value: true, DataType: "bool"},
- {Name: "public_engine_enabled", Value: true, DataType: "bool"},
- {Name: "private_engine_enabled", Value: true, DataType: "bool"},
- {Name: "cis_id", Value: permanentResources["cisInstanceId"], DataType: "string"},
- {Name: "ca_name", Value: permanentResources["certificateAuthorityName"], DataType: "string"},
- {Name: "dns_provider_name", Value: permanentResources["dnsProviderName"], DataType: "string"},
- {Name: "acme_letsencrypt_private_key", Value: *acme_letsencrypt_private_key, DataType: "string"},
}
err := options.RunSchematicUpgradeTest()