From 781c0a678ffba4aceb1069b4a2db23df7fc3c781 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Wed, 5 Mar 2025 11:54:52 +0530 Subject: [PATCH 01/19] add : fully configurable version --- .catalog-onboard-pipeline.yaml | 2 +- common-dev-assets | 2 +- cra-config.yaml | 2 +- ibm_catalog.json | 12 +- .../DA-cbr_rules.md | 0 .../README.md | 0 .../catalogValidationValues.json.template | 7 + solutions/Fully configurable/main.tf | 235 +++++++++++++ .../outputs.tf | 0 .../provider.tf | 0 solutions/Fully configurable/variables.tf | 316 ++++++++++++++++++ solutions/Fully configurable/version.tf | 14 + solutions/Security-enforced/DA-cbr_rules.md | 62 ++++ solutions/Security-enforced/README.md | 11 + .../catalogValidationValues.json.template | 0 .../{standard => Security-enforced}/main.tf | 5 +- .../{standard => Security-enforced}/moved.tf | 0 solutions/Security-enforced/outputs.tf | 34 ++ solutions/Security-enforced/provider.tf | 11 + .../variables.tf | 11 +- .../version.tf | 0 tests/pr_test.go | 2 +- 22 files changed, 703 insertions(+), 23 deletions(-) rename solutions/{standard => Fully configurable}/DA-cbr_rules.md (100%) rename solutions/{standard => Fully configurable}/README.md (100%) create mode 100644 solutions/Fully configurable/catalogValidationValues.json.template create mode 100644 solutions/Fully configurable/main.tf rename solutions/{standard => Fully configurable}/outputs.tf (100%) rename solutions/{standard => Fully configurable}/provider.tf (100%) create mode 100644 solutions/Fully configurable/variables.tf create mode 100644 solutions/Fully configurable/version.tf create mode 100644 solutions/Security-enforced/DA-cbr_rules.md create mode 100644 solutions/Security-enforced/README.md rename solutions/{standard => Security-enforced}/catalogValidationValues.json.template (100%) rename solutions/{standard => Security-enforced}/main.tf (95%) rename solutions/{standard => Security-enforced}/moved.tf (100%) create mode 100644 solutions/Security-enforced/outputs.tf create mode 100644 solutions/Security-enforced/provider.tf rename solutions/{standard => Security-enforced}/variables.tf (96%) rename solutions/{standard => Security-enforced}/version.tf (100%) diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml index 019c7766..e62e8852 100644 --- a/.catalog-onboard-pipeline.yaml +++ b/.catalog-onboard-pipeline.yaml @@ -6,7 +6,7 @@ offerings: catalog_id: 7df1e4ca-d54c-4fd0-82ce-3d13247308cd offering_id: 6d6ebc76-7bbd-42f5-8bc7-78f4fabd5944 variations: - - name: standard + - name: Security-enforced mark_ready: true install_type: fullstack scc: diff --git a/common-dev-assets b/common-dev-assets index c3e67b4a..8c7a97cb 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit c3e67b4ab4ed41f1b0239ae52e306dc8737ea591 +Subproject commit 8c7a97cb00b128503d2c81380be904b6d196cc02 diff --git a/cra-config.yaml b/cra-config.yaml index 465562e0..21551545 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,7 +1,7 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "solutions/standard" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - CRA_TARGET: "solutions/Security-enforced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. diff --git a/ibm_catalog.json b/ibm_catalog.json index e0182bf6..848a9fdb 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -21,7 +21,7 @@ ], "short_description": "Creates and configures a Secrets Manager instance.", "long_description": "This solution is used to provision and configure an IBM Cloud Secrets Manager instance.", - "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/standard/README.md", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/Security-enforced/README.md", "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-secrets-manager/main/images/secrets_manager.svg", "provider_name": "IBM", "features": [ @@ -45,10 +45,10 @@ "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues). Please note this product is not supported via the IBM Cloud Support Center.", "flavors": [ { - "label": "Standard", - "name": "standard", + "label": "Security-enforced", + "name": "Security-enforced", "install_type": "fullstack", - "working_directory": "solutions/standard", + "working_directory": "solutions/Security-enforced", "compliance": { "authority": "scc-v3", "profiles": [ @@ -162,8 +162,8 @@ "key": "service_plan", "options": [ { - "displayname": "Standard", - "value": "standard" + "displayname": "Security-enforced", + "value": "Security-enforced" }, { "displayname": "Trial", diff --git a/solutions/standard/DA-cbr_rules.md b/solutions/Fully configurable/DA-cbr_rules.md similarity index 100% rename from solutions/standard/DA-cbr_rules.md rename to solutions/Fully configurable/DA-cbr_rules.md diff --git a/solutions/standard/README.md b/solutions/Fully configurable/README.md similarity index 100% rename from solutions/standard/README.md rename to solutions/Fully configurable/README.md diff --git a/solutions/Fully configurable/catalogValidationValues.json.template b/solutions/Fully configurable/catalogValidationValues.json.template new file mode 100644 index 00000000..6f0c3500 --- /dev/null +++ b/solutions/Fully configurable/catalogValidationValues.json.template @@ -0,0 +1,7 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "resource_group_name": $PREFIX, + "service_plan": "trial", + "existing_kms_instance_crn": $HPCS_US_EAST_CRN, + "region": "ca-tor" +} diff --git a/solutions/Fully configurable/main.tf b/solutions/Fully configurable/main.tf new file mode 100644 index 00000000..fc554167 --- /dev/null +++ b/solutions/Fully configurable/main.tf @@ -0,0 +1,235 @@ +######################################################################################################################## +# Resource Group +######################################################################################################################## +locals { + # tflint-ignore: terraform_unused_declarations + validate_event_notifications = (var.existing_event_notification_instance_crn == null && var.enable_event_notification) ? tobool("To enable event notifications, an existing event notifications CRN must be set.") : true +} + +module "resource_group" { + count = var.existing_secrets_manager_crn == null ? 1 : 0 + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + 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 = var.prefix != null ? "${var.prefix}-${var.kms_key_ring_name}" : var.kms_key_ring_name + kms_key_name = var.prefix != null ? "${var.prefix}-${var.kms_key_name}" : 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 + existing_kms_guid = length(local.parsed_existing_kms_instance_crn) > 0 ? local.parsed_existing_kms_instance_crn[7] : null + create_cross_account_auth_policy = !var.skip_kms_iam_authorization_policy && var.ibmcloud_kms_api_key != null + + kms_service_name = local.kms_key_crn != null ? ( + can(regex(".*kms.*", local.kms_key_crn)) ? "kms" : can(regex(".*hs-crypto.*", local.kms_key_crn)) ? "hs-crypto" : null + ) : null +} + +data "ibm_iam_account_settings" "iam_account_settings" { + count = local.create_cross_account_auth_policy ? 1 : 0 +} + +resource "ibm_iam_authorization_policy" "kms_policy" { + count = local.create_cross_account_auth_policy ? 1 : 0 + provider = ibm.kms + source_service_account = data.ibm_iam_account_settings.iam_account_settings[0].account_id + source_service_name = "secrets-manager" + source_resource_group_id = module.resource_group[0].resource_group_id + target_service_name = local.kms_service_name + target_resource_instance_id = local.existing_kms_guid + 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 from the ${local.kms_service_name} instance GUID ${local.existing_kms_guid}" +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_authorization_policy" { + count = local.create_cross_account_auth_policy ? 1 : 0 + depends_on = [ibm_iam_authorization_policy.kms_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 + source = "terraform-ibm-modules/kms-all-inclusive/ibm" + version = "4.19.1" + create_key_protect_instance = false + region = local.kms_region + existing_kms_instance_crn = var.existing_kms_instance_crn + key_ring_endpoint_type = var.kms_endpoint_type + key_endpoint_type = var.kms_endpoint_type + keys = [ + { + key_ring_name = local.kms_key_ring_name + existing_key_ring = false + keys = [ + { + key_name = local.kms_key_name + standard_key = false + rotation_interval_month = 3 + dual_auth_delete_enabled = false + force_delete = true + } + ] + } + ] +} + +######################################################################################################################## +# Secrets Manager +######################################################################################################################## + +locals { + parsed_existing_secrets_manager_crn = var.existing_secrets_manager_crn != null ? split(":", var.existing_secrets_manager_crn) : [] + 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 + sm_endpoint_type = var.existing_secrets_manager_crn != null ? var.existing_secrets_endpoint_type : var.allowed_network == "private-only" ? "private" : "public" +} + +module "secrets_manager" { + depends_on = [time_sleep.wait_for_authorization_policy] + source = "../.." + 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 = var.prefix != null ? "${var.prefix}-${var.secrets_manager_instance_name}" : var.secrets_manager_instance_name + sm_service_plan = var.service_plan + allowed_network = var.allowed_network + sm_tags = var.secret_manager_tags + # kms dependency + kms_encryption_enabled = var.kms_encryption_enabled + existing_kms_instance_guid = local.existing_kms_guid + kms_key_crn = local.kms_key_crn + skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy || local.create_cross_account_auth_policy + # event notifications dependency + enable_event_notification = var.enable_event_notification + existing_en_instance_crn = var.existing_event_notification_instance_crn + skip_en_iam_authorization_policy = var.skip_event_notification_iam_authorization_policy + endpoint_type = local.sm_endpoint_type + 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.6" + region = local.secrets_manager_region + iam_engine_name = var.prefix != null ? "${var.prefix}-${var.iam_engine_name}" : var.iam_engine_name + secrets_manager_guid = local.secrets_manager_guid + endpoint_type = local.sm_endpoint_type +} + +locals { + # tflint-ignore: terraform_unused_declarations + validate_public_secret_engine = var.public_engine_enabled && var.public_engine_name == null ? tobool("When setting var.public_engine_enabled to true, a value must be passed for var.public_engine_name") : true + # tflint-ignore: terraform_unused_declarations + validate_private_secret_engine = var.private_engine_enabled && var.private_engine_name == null ? tobool("When setting var.private_engine_enabled to true, a value must be passed for var.private_engine_name") : true +} + +# Configure an IBM Secrets Manager public certificate engine for an existing IBM Secrets Manager instance. +module "secrets_manager_public_cert_engine" { + count = var.public_engine_enabled ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-public-cert-engine/ibm" + version = "1.0.2" + providers = { + ibm = ibm + ibm.secret-store = ibm + } + secrets_manager_guid = local.secrets_manager_guid + region = local.secrets_manager_region + internet_services_crn = var.cis_id + ibmcloud_cis_api_key = var.ibmcloud_api_key + dns_config_name = var.dns_provider_name + ca_config_name = var.ca_name + acme_letsencrypt_private_key = var.acme_letsencrypt_private_key + service_endpoints = local.sm_endpoint_type +} + + +# Configure an IBM Secrets Manager private certificate engine for an existing IBM Secrets Manager instance. +module "private_secret_engine" { + count = var.private_engine_enabled ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-private-cert-engine/ibm" + version = "1.3.4" + secrets_manager_guid = local.secrets_manager_guid + region = var.region + root_ca_name = var.root_ca_name + root_ca_common_name = var.root_ca_common_name + root_ca_max_ttl = var.root_ca_max_ttl + intermediate_ca_name = var.intermediate_ca_name + certificate_template_name = var.certificate_template_name + endpoint_type = local.sm_endpoint_type +} + +data "ibm_resource_instance" "existing_sm" { + count = var.existing_secrets_manager_crn == null ? 0 : 1 + identifier = var.existing_secrets_manager_crn +} + +####################################################################################################################### +# Secrets Manager Event Notifications Configuration +####################################################################################################################### + +locals { + parsed_existing_en_instance_crn = var.existing_event_notification_instance_crn != null ? split(":", var.existing_event_notification_instance_crn) : [] + existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null +} + +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_notification ? 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_notification ? 1 : 0 + depends_on = [module.secrets_manager] + + create_duration = "30s" +} + +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_notification ? 1 : 0 + depends_on = [time_sleep.wait_for_secrets_manager] + instance_guid = local.existing_en_guid + name = "Secrets Manager Topic" + description = "Topic for Secrets Manager events routing" + sources { + id = local.secrets_manager_crn + rules { + enabled = true + event_type_filter = "$.*" + } + } +} + +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_notification && length(var.sm_en_email_list) > 0 ? 1 : 0 + instance_guid = local.existing_en_guid + name = "Email for Secrets Manager Subscription" + description = "Subscription for Secret Manager Events" + destination_id = [for s in toset(data.ibm_en_destinations.en_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_topic[count.index].topic_id + attributes { + add_notification_payload = true + reply_to_mail = var.sm_en_reply_to_email + reply_to_name = "Secret Manager Event Notifications Bot" + from_name = var.sm_en_from_email + invited = var.sm_en_email_list + } +} diff --git a/solutions/standard/outputs.tf b/solutions/Fully configurable/outputs.tf similarity index 100% rename from solutions/standard/outputs.tf rename to solutions/Fully configurable/outputs.tf 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/Fully configurable/variables.tf b/solutions/Fully configurable/variables.tf new file mode 100644 index 00000000..4bf70106 --- /dev/null +++ b/solutions/Fully configurable/variables.tf @@ -0,0 +1,316 @@ +######################################################################################################################## +# Common variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The API Key to use for IBM Cloud." + sensitive = true +} + +variable "provider_visibility" { + description = "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)." + type = string + default = "private" + + validation { + condition = contains(["public", "private", "public-and-private"], var.provider_visibility) + error_message = "Invalid visibility option. Allowed values are 'public', 'private', or 'public-and-private'." + } +} +variable "existing_resource_group_name" { + type = string + description = "Name of the existing resource group." +} + +variable "region" { + type = string + description = "The region to provision resources to." + default = "us-south" +} + +variable "prefix" { + type = string + description = "The prefix to apply to all resources created by this solution." + default = null +} + +######################################################################################################################## +# 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." + default = "base-security-services-sm" +} + +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 "existing_secrets_endpoint_type" { + type = string + description = "The endpoint type to use if existing_secrets_manager_crn is specified. Possible values: public, private." + default = "private" + validation { + condition = contains(["public", "private"], var.existing_secrets_endpoint_type) + error_message = "Only \"public\" and \"private\" are allowed values for 'existing_secrets_endpoint_type'." + } +} + +variable "service_plan" { + type = string + description = "The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. Applies only if `provision_sm_instance` is set to `true`." + default = "standard" + validation { + condition = contains(["standard", "trial"], var.service_plan) + error_message = "Only \"standard\" and \"trial\" are allowed values for sm_service_plan." + } +} + +variable "allowed_network" { + type = string + description = "The types of service endpoints to set on the Secrets Manager instance. Possible values: `private-only`, `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." + } +} + +variable "kms_encryption_enabled" { + type = bool + description = "Set this to true to control the encryption keys used to encrypt the data that you store in Secrets Manager. If set to false, the data that you store is encrypted at rest by using envelope encryption. For more details, see https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-mng-data&interface=ui#about-encryption." + default = false +} + +variable "secret_manager_tags" { + type = list(any) + description = "The list of resource tags you want to associate with your Secrets Manager instance." + default = [] +} + +variable "public_engine_enabled" { + 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." + default = false +} + +######################################################################################################################## +# Public cert engine config +######################################################################################################################## + +variable "public_engine_name" { + type = string + description = "The name of the IAM engine used to configure a Secrets Manager public certificate engine for an existing instance." + default = "public-engine-sm" +} + +variable "cis_id" { + type = string + description = "Cloud Internet Service ID." + default = null +} + +variable "dns_provider_name" { + type = string + description = "The name of the DNS provider for the public certificate secrets engine configuration." + default = "certificate-dns" +} + +variable "ca_name" { + type = string + description = "The name of the certificate authority for Secrets Manager." + default = "cert-auth" +} + +variable "acme_letsencrypt_private_key" { + type = string + description = "The private key generated by the ACME account creation tool." + sensitive = true + default = null +} + +######################################################################################################################## +# Private cert engine config +######################################################################################################################## + +variable "private_engine_enabled" { + 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." + default = false +} + +variable "private_engine_name" { + type = string + description = "The name of the IAM Engine used to configure a Secrets Manager private certificate engine for an existing instance." + default = "private-engine-sm" +} + +variable "root_ca_name" { + type = string + description = "The name of the root certificate authority associated with the private_cert secret engine." + default = "root-ca" +} + +variable "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 "root_ca_max_ttl" { + type = string + description = "The maximum time-to-live value for the root certificate authority." + default = "87600h" +} + +variable "intermediate_ca_name" { + type = string + description = "A human-readable unique name to assign to the intermediate certificate authority configuration." + default = "intermediate-ca" +} + +variable "certificate_template_name" { + type = string + description = "The name of the certificate template." + default = "default-cert-template" +} + +######################################################################################################################## +# IAM engine config +######################################################################################################################## + +variable "iam_engine_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." + 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 = "base-sm-iam-engine" +} + +######################################################################################################################## +# Key Protect +######################################################################################################################## + +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 +} + +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`." +} + +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." + default = "private" + validation { + condition = can(regex("public|private", var.kms_endpoint_type)) + error_message = "The kms_endpoint_type value must be 'public' or 'private'." + } +} + +variable "kms_key_ring_name" { + type = string + default = "sm-cos-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 = "sm-cos-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 "enable_event_notification" { + 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_en_instance_crn` and `existing_sm_instance_crn` must be null." +} + +variable "existing_event_notification_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_notification_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 "sm_en_email_list" { + type = list(string) + description = "The list of email address to target out when Secrets Manager triggers an event" + default = [] +} + +variable "sm_en_from_email" { + type = string + description = "The email address in the used in the 'from' of any Secret Manager event coming from Event Notifications" + default = "compliancealert@ibm.com" +} + +variable "sm_en_reply_to_email" { + type = string + description = "The email address used in the 'reply_to' of any Secret Manager event coming from Event Notifications" + default = "no-reply@ibm.com" +} +############################################################## +# Context-based restriction (CBR) +############################################################## + +variable "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/standard/DA-cbr_rules.md)" + default = [] + # Validation happens in the rule module +} diff --git a/solutions/Fully configurable/version.tf b/solutions/Fully configurable/version.tf new file mode 100644 index 00000000..e51ef9af --- /dev/null +++ b/solutions/Fully configurable/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.3.0" + # Lock DA into an exact provider version - renovate automation will keep it updated + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.74.0" + } + time = { + source = "hashicorp/time" + version = "0.12.1" + } + } +} diff --git a/solutions/Security-enforced/DA-cbr_rules.md b/solutions/Security-enforced/DA-cbr_rules.md new file mode 100644 index 00000000..155a5368 --- /dev/null +++ b/solutions/Security-enforced/DA-cbr_rules.md @@ -0,0 +1,62 @@ +# Configuring complex inputs for Secrets Manager in IBM Cloud projects + +Several optional input variables in the IBM Cloud [Secrets Manager deployable architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You specify these inputs when you configure deployable architecture. + +* Context-Based Restrictions Rules (`cbr_rules`) + + +## Rules For Context-Based Restrictions + +The `cbr_rules` input variable allows you to provide a rule for the target service to enforce access restrictions for the service based on the context of access requests. Contexts are criteria that include the network location of access requests, the endpoint type from where the request is sent, etc. + +- Variable name: `cbr_rules`. +- Type: A list of objects. Allows only one object representing a rule for the target service +- Default value: An empty list (`[]`). + +### Options for cbr_rules + + - `description` (required): The description of the rule to create. + - `account_id` (required): The IBM Cloud Account ID + - `rule_contexts` (required): (List) The contexts the rule applies to + - `attributes` (optional): (List) Individual context attributes + - `name` (required): The attribute name. + - `value`(required): The attribute value. + + - `enforcement_mode` (required): The rule enforcement mode can have the following values: + - `enabled` - The restrictions are enforced and reported. This is the default. + - `disabled` - The restrictions are disabled. Nothing is enforced or reported. + - `report` - The restrictions are evaluated and reported, but not enforced. + - `operations` (optional): The operations this rule applies to + - `api_types`(required): (List) The API types this rule applies to. + - `api_type_id`(required):The API type ID + + +### Example Rule For Context-Based Restrictions Configuration + +```hcl +cbr_rules = [ + { + description = "Secrets Manager can be accessed from xyz" + account_id = "defc0df06b644a9cabc6e44f55b3880s." + rule_contexts= [{ + attributes = [ + { + "name" : "endpointType", + "value" : "private" + }, + { + name = "networkZoneId" + value = "93a51a1debe2674193217209601dde6f" # pragma: allowlist secret + } + ] + } + ] + enforcement_mode = "enabled" + operations = [{ + api_types = [{ + api_type_id = "crn:v1:bluemix:public:context-based-restrictions::::api-type:" + }] + }] + } +] +``` diff --git a/solutions/Security-enforced/README.md b/solutions/Security-enforced/README.md new file mode 100644 index 00000000..a34dc2f7 --- /dev/null +++ b/solutions/Security-enforced/README.md @@ -0,0 +1,11 @@ +# 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. + +![secret-manager-deployable-architecture](../../reference-architecture/secrets_manager.svg) + +**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/catalogValidationValues.json.template b/solutions/Security-enforced/catalogValidationValues.json.template similarity index 100% rename from solutions/standard/catalogValidationValues.json.template rename to solutions/Security-enforced/catalogValidationValues.json.template diff --git a/solutions/standard/main.tf b/solutions/Security-enforced/main.tf similarity index 95% rename from solutions/standard/main.tf rename to solutions/Security-enforced/main.tf index b3335941..818b94f9 100644 --- a/solutions/standard/main.tf +++ b/solutions/Security-enforced/main.tf @@ -2,8 +2,6 @@ # 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 @@ -13,8 +11,7 @@ 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 } ####################################################################################################################### diff --git a/solutions/standard/moved.tf b/solutions/Security-enforced/moved.tf similarity index 100% rename from solutions/standard/moved.tf rename to solutions/Security-enforced/moved.tf diff --git a/solutions/Security-enforced/outputs.tf b/solutions/Security-enforced/outputs.tf new file mode 100644 index 00000000..9c4d0c8f --- /dev/null +++ b/solutions/Security-enforced/outputs.tf @@ -0,0 +1,34 @@ +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 +} + +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 +} + +output "secrets_manager_guid" { + description = "GUID of Secrets Manager instance" + value = local.secrets_manager_guid +} + +output "secrets_manager_id" { + description = "ID of Secrets Manager instance. Same value as secrets_manager_guid" + value = var.existing_secrets_manager_crn == null ? module.secrets_manager.secrets_manager_id : local.secrets_manager_guid +} + +output "secrets_manager_name" { + value = var.existing_secrets_manager_crn == null ? module.secrets_manager.secrets_manager_name : data.ibm_resource_instance.existing_sm[0].resource_name + description = "Name of the Secrets Manager instance" +} + +output "secrets_manager_crn" { + value = local.secrets_manager_crn + description = "CRN of the Secrets Manager instance" +} + +output "secrets_manager_region" { + value = local.secrets_manager_region + description = "Region of the Secrets Manager instance" +} diff --git a/solutions/Security-enforced/provider.tf b/solutions/Security-enforced/provider.tf new file mode 100644 index 00000000..65c38f7d --- /dev/null +++ b/solutions/Security-enforced/provider.tf @@ -0,0 +1,11 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region + visibility = var.provider_visibility +} +provider "ibm" { + alias = "kms" + ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key + region = local.kms_region + visibility = var.provider_visibility +} diff --git a/solutions/standard/variables.tf b/solutions/Security-enforced/variables.tf similarity index 96% rename from solutions/standard/variables.tf rename to solutions/Security-enforced/variables.tf index de0173c2..e235fc84 100644 --- a/solutions/standard/variables.tf +++ b/solutions/Security-enforced/variables.tf @@ -19,16 +19,9 @@ 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 = "Name of the existing resource group." } variable "region" { diff --git a/solutions/standard/version.tf b/solutions/Security-enforced/version.tf similarity index 100% rename from solutions/standard/version.tf rename to solutions/Security-enforced/version.tf diff --git a/tests/pr_test.go b/tests/pr_test.go index 362af949..c913044b 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -24,7 +24,7 @@ import ( const completeExampleTerraformDir = "examples/complete" const fscloudExampleTerraformDir = "examples/fscloud" -const solutionsTerraformDir = "solutions/standard" +const solutionsTerraformDir = "solutions/Security-enforced" const resourceGroup = "geretain-test-scc-module" From cf7ab9cdef0983da8c1fc7aa24a0d8bdaf449087 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Wed, 12 Mar 2025 14:49:25 +0530 Subject: [PATCH 02/19] working code for fully-configurable variation --- .catalog-onboard-pipeline.yaml | 8 +- cra-config.yaml | 2 +- examples/basic/version.tf | 2 +- examples/complete/version.tf | 2 +- examples/fscloud/version.tf | 2 +- ibm_catalog.json | 12 +- modules/fscloud/version.tf | 2 +- modules/secrets/version.tf | 2 +- .../catalogValidationValues.json.template | 7 - solutions/Security-enforced/DA-cbr_rules.md | 62 ---- solutions/Security-enforced/README.md | 11 - .../catalogValidationValues.json.template | 2 +- solutions/Security-enforced/main.tf | 226 -------------- solutions/Security-enforced/moved.tf | 14 - solutions/Security-enforced/outputs.tf | 34 --- solutions/Security-enforced/provider.tf | 11 - solutions/Security-enforced/variables.tf | 280 ------------------ solutions/Security-enforced/version.tf | 14 - .../DA-cbr_rules.md | 0 .../README.md | 0 .../catalogValidationValues.json.template | 7 + .../main.tf | 99 +++---- .../outputs.tf | 4 +- .../provider.tf | 0 .../variables.tf | 148 +++++---- .../version.tf | 4 +- tests/existing-resources/version.tf | 2 +- tests/pr_test.go | 15 +- version.tf | 2 +- 29 files changed, 145 insertions(+), 829 deletions(-) delete mode 100644 solutions/Fully configurable/catalogValidationValues.json.template rename solutions/{Fully configurable => fully-configurable}/DA-cbr_rules.md (100%) rename solutions/{Fully configurable => fully-configurable}/README.md (100%) create mode 100644 solutions/fully-configurable/catalogValidationValues.json.template rename solutions/{Fully configurable => fully-configurable}/main.tf (67%) rename solutions/{Fully configurable => fully-configurable}/outputs.tf (75%) rename solutions/{Fully configurable => fully-configurable}/provider.tf (100%) rename solutions/{Fully configurable => fully-configurable}/variables.tf (75%) rename solutions/{Fully configurable => fully-configurable}/version.tf (81%) diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml index e62e8852..aa1b21bd 100644 --- a/.catalog-onboard-pipeline.yaml +++ b/.catalog-onboard-pipeline.yaml @@ -6,7 +6,13 @@ offerings: catalog_id: 7df1e4ca-d54c-4fd0-82ce-3d13247308cd offering_id: 6d6ebc76-7bbd-42f5-8bc7-78f4fabd5944 variations: - - name: Security-enforced + - name: security-enforced + mark_ready: true + install_type: fullstack + scc: + instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 + region: us-south + - name: fully-configurable mark_ready: true install_type: fullstack scc: diff --git a/cra-config.yaml b/cra-config.yaml index 21551545..7dcfd090 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,7 +1,7 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "solutions/Security-enforced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - CRA_TARGET: "solutions/security-enforced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 2a34320c..bf6a8999 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= v1.0.0" + required_version = ">= v1.9.0" # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main # module's version.tf (this example), and 1 example that will always use the latest provider version (complete example). diff --git a/examples/complete/version.tf b/examples/complete/version.tf index c34bf04d..4aac0b35 100644 --- a/examples/complete/version.tf +++ b/examples/complete/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= v1.0.0" + required_version = ">= v1.9.0" required_providers { ibm = { source = "IBM-Cloud/ibm" diff --git a/examples/fscloud/version.tf b/examples/fscloud/version.tf index 8f37dab1..e6c04b07 100644 --- a/examples/fscloud/version.tf +++ b/examples/fscloud/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.9.0" required_providers { # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { diff --git a/ibm_catalog.json b/ibm_catalog.json index 848a9fdb..3e975068 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -21,7 +21,7 @@ ], "short_description": "Creates and configures a Secrets Manager instance.", "long_description": "This solution is used to provision and configure an IBM Cloud Secrets Manager instance.", - "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/Security-enforced/README.md", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/security-enforced/README.md", "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-secrets-manager/main/images/secrets_manager.svg", "provider_name": "IBM", "features": [ @@ -46,9 +46,9 @@ "flavors": [ { "label": "Security-enforced", - "name": "Security-enforced", + "name": "security-enforced", "install_type": "fullstack", - "working_directory": "solutions/Security-enforced", + "working_directory": "solutions/security-enforced", "compliance": { "authority": "scc-v3", "profiles": [ @@ -149,7 +149,7 @@ "key": "existing_secrets_manager_crn" }, { - "key": "secrets_manager_tags", + "key": "secrets_manager_resource_tags", "custom_config": { "grouping": "deployment", "original_grouping": "deployment", @@ -162,8 +162,8 @@ "key": "service_plan", "options": [ { - "displayname": "Security-enforced", - "value": "Security-enforced" + "displayname": "Standard", + "value": "standard" }, { "displayname": "Trial", diff --git a/modules/fscloud/version.tf b/modules/fscloud/version.tf index 8d342a5f..08387bee 100644 --- a/modules/fscloud/version.tf +++ b/modules/fscloud/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.9.0" required_providers { # The below tflint-ignore is required because although the below provider is not directly required by this submodule, # it is required by consuming modules, and if not set here, the top level module calling this module will not be diff --git a/modules/secrets/version.tf b/modules/secrets/version.tf index 8d342a5f..08387bee 100644 --- a/modules/secrets/version.tf +++ b/modules/secrets/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.9.0" required_providers { # The below tflint-ignore is required because although the below provider is not directly required by this submodule, # it is required by consuming modules, and if not set here, the top level module calling this module will not be diff --git a/solutions/Fully configurable/catalogValidationValues.json.template b/solutions/Fully configurable/catalogValidationValues.json.template deleted file mode 100644 index 6f0c3500..00000000 --- a/solutions/Fully configurable/catalogValidationValues.json.template +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ibmcloud_api_key": $VALIDATION_APIKEY, - "resource_group_name": $PREFIX, - "service_plan": "trial", - "existing_kms_instance_crn": $HPCS_US_EAST_CRN, - "region": "ca-tor" -} diff --git a/solutions/Security-enforced/DA-cbr_rules.md b/solutions/Security-enforced/DA-cbr_rules.md index 155a5368..e69de29b 100644 --- a/solutions/Security-enforced/DA-cbr_rules.md +++ b/solutions/Security-enforced/DA-cbr_rules.md @@ -1,62 +0,0 @@ -# Configuring complex inputs for Secrets Manager in IBM Cloud projects - -Several optional input variables in the IBM Cloud [Secrets Manager deployable architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You specify these inputs when you configure deployable architecture. - -* Context-Based Restrictions Rules (`cbr_rules`) - - -## Rules For Context-Based Restrictions - -The `cbr_rules` input variable allows you to provide a rule for the target service to enforce access restrictions for the service based on the context of access requests. Contexts are criteria that include the network location of access requests, the endpoint type from where the request is sent, etc. - -- Variable name: `cbr_rules`. -- Type: A list of objects. Allows only one object representing a rule for the target service -- Default value: An empty list (`[]`). - -### Options for cbr_rules - - - `description` (required): The description of the rule to create. - - `account_id` (required): The IBM Cloud Account ID - - `rule_contexts` (required): (List) The contexts the rule applies to - - `attributes` (optional): (List) Individual context attributes - - `name` (required): The attribute name. - - `value`(required): The attribute value. - - - `enforcement_mode` (required): The rule enforcement mode can have the following values: - - `enabled` - The restrictions are enforced and reported. This is the default. - - `disabled` - The restrictions are disabled. Nothing is enforced or reported. - - `report` - The restrictions are evaluated and reported, but not enforced. - - `operations` (optional): The operations this rule applies to - - `api_types`(required): (List) The API types this rule applies to. - - `api_type_id`(required):The API type ID - - -### Example Rule For Context-Based Restrictions Configuration - -```hcl -cbr_rules = [ - { - description = "Secrets Manager can be accessed from xyz" - account_id = "defc0df06b644a9cabc6e44f55b3880s." - rule_contexts= [{ - attributes = [ - { - "name" : "endpointType", - "value" : "private" - }, - { - name = "networkZoneId" - value = "93a51a1debe2674193217209601dde6f" # pragma: allowlist secret - } - ] - } - ] - enforcement_mode = "enabled" - operations = [{ - api_types = [{ - api_type_id = "crn:v1:bluemix:public:context-based-restrictions::::api-type:" - }] - }] - } -] -``` diff --git a/solutions/Security-enforced/README.md b/solutions/Security-enforced/README.md index a34dc2f7..e69de29b 100644 --- a/solutions/Security-enforced/README.md +++ b/solutions/Security-enforced/README.md @@ -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. - -![secret-manager-deployable-architecture](../../reference-architecture/secrets_manager.svg) - -**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/Security-enforced/catalogValidationValues.json.template b/solutions/Security-enforced/catalogValidationValues.json.template index 069d9f92..cd067095 100644 --- a/solutions/Security-enforced/catalogValidationValues.json.template +++ b/solutions/Security-enforced/catalogValidationValues.json.template @@ -1,6 +1,6 @@ { "ibmcloud_api_key": $VALIDATION_APIKEY, - "resource_group_name": $PREFIX, + "existing_resource_group_name": "geretain-test-secrets-manager", "service_plan": "trial", "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, "region": "ca-tor" diff --git a/solutions/Security-enforced/main.tf b/solutions/Security-enforced/main.tf index b4141ed5..e69de29b 100644 --- a/solutions/Security-enforced/main.tf +++ b/solutions/Security-enforced/main.tf @@ -1,226 +0,0 @@ -######################################################################################################################## -# Resource Group -######################################################################################################################## -locals { - # 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 -} - -module "resource_group" { - count = var.existing_secrets_manager_crn == null ? 1 : 0 - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.6" - 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) - - 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 - existing_kms_guid = length(local.parsed_existing_kms_instance_crn) > 0 ? local.parsed_existing_kms_instance_crn[7] : null - create_cross_account_auth_policy = !var.skip_kms_iam_authorization_policy && var.ibmcloud_kms_api_key != null - - kms_service_name = local.kms_key_crn != null ? ( - can(regex(".*kms.*", local.kms_key_crn)) ? "kms" : can(regex(".*hs-crypto.*", local.kms_key_crn)) ? "hs-crypto" : null - ) : null -} - -data "ibm_iam_account_settings" "iam_account_settings" { - count = local.create_cross_account_auth_policy ? 1 : 0 -} - -resource "ibm_iam_authorization_policy" "kms_policy" { - count = local.create_cross_account_auth_policy ? 1 : 0 - provider = ibm.kms - source_service_account = data.ibm_iam_account_settings.iam_account_settings[0].account_id - source_service_name = "secrets-manager" - source_resource_group_id = module.resource_group[0].resource_group_id - target_service_name = local.kms_service_name - target_resource_instance_id = local.existing_kms_guid - 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 from the ${local.kms_service_name} instance GUID ${local.existing_kms_guid}" -} - -# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 -resource "time_sleep" "wait_for_authorization_policy" { - count = local.create_cross_account_auth_policy ? 1 : 0 - depends_on = [ibm_iam_authorization_policy.kms_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 - source = "terraform-ibm-modules/kms-all-inclusive/ibm" - version = "4.20.0" - create_key_protect_instance = false - region = local.kms_region - existing_kms_instance_crn = var.existing_kms_instance_crn - key_ring_endpoint_type = var.kms_endpoint_type - key_endpoint_type = var.kms_endpoint_type - keys = [ - { - key_ring_name = local.kms_key_ring_name - existing_key_ring = false - keys = [ - { - key_name = local.kms_key_name - standard_key = false - rotation_interval_month = 3 - dual_auth_delete_enabled = false - force_delete = true - } - ] - } - ] -} - -######################################################################################################################## -# Secrets Manager -######################################################################################################################## - -locals { - parsed_existing_secrets_manager_crn = var.existing_secrets_manager_crn != null ? split(":", var.existing_secrets_manager_crn) : [] - 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 -} - -module "secrets_manager" { - depends_on = [time_sleep.wait_for_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 - # kms dependency - existing_kms_instance_guid = local.existing_kms_guid - kms_key_crn = local.kms_key_crn - skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy || local.create_cross_account_auth_policy - # event notifications dependency - enable_event_notification = var.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.8" - 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.2" - 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" -} - -data "ibm_resource_instance" "existing_sm" { - count = var.existing_secrets_manager_crn == null ? 0 : 1 - identifier = var.existing_secrets_manager_crn -} - -####################################################################################################################### -# Secrets Manager Event Notifications Configuration -####################################################################################################################### - -locals { - parsed_existing_en_instance_crn = var.existing_event_notifications_instance_crn != null ? split(":", var.existing_event_notifications_instance_crn) : [] - existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null -} - -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 - 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 - depends_on = [module.secrets_manager] - - create_duration = "30s" -} - -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 - depends_on = [time_sleep.wait_for_secrets_manager] - instance_guid = local.existing_en_guid - name = "Secrets Manager Topic" - description = "Topic for Secrets Manager events routing" - sources { - id = local.secrets_manager_crn - rules { - enabled = true - event_type_filter = "$.*" - } - } -} - -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 - instance_guid = local.existing_en_guid - name = "Email for Secrets Manager Subscription" - description = "Subscription for Secret Manager Events" - destination_id = [for s in toset(data.ibm_en_destinations.en_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] - topic_id = ibm_en_topic.en_topic[count.index].topic_id - attributes { - add_notification_payload = true - reply_to_mail = var.event_notifications_reply_to_email - reply_to_name = "Secret Manager Event Notifications Bot" - from_name = var.event_notifications_from_email - invited = var.event_notifications_email_list - } -} diff --git a/solutions/Security-enforced/moved.tf b/solutions/Security-enforced/moved.tf index 4064d8b9..e69de29b 100644 --- a/solutions/Security-enforced/moved.tf +++ b/solutions/Security-enforced/moved.tf @@ -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/solutions/Security-enforced/outputs.tf b/solutions/Security-enforced/outputs.tf index 9c4d0c8f..e69de29b 100644 --- a/solutions/Security-enforced/outputs.tf +++ b/solutions/Security-enforced/outputs.tf @@ -1,34 +0,0 @@ -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 -} - -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 -} - -output "secrets_manager_guid" { - description = "GUID of Secrets Manager instance" - value = local.secrets_manager_guid -} - -output "secrets_manager_id" { - description = "ID of Secrets Manager instance. Same value as secrets_manager_guid" - value = var.existing_secrets_manager_crn == null ? module.secrets_manager.secrets_manager_id : local.secrets_manager_guid -} - -output "secrets_manager_name" { - value = var.existing_secrets_manager_crn == null ? module.secrets_manager.secrets_manager_name : data.ibm_resource_instance.existing_sm[0].resource_name - description = "Name of the Secrets Manager instance" -} - -output "secrets_manager_crn" { - value = local.secrets_manager_crn - description = "CRN of the Secrets Manager instance" -} - -output "secrets_manager_region" { - value = local.secrets_manager_region - description = "Region of the Secrets Manager instance" -} diff --git a/solutions/Security-enforced/provider.tf b/solutions/Security-enforced/provider.tf index 65c38f7d..e69de29b 100644 --- a/solutions/Security-enforced/provider.tf +++ b/solutions/Security-enforced/provider.tf @@ -1,11 +0,0 @@ -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region - visibility = var.provider_visibility -} -provider "ibm" { - alias = "kms" - ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key - region = local.kms_region - visibility = var.provider_visibility -} diff --git a/solutions/Security-enforced/variables.tf b/solutions/Security-enforced/variables.tf index e235fc84..e69de29b 100644 --- a/solutions/Security-enforced/variables.tf +++ b/solutions/Security-enforced/variables.tf @@ -1,280 +0,0 @@ -######################################################################################################################## -# Common variables -######################################################################################################################## - -variable "ibmcloud_api_key" { - type = string - description = "The API Key to use for IBM Cloud." - sensitive = true -} - -variable "provider_visibility" { - description = "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)." - type = string - default = "private" - - validation { - condition = contains(["public", "private", "public-and-private"], var.provider_visibility) - error_message = "Invalid visibility option. Allowed values are 'public', 'private', or 'public-and-private'." - } -} - -variable "existing_resource_group_name" { - type = string - description = "Name of the existing resource group." -} - -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." - default = "dev" -} - -######################################################################################################################## -# 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." - 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 "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" { - 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." - 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 "public_cert_engine_lets_encrypt_config_ca_name" { - type = string - description = "The name of the certificate authority for Secrets Manager." - default = "cert-auth" -} - -variable "acme_letsencrypt_private_key" { - type = string - description = "The private key generated by the ACME account creation tool." - sensitive = true - default = null -} - -######################################################################################################################## -# Private cert engine config -######################################################################################################################## - -variable "private_cert_engine_enabled" { - 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." - 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" { - type = string - description = "The name of the certificate template." - default = "default-cert-template" -} - -######################################################################################################################## -# IAM engine config -######################################################################################################################## - -variable "iam_engine_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." - 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" -} - -######################################################################################################################## -# Key Protect -######################################################################################################################## - -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 -} - -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`." -} - -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." - default = "private" - validation { - condition = can(regex("public|private", var.kms_endpoint_type)) - error_message = "The kms_endpoint_type value must be 'public' or 'private'." - } -} - -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 "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." - 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 "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/standard/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 index 2d891d98..e69de29b 100644 --- a/solutions/Security-enforced/version.tf +++ b/solutions/Security-enforced/version.tf @@ -1,14 +0,0 @@ -terraform { - required_version = ">= 1.3.0" - # Lock DA into an exact provider version - renovate automation will keep it updated - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = "1.76.0" - } - time = { - source = "hashicorp/time" - version = "0.12.1" - } - } -} diff --git a/solutions/Fully configurable/DA-cbr_rules.md b/solutions/fully-configurable/DA-cbr_rules.md similarity index 100% rename from solutions/Fully configurable/DA-cbr_rules.md rename to solutions/fully-configurable/DA-cbr_rules.md diff --git a/solutions/Fully configurable/README.md b/solutions/fully-configurable/README.md similarity index 100% rename from solutions/Fully configurable/README.md rename to solutions/fully-configurable/README.md diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template new file mode 100644 index 00000000..cd067095 --- /dev/null +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -0,0 +1,7 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "existing_resource_group_name": "geretain-test-secrets-manager", + "service_plan": "trial", + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "region": "ca-tor" +} diff --git a/solutions/Fully configurable/main.tf b/solutions/fully-configurable/main.tf similarity index 67% rename from solutions/Fully configurable/main.tf rename to solutions/fully-configurable/main.tf index fc554167..547e55d9 100644 --- a/solutions/Fully configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -2,12 +2,10 @@ # Resource Group ######################################################################################################################## locals { - # tflint-ignore: terraform_unused_declarations - validate_event_notifications = (var.existing_event_notification_instance_crn == null && var.enable_event_notification) ? tobool("To enable event notifications, an existing event notifications CRN must be set.") : true + prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null } module "resource_group" { - count = var.existing_secrets_manager_crn == null ? 1 : 0 source = "terraform-ibm-modules/resource-group/ibm" version = "1.1.6" existing_resource_group_name = var.existing_resource_group_name @@ -18,13 +16,13 @@ module "resource_group" { ####################################################################################################################### 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 = var.prefix != null ? "${var.prefix}-${var.kms_key_ring_name}" : var.kms_key_ring_name - kms_key_name = var.prefix != null ? "${var.prefix}-${var.kms_key_name}" : var.kms_key_name + 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) 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 existing_kms_guid = length(local.parsed_existing_kms_instance_crn) > 0 ? local.parsed_existing_kms_instance_crn[7] : null - create_cross_account_auth_policy = !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_kms_iam_authorization_policy && var.ibmcloud_kms_api_key != null kms_service_name = local.kms_key_crn != null ? ( can(regex(".*kms.*", local.kms_key_crn)) ? "kms" : can(regex(".*hs-crypto.*", local.kms_key_crn)) ? "hs-crypto" : null @@ -44,7 +42,7 @@ resource "ibm_iam_authorization_policy" "kms_policy" { target_service_name = local.kms_service_name target_resource_instance_id = local.existing_kms_guid 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 from the ${local.kms_service_name} instance GUID ${local.existing_kms_guid}" + description = "Allow all Secrets Manager instances in the resource group ${module.resource_group.resource_group_id} in the account ${data.ibm_iam_account_settings.iam_account_settings[0].account_id} to read from the ${local.kms_service_name} instance GUID ${local.existing_kms_guid}" } # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 @@ -59,9 +57,9 @@ 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.existing_secrets_manager_kms_key_crn != null) ? 0 : (var.key_management_service_encryption_enabled == false ? 0 : 1) # no need to create any KMS resources if passing an existing key, or bucket source = "terraform-ibm-modules/kms-all-inclusive/ibm" - version = "4.19.1" + version = "4.20.0" create_key_protect_instance = false region = local.kms_region existing_kms_instance_crn = var.existing_kms_instance_crn @@ -93,53 +91,34 @@ 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 - sm_endpoint_type = var.existing_secrets_manager_crn != null ? var.existing_secrets_endpoint_type : var.allowed_network == "private-only" ? "private" : "public" } module "secrets_manager" { depends_on = [time_sleep.wait_for_authorization_policy] source = "../.." 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 + resource_group_id = module.resource_group.resource_group_id region = var.region - secrets_manager_name = var.prefix != null ? "${var.prefix}-${var.secrets_manager_instance_name}" : var.secrets_manager_instance_name - sm_service_plan = var.service_plan - allowed_network = var.allowed_network - sm_tags = var.secret_manager_tags + secrets_manager_name = try("${local.prefix}-${var.secrets_manager_instance_name}", var.secrets_manager_instance_name) + sm_service_plan = var.service_plan + sm_tags = var.secrets_manager_resource_tags # kms dependency - kms_encryption_enabled = var.kms_encryption_enabled + kms_encryption_enabled = var.key_management_service_encryption_enabled existing_kms_instance_guid = local.existing_kms_guid kms_key_crn = local.kms_key_crn skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy || local.create_cross_account_auth_policy # event notifications dependency - enable_event_notification = var.enable_event_notification - existing_en_instance_crn = var.existing_event_notification_instance_crn - skip_en_iam_authorization_policy = var.skip_event_notification_iam_authorization_policy - endpoint_type = local.sm_endpoint_type + enable_event_notification = var.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.6" - region = local.secrets_manager_region - iam_engine_name = var.prefix != null ? "${var.prefix}-${var.iam_engine_name}" : var.iam_engine_name - secrets_manager_guid = local.secrets_manager_guid - endpoint_type = local.sm_endpoint_type -} - -locals { - # tflint-ignore: terraform_unused_declarations - validate_public_secret_engine = var.public_engine_enabled && var.public_engine_name == null ? tobool("When setting var.public_engine_enabled to true, a value must be passed for var.public_engine_name") : true - # tflint-ignore: terraform_unused_declarations - validate_private_secret_engine = var.private_engine_enabled && var.private_engine_name == null ? tobool("When setting var.private_engine_enabled to true, a value must be passed for var.private_engine_name") : true + endpoint_type = var.service_endpoints + allowed_network = var.allowed_network } # Configure an IBM Secrets Manager public certificate engine for an existing IBM Secrets Manager instance. module "secrets_manager_public_cert_engine" { - count = var.public_engine_enabled ? 1 : 0 + count = var.public_cert_engine_enabled ? 1 : 0 source = "terraform-ibm-modules/secrets-manager-public-cert-engine/ibm" version = "1.0.2" providers = { @@ -148,28 +127,28 @@ module "secrets_manager_public_cert_engine" { } secrets_manager_guid = local.secrets_manager_guid region = local.secrets_manager_region - internet_services_crn = var.cis_id + internet_services_crn = var.public_cert_engine_internet_services_crn ibmcloud_cis_api_key = var.ibmcloud_api_key - dns_config_name = var.dns_provider_name - ca_config_name = var.ca_name + 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 = local.sm_endpoint_type + 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_engine_enabled ? 1 : 0 + count = var.private_cert_engine_enabled ? 1 : 0 source = "terraform-ibm-modules/secrets-manager-private-cert-engine/ibm" - version = "1.3.4" + version = "1.3.5" secrets_manager_guid = local.secrets_manager_guid region = var.region - root_ca_name = var.root_ca_name - root_ca_common_name = var.root_ca_common_name - root_ca_max_ttl = var.root_ca_max_ttl - intermediate_ca_name = var.intermediate_ca_name - certificate_template_name = var.certificate_template_name - endpoint_type = local.sm_endpoint_type + 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" } data "ibm_resource_instance" "existing_sm" { @@ -182,20 +161,20 @@ data "ibm_resource_instance" "existing_sm" { ####################################################################################################################### locals { - parsed_existing_en_instance_crn = var.existing_event_notification_instance_crn != null ? split(":", var.existing_event_notification_instance_crn) : [] + parsed_existing_en_instance_crn = var.existing_event_notifications_instance_crn != null ? split(":", var.existing_event_notifications_instance_crn) : [] existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null } 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_notification ? 1 : 0 + count = var.existing_secrets_manager_crn == null && var.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_notification ? 1 : 0 + count = var.existing_secrets_manager_crn == null && var.enable_event_notifications ? 1 : 0 depends_on = [module.secrets_manager] create_duration = "30s" @@ -203,7 +182,7 @@ 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_notification ? 1 : 0 + count = var.existing_secrets_manager_crn == null && var.enable_event_notifications ? 1 : 0 depends_on = [time_sleep.wait_for_secrets_manager] instance_guid = local.existing_en_guid name = "Secrets Manager Topic" @@ -219,7 +198,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_notification && length(var.sm_en_email_list) > 0 ? 1 : 0 + count = var.existing_secrets_manager_crn == null && var.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" @@ -227,9 +206,9 @@ resource "ibm_en_subscription_email" "email_subscription" { topic_id = ibm_en_topic.en_topic[count.index].topic_id attributes { add_notification_payload = true - reply_to_mail = var.sm_en_reply_to_email + reply_to_mail = var.event_notifications_reply_to_email reply_to_name = "Secret Manager Event Notifications Bot" - from_name = var.sm_en_from_email - invited = var.sm_en_email_list + from_name = var.event_notifications_from_email + invited = var.event_notifications_email_list } -} +} \ No newline at end of file diff --git a/solutions/Fully configurable/outputs.tf b/solutions/fully-configurable/outputs.tf similarity index 75% rename from solutions/Fully configurable/outputs.tf rename to solutions/fully-configurable/outputs.tf index 9c4d0c8f..5a26d726 100644 --- a/solutions/Fully configurable/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 = var.existing_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" { diff --git a/solutions/Fully configurable/provider.tf b/solutions/fully-configurable/provider.tf similarity index 100% rename from solutions/Fully configurable/provider.tf rename to solutions/fully-configurable/provider.tf diff --git a/solutions/Fully configurable/variables.tf b/solutions/fully-configurable/variables.tf similarity index 75% rename from solutions/Fully configurable/variables.tf rename to solutions/fully-configurable/variables.tf index 4bf70106..d8a2e111 100644 --- a/solutions/Fully configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -18,11 +18,18 @@ variable "provider_visibility" { error_message = "Invalid visibility option. Allowed values are 'public', 'private', or 'public-and-private'." } } + variable "existing_resource_group_name" { type = string description = "Name of the existing resource group." } +variable "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 +} + variable "region" { type = string description = "The region to provision resources to." @@ -31,8 +38,7 @@ variable "region" { variable "prefix" { type = string - description = "The prefix to apply to all resources created by this solution." - default = null + 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." } ######################################################################################################################## @@ -42,7 +48,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." - default = "base-security-services-sm" + default = "secrets-manager" } variable "existing_secrets_manager_crn" { @@ -51,77 +57,65 @@ variable "existing_secrets_manager_crn" { default = null } -variable "existing_secrets_endpoint_type" { +variable "service_plan" { type = string - description = "The endpoint type to use if existing_secrets_manager_crn is specified. Possible values: public, private." - default = "private" + description = "The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`." + default = "standard" validation { - condition = contains(["public", "private"], var.existing_secrets_endpoint_type) - error_message = "Only \"public\" and \"private\" are allowed values for 'existing_secrets_endpoint_type'." + 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 "service_plan" { +variable "secrets_manager_resource_tags" { + type = list(any) + description = "The list of resource tags you want to associate with your Secrets Manager instance." + default = [] +} + +variable "service_endpoints" { type = string - description = "The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. Applies only if `provision_sm_instance` is set to `true`." - default = "standard" + 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(["standard", "trial"], var.service_plan) - error_message = "Only \"standard\" and \"trial\" are allowed values for sm_service_plan." + condition = contains(["public", "private"], var.service_endpoints) + error_message = "The specified service endpoint is not a valid selection!" } } variable "allowed_network" { type = string - description = "The types of service endpoints to set on the Secrets Manager instance. Possible values: `private-only`, `public-and-private`." - default = "private-only" + description = "The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`." + default = "public-and-private" validation { condition = contains(["private-only", "public-and-private"], var.allowed_network) - error_message = "The specified allowed_network is not a valid selection." + error_message = "The specified allowed_network is not a valid selection!" } } -variable "kms_encryption_enabled" { - type = bool - description = "Set this to true to control the encryption keys used to encrypt the data that you store in Secrets Manager. If set to false, the data that you store is encrypted at rest by using envelope encryption. For more details, see https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-mng-data&interface=ui#about-encryption." - default = false -} - -variable "secret_manager_tags" { - type = list(any) - description = "The list of resource tags you want to associate with your Secrets Manager instance." - default = [] -} - -variable "public_engine_enabled" { - 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." - default = false -} - ######################################################################################################################## # Public cert engine config ######################################################################################################################## -variable "public_engine_name" { - type = string - description = "The name of the IAM engine used to configure a Secrets Manager public certificate engine for an existing instance." - default = "public-engine-sm" +variable "public_cert_engine_enabled" { + 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." + default = false } -variable "cis_id" { +variable "public_cert_engine_internet_services_crn" { type = string description = "Cloud Internet Service ID." default = null } -variable "dns_provider_name" { +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 "ca_name" { +variable "public_cert_engine_lets_encrypt_config_ca_name" { type = string description = "The name of the certificate authority for Secrets Manager." default = "cert-auth" @@ -138,64 +132,42 @@ variable "acme_letsencrypt_private_key" { # Private cert engine config ######################################################################################################################## -variable "private_engine_enabled" { +variable "private_cert_engine_enabled" { 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." default = false } -variable "private_engine_name" { - type = string - description = "The name of the IAM Engine used to configure a Secrets Manager private certificate engine for an existing instance." - default = "private-engine-sm" -} - -variable "root_ca_name" { +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 "root_ca_common_name" { +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 "root_ca_max_ttl" { +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 "intermediate_ca_name" { +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 "certificate_template_name" { +variable "private_cert_engine_config_template_name" { type = string description = "The name of the certificate template." default = "default-cert-template" } -######################################################################################################################## -# IAM engine config -######################################################################################################################## - -variable "iam_engine_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." - 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 = "base-sm-iam-engine" -} - ######################################################################################################################## # Key Protect ######################################################################################################################## @@ -216,6 +188,12 @@ variable "existing_secrets_manager_kms_key_crn" { # KMS properties required when creating an encryption key, rather than passing an existing key CRN. ######################################################################################################################## +variable "key_management_service_encryption_enabled" { + type = bool + description = "Set to true to enable Secrets Manager Secrets Encryption." + default = true +} + variable "existing_kms_instance_crn" { type = string default = null @@ -234,13 +212,13 @@ variable "kms_endpoint_type" { variable "kms_key_ring_name" { type = string - default = "sm-cos-key-ring" + 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 = "sm-cos-key" + 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." } @@ -255,41 +233,47 @@ variable "ibmcloud_kms_api_key" { # Event Notifications ######################################################################################################################## -variable "enable_event_notification" { +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_en_instance_crn` and `existing_sm_instance_crn` must be null." + 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_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." default = null + + validation { + condition = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? false : true + error_message = "To enable event notifications, an existing event notifications CRN must be set." + } } -variable "skip_event_notification_iam_authorization_policy" { +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 "sm_en_email_list" { +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 "sm_en_from_email" { +variable "event_notifications_from_email" { type = string - description = "The email address in the used in the 'from' of any Secret Manager event coming from Event Notifications" + description = "The email address used to send any Secrets Manager event coming via Event Notifications" default = "compliancealert@ibm.com" } -variable "sm_en_reply_to_email" { +variable "event_notifications_reply_to_email" { type = string - description = "The email address used in the 'reply_to' of any Secret Manager event coming from Event Notifications" + 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) ############################################################## @@ -310,7 +294,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 -} +} \ No newline at end of file diff --git a/solutions/Fully configurable/version.tf b/solutions/fully-configurable/version.tf similarity index 81% rename from solutions/Fully configurable/version.tf rename to solutions/fully-configurable/version.tf index e51ef9af..337e7025 100644 --- a/solutions/Fully configurable/version.tf +++ b/solutions/fully-configurable/version.tf @@ -1,10 +1,10 @@ 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 = { source = "IBM-Cloud/ibm" - version = "1.74.0" + version = "1.76.0" } time = { source = "hashicorp/time" diff --git a/tests/existing-resources/version.tf b/tests/existing-resources/version.tf index 6323b3e9..7db4be46 100644 --- a/tests/existing-resources/version.tf +++ b/tests/existing-resources/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.9.0" required_providers { ibm = { source = "ibm-cloud/ibm" diff --git a/tests/pr_test.go b/tests/pr_test.go index c913044b..ab23ddd0 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -24,7 +24,7 @@ import ( const completeExampleTerraformDir = "examples/complete" const fscloudExampleTerraformDir = "examples/fscloud" -const solutionsTerraformDir = "solutions/Security-enforced" +const fullyConfigurableTerraformDir = "solutions/fully-configurable" const resourceGroup = "geretain-test-scc-module" @@ -82,7 +82,7 @@ func TestRunUpgradeExample(t *testing.T) { } } -func TestRunDASolutionSchematics(t *testing.T) { +func TestRunFullyConfigurableSchematics(t *testing.T) { t.Parallel() acme_letsencrypt_private_key := GetSecretsManagerKey( // pragma: allowlist secret @@ -96,14 +96,14 @@ func TestRunDASolutionSchematics(t *testing.T) { 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, @@ -113,10 +113,9 @@ 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: "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"}, @@ -151,7 +150,7 @@ func GetSecretsManagerKey(sm_id string, sm_region string, sm_key_id string) *str return secret.(*secretsmanagerv2.ArbitrarySecret).Payload } -// A test to pass existing resources to the SM DA +//A test to pass existing resources to the SM DA func TestRunExistingResourcesInstances(t *testing.T) { t.Parallel() diff --git a/version.tf b/version.tf index cb85c3b3..916ac3bd 100644 --- a/version.tf +++ b/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= v1.0.0" + required_version = ">= v1.9.0" required_providers { # Use "greater than or equal to" range in modules ibm = { From 609490fc758a64ea00db0176ff6f86d1cedf5f22 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 13 Mar 2025 11:38:37 +0530 Subject: [PATCH 03/19] update variables --- README.md | 2 +- examples/complete/README.md | 2 +- ibm_catalog.json | 69 ++++++-------- modules/fscloud/README.md | 2 +- modules/secrets/README.md | 2 +- solutions/Security-enforced/DA-cbr_rules.md | 0 solutions/Security-enforced/README.md | 0 .../catalogValidationValues.json.template | 7 -- solutions/Security-enforced/main.tf | 0 solutions/Security-enforced/moved.tf | 0 solutions/Security-enforced/outputs.tf | 0 solutions/Security-enforced/provider.tf | 0 solutions/Security-enforced/variables.tf | 0 solutions/Security-enforced/version.tf | 0 solutions/fully-configurable/main.tf | 45 +-------- solutions/fully-configurable/variables.tf | 85 +---------------- tests/pr_test.go | 93 ------------------- 17 files changed, 38 insertions(+), 269 deletions(-) delete mode 100644 solutions/Security-enforced/DA-cbr_rules.md delete mode 100644 solutions/Security-enforced/README.md delete mode 100644 solutions/Security-enforced/catalogValidationValues.json.template delete mode 100644 solutions/Security-enforced/main.tf delete mode 100644 solutions/Security-enforced/moved.tf delete mode 100644 solutions/Security-enforced/outputs.tf delete mode 100644 solutions/Security-enforced/provider.tf delete mode 100644 solutions/Security-enforced/variables.tf delete mode 100644 solutions/Security-enforced/version.tf diff --git a/README.md b/README.md index 41a97fbe..ce14a61d 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ You need the following permissions to run this module. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= v1.0.0 | +| [terraform](#requirement\_terraform) | >= v1.9.0 | | [ibm](#requirement\_ibm) | >= 1.76.0, <2.0.0 | | [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | diff --git a/examples/complete/README.md b/examples/complete/README.md index e2e7bb2e..7b582520 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -7,7 +7,7 @@ This examples handles the provisioning of a new Secrets Manager instance. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= v1.0.0 | +| [terraform](#requirement\_terraform) | >= v1.9.0 | | [ibm](#requirement\_ibm) | >=1.76.0 | | [time](#requirement\_time) | 0.12.1 | diff --git a/ibm_catalog.json b/ibm_catalog.json index 3e975068..8c51e745 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -45,10 +45,10 @@ "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues). Please note this product is not supported via the IBM Cloud Support Center.", "flavors": [ { - "label": "Security-enforced", - "name": "security-enforced", + "label": "Fully-configurable", + "name": "fully-configurable", "install_type": "fullstack", - "working_directory": "solutions/security-enforced", + "working_directory": "solutions/fully-configurable", "compliance": { "authority": "scc-v3", "profiles": [ @@ -113,14 +113,6 @@ "required": true, "description": "Prefix to add to all resources created by this solution. To not use any prefix value, you can enter the string `__NULL__`." }, - { - "key": "use_existing_resource_group", - "required": true - }, - { - "key": "resource_group_name", - "required": true - }, { "key": "existing_kms_instance_crn", "required": true @@ -172,43 +164,36 @@ ] }, { - "key": "iam_engine_enabled" - }, - { - "key": "iam_engine_name" - }, - { - "key": "public_cert_engine_enabled" - }, - { - "key": "public_cert_engine_internet_services_crn" - }, - { - "key": "public_cert_engine_dns_provider_config_name" - }, - { - "key": "public_cert_engine_lets_encrypt_config_ca_name" - }, - { - "key": "acme_letsencrypt_private_key" - }, - { - "key": "private_cert_engine_enabled" - }, - { - "key": "private_cert_engine_config_root_ca_name" - }, - { - "key": "private_cert_engine_config_root_ca_common_name" + "key": "allowed_network", + "options": [ + { + "displayname": "private-only", + "value": "private-only" + }, + { + "displayname": "public-and-private", + "value": "public-and-private" + } + ] }, { - "key": "private_cert_engine_config_root_ca_max_ttl" + "key": "existing_resource_group_name" }, { - "key": "private_cert_engine_config_intermediate_ca_name" + "key": "key_management_service_encryption_enabled" }, { - "key": "private_cert_engine_config_template_name" + "key": "service_endpoints", + "options": [ + { + "displayname": "public", + "value": "public" + }, + { + "displayname": "private", + "value": "private" + } + ] }, { "key": "existing_secrets_manager_kms_key_crn" diff --git a/modules/fscloud/README.md b/modules/fscloud/README.md index 092e038c..1824cc2d 100644 --- a/modules/fscloud/README.md +++ b/modules/fscloud/README.md @@ -30,7 +30,7 @@ module "secrets_manager" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [terraform](#requirement\_terraform) | >= 1.9.0 | | [ibm](#requirement\_ibm) | >=1.62.0, <2.0.0 | ### Modules diff --git a/modules/secrets/README.md b/modules/secrets/README.md index 5b478975..f2ffc2c9 100644 --- a/modules/secrets/README.md +++ b/modules/secrets/README.md @@ -43,7 +43,7 @@ module "secrets_manager" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [terraform](#requirement\_terraform) | >= 1.9.0 | | [ibm](#requirement\_ibm) | >=1.62.0, <2.0.0 | ### Modules diff --git a/solutions/Security-enforced/DA-cbr_rules.md b/solutions/Security-enforced/DA-cbr_rules.md deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/README.md b/solutions/Security-enforced/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/catalogValidationValues.json.template b/solutions/Security-enforced/catalogValidationValues.json.template deleted file mode 100644 index cd067095..00000000 --- a/solutions/Security-enforced/catalogValidationValues.json.template +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ibmcloud_api_key": $VALIDATION_APIKEY, - "existing_resource_group_name": "geretain-test-secrets-manager", - "service_plan": "trial", - "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, - "region": "ca-tor" -} diff --git a/solutions/Security-enforced/main.tf b/solutions/Security-enforced/main.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/moved.tf b/solutions/Security-enforced/moved.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/outputs.tf b/solutions/Security-enforced/outputs.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/provider.tf b/solutions/Security-enforced/provider.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/variables.tf b/solutions/Security-enforced/variables.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/Security-enforced/version.tf b/solutions/Security-enforced/version.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index 547e55d9..a7269842 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -2,7 +2,7 @@ # Resource Group ######################################################################################################################## locals { - prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null + prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null } module "resource_group" { @@ -100,7 +100,7 @@ module "secrets_manager" { resource_group_id = module.resource_group.resource_group_id region = var.region secrets_manager_name = try("${local.prefix}-${var.secrets_manager_instance_name}", var.secrets_manager_instance_name) - sm_service_plan = var.service_plan + sm_service_plan = var.service_plan sm_tags = var.secrets_manager_resource_tags # kms dependency kms_encryption_enabled = var.key_management_service_encryption_enabled @@ -112,43 +112,8 @@ module "secrets_manager" { 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 - endpoint_type = var.service_endpoints - allowed_network = var.allowed_network -} - -# 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.2" - 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" + endpoint_type = var.service_endpoints + allowed_network = var.allowed_network } data "ibm_resource_instance" "existing_sm" { @@ -211,4 +176,4 @@ resource "ibm_en_subscription_email" "email_subscription" { from_name = var.event_notifications_from_email invited = var.event_notifications_email_list } -} \ No newline at end of file +} diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index d8a2e111..3a7a277f 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -24,12 +24,6 @@ variable "existing_resource_group_name" { description = "Name of the existing resource group." } -variable "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 -} - variable "region" { type = string description = "The region to provision resources to." @@ -93,81 +87,6 @@ variable "allowed_network" { } } -######################################################################################################################## -# Public cert engine config -######################################################################################################################## - -variable "public_cert_engine_enabled" { - 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." - 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 "public_cert_engine_lets_encrypt_config_ca_name" { - type = string - description = "The name of the certificate authority for Secrets Manager." - default = "cert-auth" -} - -variable "acme_letsencrypt_private_key" { - type = string - description = "The private key generated by the ACME account creation tool." - sensitive = true - default = null -} - -######################################################################################################################## -# Private cert engine config -######################################################################################################################## - -variable "private_cert_engine_enabled" { - 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." - 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" { - type = string - description = "The name of the certificate template." - default = "default-cert-template" -} - ######################################################################################################################## # Key Protect ######################################################################################################################## @@ -245,7 +164,7 @@ variable "existing_event_notifications_instance_crn" { default = null validation { - condition = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? false : true + condition = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? false : true error_message = "To enable event notifications, an existing event notifications CRN must be set." } } @@ -297,4 +216,4 @@ 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/fully-configurable/DA-cbr_rules.md)" default = [] # Validation happens in the rule module -} \ No newline at end of file +} diff --git a/tests/pr_test.go b/tests/pr_test.go index ab23ddd0..78b31a13 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -6,17 +6,11 @@ import ( "log" "math/rand" "os" - "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" - "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/common" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testschematic" @@ -149,90 +143,3 @@ func GetSecretsManagerKey(sm_id string, sm_region string, sm_key_id string) *str } return secret.(*secretsmanagerv2.ArbitrarySecret).Payload } - -//A test to pass existing resources to the SM DA -func TestRunExistingResourcesInstances(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())) - realTerraformDir := ".." - tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) - tags := common.GetTagsFromTravis() - - // Verify ibmcloud_api_key variable is set - checkVariable := "TF_VAR_ibmcloud_api_key" - val, present := os.LookupEnv(checkVariable) - require.True(t, present, checkVariable+" environment variable not set") - require.NotEqual(t, "", val, checkVariable+" environment variable is empty") - logger.Log(t, "Tempdir: ", tempTerraformDir) - existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ - TerraformDir: tempTerraformDir + "/tests/existing-resources", - Vars: map[string]interface{}{ - "prefix": prefix, - "region": region, - "resource_tags": tags, - }, - // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. - // This is the same as setting the -upgrade=true flag with terraform. - Upgrade: true, - }) - - terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) - _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) - if existErr != nil { - assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") - } else { - - // ------------------------------------------------------------------------------------ - // Test passing existing RG, EN, and KMS key - // ------------------------------------------------------------------------------------ - options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ - Testing: t, - TarIncludePatterns: []string{ - "*.tf", - fmt.Sprintf("%s/*.tf", solutionsTerraformDir), - fmt.Sprintf("%s/*.tf", "modules/secrets"), - fmt.Sprintf("%s/*.tf", "modules/fscloud"), - }, - TemplateFolder: solutionsTerraformDir, - ResourceGroup: resourceGroup, - 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: "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_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: "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() - assert.NoError(t, err, "Schematic Test had unexpected error") - } - - // Check if "DO_NOT_DESTROY_ON_FAILURE" is set - envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") - // Destroy the temporary existing resources if required - if t.Failed() && strings.ToLower(envVal) == "true" { - fmt.Println("Terratest failed. Debug the test and delete resources manually.") - } else { - logger.Log(t, "START: Destroy (existing resources)") - terraform.Destroy(t, existingTerraformOptions) - terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) - logger.Log(t, "END: Destroy (existing resources)") - } -} From 5a56420a0152d0d6a12a524d1c399a69928899fc Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 13 Mar 2025 12:39:28 +0530 Subject: [PATCH 04/19] fix: cra scan --- cra-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cra-config.yaml b/cra-config.yaml index 7dcfd090..422455a9 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,10 +1,10 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "solutions/security-enforced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - CRA_TARGET: "solutions/fully-configurable" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" - TF_VAR_resource_group_name: "test" + TF_VAR_existing_resource_group_name: "test" TF_VAR_provider_visibility: "public" From 180ca1760a9e216d77f48ae87eb893a8a04066ba Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 13 Mar 2025 12:47:00 +0530 Subject: [PATCH 05/19] fix: cra scan --- cra-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/cra-config.yaml b/cra-config.yaml index 422455a9..a8928c36 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -8,3 +8,4 @@ CRA_TARGETS: TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" TF_VAR_existing_resource_group_name: "test" TF_VAR_provider_visibility: "public" + TF_VAR_prefix: "test" From 6de6278568d5455b8c780897a7fe9e921dc317f5 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 13 Mar 2025 12:53:57 +0530 Subject: [PATCH 06/19] fix: cra scan --- cra-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cra-config.yaml b/cra-config.yaml index a8928c36..b6eef45c 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -6,6 +6,6 @@ CRA_TARGETS: PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" - TF_VAR_existing_resource_group_name: "test" + TF_VAR_existing_resource_group_name: "geretain-test-secrets-manager" TF_VAR_provider_visibility: "public" TF_VAR_prefix: "test" From 0968514efceeaaedeaf3c893c0ea320c6e3c7701 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Mon, 17 Mar 2025 17:59:35 +0530 Subject: [PATCH 07/19] add: security-enforced variation --- common-dev-assets | 2 +- ibm_catalog.json | 177 +++++++++++++++++ solutions/fully-configurable/README.md | 5 +- solutions/security-enforced/README.md | 10 + .../catalogValidationValues.json.template | 7 + solutions/security-enforced/main.tf | 29 +++ solutions/security-enforced/outputs.tf | 19 ++ solutions/security-enforced/provider.tf | 1 + solutions/security-enforced/variables.tf | 178 ++++++++++++++++++ solutions/security-enforced/version.tf | 6 + tests/pr_test.go | 97 +++++++++- 11 files changed, 526 insertions(+), 5 deletions(-) create mode 100644 solutions/security-enforced/README.md create mode 100644 solutions/security-enforced/catalogValidationValues.json.template create mode 100644 solutions/security-enforced/main.tf create mode 100644 solutions/security-enforced/outputs.tf create mode 100644 solutions/security-enforced/provider.tf create mode 100644 solutions/security-enforced/variables.tf create mode 100644 solutions/security-enforced/version.tf diff --git a/common-dev-assets b/common-dev-assets index 8c7a97cb..2f8bedb6 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 8c7a97cb00b128503d2c81380be904b6d196cc02 +Subproject commit 2f8bedb6f5e623405e41553b0491c0306a027023 diff --git a/ibm_catalog.json b/ibm_catalog.json index 8c51e745..cb3b959b 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -276,6 +276,183 @@ } ] } + }, + { + "label": "Security-enforced", + "name": "security-enforced", + "install_type": "fullstack", + "working_directory": "solutions/security-enforced", + "compliance": { + "authority": "scc-v3", + "profiles": [ + { + "profile_name": "IBM Cloud Framework for Financial Services", + "profile_version": "1.7.0" + } + ] + }, + "configuration": [ + { + "key": "ibmcloud_api_key" + }, + { + "key": "region", + "required": true, + "options": [ + { + "displayname": "Osaka (jp-osa)", + "value": "jp-osa" + }, + { + "displayname": "Sydney (au-syd)", + "value": "au-syd" + }, + { + "displayname": "Tokyo (jp-tok)", + "value": "jp-tok" + }, + { + "displayname": "Frankfurt (eu-de)", + "value": "eu-de" + }, + { + "displayname": "London (eu-gb)", + "value": "eu-gb" + }, + { + "displayname": "Madrid (eu-es)", + "value": "eu-es" + }, + { + "displayname": "Dallas (us-south)", + "value": "us-south" + }, + { + "displayname": "Toronto (ca-tor)", + "value": "ca-tor" + }, + { + "displayname": "Washington DC (us-east)", + "value": "us-east" + }, + { + "displayname": "Sao Paulo (br-sao)", + "value": "br-sao" + } + ] + }, + { + "key": "prefix", + "required": true, + "description": "Prefix to add to all resources created by this solution. To not use any prefix value, you can enter the string `__NULL__`." + }, + { + "key": "existing_kms_instance_crn", + "required": true + }, + { + "key": "secrets_manager_instance_name" + }, + { + "key": "existing_secrets_manager_crn" + }, + { + "key": "secrets_manager_resource_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "service_plan", + "options": [ + { + "displayname": "Standard", + "value": "standard" + }, + { + "displayname": "Trial", + "value": "trial" + } + ] + }, + { + "key": "existing_resource_group_name" + }, + { + "key": "key_management_service_encryption_enabled" + }, + { + "key": "existing_secrets_manager_kms_key_crn" + }, + { + "key": "skip_kms_iam_authorization_policy" + }, + { + "key": "ibmcloud_kms_api_key" + }, + { + "key": "kms_key_ring_name" + }, + { + "key": "kms_key_name" + }, + { + "key": "enable_event_notifications" + }, + { + "key": "event_notifications_email_list" + }, + { + "key": "event_notifications_from_email" + }, + { + "key": "event_notifications_reply_to_email" + }, + { + "key": "existing_event_notifications_instance_crn" + }, + { + "key": "skip_event_notifications_iam_authorization_policy" + }, + { + "key":"cbr_rules" + } + ], + "architecture": { + "descriptions": "This architecture supports creating and configuring a Secrets Manager instance.", + "features": [ + { + "title": "Creates a Secrets Manager instance.", + "description": "Creates and configures an IBM Secrets Manager instance." + }, + { + "title": "Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance.", + "description": "Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance." + }, + { + "title": "Sets up authorization policy.", + "description": "Sets up IBM IAM authorization policy between IBM Secrets Manager instance and IBM Key Management Service (KMS) instance. It also supports Event Notification authorization policy." + }, + { + "title": "Configures lifecycle notifications for the Secrets Manager instance.", + "description": "Configures lifecycle notifications for the IBM Secrets Manager instance by connecting an IBM Event Notifications service. The DA supports optionally creating a KMS key ring and key, or using an already existing one to encrypt data." + } + ], + "diagrams": [ + { + "diagram": { + "caption": "Secrets Manager", + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-secrets-manager/main/reference-architecture/secrets_manager.svg", + "type": "image/svg+xml" + }, + "description": "This architecture supports creating and configuring IBM Secrets Manager instance." + } + ] + } } ] } diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md index a34dc2f7..20605e6c 100644 --- a/solutions/fully-configurable/README.md +++ b/solutions/fully-configurable/README.md @@ -1,9 +1,8 @@ -# Secrets Manager solution +# Secrets Manager fully-configurable solution This solution supports the following: -- Creating a new resource group, or taking in an existing one. +- Taking in an existing resource group. - 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. ![secret-manager-deployable-architecture](../../reference-architecture/secrets_manager.svg) diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md new file mode 100644 index 00000000..2386ab92 --- /dev/null +++ b/solutions/security-enforced/README.md @@ -0,0 +1,10 @@ +# 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. + +![secret-manager-deployable-architecture](../../reference-architecture/secrets_manager.svg) + +**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/security-enforced/catalogValidationValues.json.template b/solutions/security-enforced/catalogValidationValues.json.template new file mode 100644 index 00000000..cd067095 --- /dev/null +++ b/solutions/security-enforced/catalogValidationValues.json.template @@ -0,0 +1,7 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "existing_resource_group_name": "geretain-test-secrets-manager", + "service_plan": "trial", + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "region": "ca-tor" +} diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf new file mode 100644 index 00000000..782b5241 --- /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 + secrets_manager_resource_tags = var.secrets_manager_resource_tags + service_endpoints = "private" + allowed_network = "private-only" + skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy + existing_secrets_manager_kms_key_crn = var.existing_secrets_manager_kms_key_crn + key_management_service_encryption_enabled = var.key_management_service_encryption_enabled + 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 + enable_event_notifications = var.enable_event_notifications + 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 + cbr_rules = var.cbr_rules +} diff --git a/solutions/security-enforced/outputs.tf b/solutions/security-enforced/outputs.tf new file mode 100644 index 00000000..b29b7975 --- /dev/null +++ b/solutions/security-enforced/outputs.tf @@ -0,0 +1,19 @@ +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. Same value as secrets_manager_guid" + value = module.secrets_manager.secrets_manager_id +} 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..88c66553 --- /dev/null +++ b/solutions/security-enforced/variables.tf @@ -0,0 +1,178 @@ +######################################################################################################################## +# Common variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The API Key to use for IBM Cloud." + sensitive = true +} + +variable "existing_resource_group_name" { + type = string + description = "Name of the existing resource group." +} + +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." +} + +######################################################################################################################## +# 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." + 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 "secrets_manager_resource_tags" { + type = list(any) + description = "The list of resource tags you want to associate with your Secrets Manager instance." + default = [] +} + +######################################################################################################################## +# Key Protect +######################################################################################################################## + +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 +} + +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 "key_management_service_encryption_enabled" { + type = bool + description = "Set to true to enable Secrets Manager Secrets Encryption." + default = true +} + +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`." +} + +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 "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." + default = null + + validation { + condition = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? false : true + error_message = "To enable event notifications, an existing event notifications CRN must be set." + } +} + +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 "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/tests/pr_test.go b/tests/pr_test.go index 7ff49962..e8df1fc8 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -19,6 +19,7 @@ import ( const completeExampleTerraformDir = "examples/complete" const fscloudExampleTerraformDir = "examples/fscloud" const fullyConfigurableTerraformDir = "solutions/fully-configurable" +const securityEnforcedTerraformDir = "solutions/security-enforced" const resourceGroup = "geretain-test-scc-module" @@ -159,7 +160,6 @@ func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { TarIncludePatterns: []string{ "*.tf", fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir), - fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir), fmt.Sprintf("%s/*.tf", "modules/secrets"), fmt.Sprintf("%s/*.tf", "modules/fscloud"), }, @@ -191,3 +191,98 @@ func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { assert.Nil(t, err, "This should not have errored") } } + +func TestRunSecurityEnforcedSchematics(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), + ) + + // 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", fscloudExampleTerraformDir), + fmt.Sprintf("%s/*.tf", "modules/secrets"), + fmt.Sprintf("%s/*.tf", "modules/fscloud"), + }, + 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"}, + {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 TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(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), + ) + + // 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-se-ug", + 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"}, + {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() + if !options.UpgradeTestSkipped { + assert.Nil(t, err, "This should not have errored") + } +} From 5e87ae9458467dab96f4b38d5506340bb45ea6a3 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Tue, 18 Mar 2025 01:19:18 +0530 Subject: [PATCH 08/19] fix: tests --- tests/pr_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index e8df1fc8..77d401bc 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -193,7 +193,6 @@ func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { } func TestRunSecurityEnforcedSchematics(t *testing.T) { - t.Parallel() acme_letsencrypt_private_key := GetSecretsManagerKey( // pragma: allowlist secret permanentResources["acme_letsencrypt_private_key_sm_id"].(string), @@ -240,7 +239,6 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { } func TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(t *testing.T) { - t.Parallel() acme_letsencrypt_private_key := GetSecretsManagerKey( // pragma: allowlist secret permanentResources["acme_letsencrypt_private_key_sm_id"].(string), From a34b81593d1906eb969684aa40c03ae197857dde Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 20 Mar 2025 02:25:37 +0530 Subject: [PATCH 09/19] resolve comments --- README.md | 2 +- examples/basic/version.tf | 2 +- examples/complete/README.md | 2 +- examples/complete/version.tf | 2 +- examples/fscloud/version.tf | 2 +- ibm_catalog.json | 111 ++++++++++++++++----- reference-architecture/secrets_manager.svg | 2 +- solutions/fully-configurable/main.tf | 29 +++--- solutions/fully-configurable/outputs.tf | 2 +- solutions/fully-configurable/variables.tf | 56 ++++++++--- solutions/security-enforced/main.tf | 8 +- solutions/security-enforced/variables.tf | 28 ++++-- tests/pr_test.go | 10 +- version.tf | 2 +- 14 files changed, 179 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index ce14a61d..41a97fbe 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ You need the following permissions to run this module. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= v1.9.0 | +| [terraform](#requirement\_terraform) | >= v1.0.0 | | [ibm](#requirement\_ibm) | >= 1.76.0, <2.0.0 | | [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | diff --git a/examples/basic/version.tf b/examples/basic/version.tf index bf6a8999..2a34320c 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= v1.9.0" + required_version = ">= v1.0.0" # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main # module's version.tf (this example), and 1 example that will always use the latest provider version (complete example). diff --git a/examples/complete/README.md b/examples/complete/README.md index 7b582520..e2e7bb2e 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -7,7 +7,7 @@ This examples handles the provisioning of a new Secrets Manager instance. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= v1.9.0 | +| [terraform](#requirement\_terraform) | >= v1.0.0 | | [ibm](#requirement\_ibm) | >=1.76.0 | | [time](#requirement\_time) | 0.12.1 | diff --git a/examples/complete/version.tf b/examples/complete/version.tf index 4aac0b35..c34bf04d 100644 --- a/examples/complete/version.tf +++ b/examples/complete/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= v1.9.0" + required_version = ">= v1.0.0" required_providers { ibm = { source = "IBM-Cloud/ibm" diff --git a/examples/fscloud/version.tf b/examples/fscloud/version.tf index e6c04b07..86508b36 100644 --- a/examples/fscloud/version.tf +++ b/examples/fscloud/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.9.0" + required_version = ">= 1.0.0" required_providers { # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { diff --git a/ibm_catalog.json b/ibm_catalog.json index cb3b959b..a08c2ac1 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -45,7 +45,7 @@ "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues). Please note this product is not supported via the IBM Cloud Support Center.", "flavors": [ { - "label": "Fully-configurable", + "label": "Fully configurable", "name": "fully-configurable", "install_type": "fullstack", "working_directory": "solutions/fully-configurable", @@ -163,6 +163,9 @@ } ] }, + { + "key": "skip_iam_authorization_policy" + }, { "key": "allowed_network", "options": [ @@ -180,10 +183,10 @@ "key": "existing_resource_group_name" }, { - "key": "key_management_service_encryption_enabled" + "key": "kms_encryption_enabled" }, { - "key": "service_endpoints", + "key": "secrets_manager_endpoint_type", "options": [ { "displayname": "public", @@ -223,6 +226,9 @@ { "key": "kms_key_name" }, + { + "key": "force_delete_kms_key" + }, { "key": "enable_event_notifications" }, @@ -242,27 +248,55 @@ "key": "skip_event_notifications_iam_authorization_policy" }, { - "key":"cbr_rules" + "key": "secrets_manager_cbr_rules" } ], "architecture": { "descriptions": "This architecture supports creating and configuring a Secrets Manager instance.", "features": [ { - "title": "Creates a Secrets Manager instance.", - "description": "Creates and configures an IBM Secrets Manager instance." + "title": "Secrets manager instance creation", + "description": "Yes" + }, + { + "title": "Use existing secrets manager instance", + "description": "Yes" + }, + { + "title": "New resource group creation", + "description": "No" + }, + { + "title": "Use existing resource group", + "description": "Yes" + }, + { + "title": "Enforced private-only endpoint communication", + "description": "Yes" + }, + { + "title": "Enforced KMS encryption", + "description": "Yes" + }, + { + "title": "KMS instance creation", + "description": "No" + }, + { + "title": "KMS key ring and key creation", + "description": "Yes" }, { - "title": "Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance.", - "description": "Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance." + "title": "Use existing KMS key", + "description": "Yes" }, { - "title": "Sets up authorization policy.", - "description": "Sets up IBM IAM authorization policy between IBM Secrets Manager instance and IBM Key Management Service (KMS) instance. It also supports Event Notification authorization policy." + "title": "IAM s2s auth policies creation", + "description": "Yes" }, { - "title": "Configures lifecycle notifications for the Secrets Manager instance.", - "description": "Configures lifecycle notifications for the IBM Secrets Manager instance by connecting an IBM Event Notifications service. The DA supports optionally creating a KMS key ring and key, or using an already existing one to encrypt data." + "title": "Event Notifications integration", + "description": "Yes" } ], "diagrams": [ @@ -380,10 +414,10 @@ ] }, { - "key": "existing_resource_group_name" + "key": "skip_iam_authorization_policy" }, { - "key": "key_management_service_encryption_enabled" + "key": "existing_resource_group_name" }, { "key": "existing_secrets_manager_kms_key_crn" @@ -400,6 +434,9 @@ { "key": "kms_key_name" }, + { + "key": "force_delete_kms_key" + }, { "key": "enable_event_notifications" }, @@ -419,27 +456,55 @@ "key": "skip_event_notifications_iam_authorization_policy" }, { - "key":"cbr_rules" + "key": "secrets_manager_cbr_rules" } ], "architecture": { "descriptions": "This architecture supports creating and configuring a Secrets Manager instance.", "features": [ { - "title": "Creates a Secrets Manager instance.", - "description": "Creates and configures an IBM Secrets Manager instance." + "title": "Secrets manager instance creation", + "description": "Yes" + }, + { + "title": "Use existing secrets manager instance", + "description": "Yes" + }, + { + "title": "New resource group creation", + "description": "No" + }, + { + "title": "Use existing resource group", + "description": "Yes" + }, + { + "title": "Enforced private-only endpoint communication", + "description": "Yes" + }, + { + "title": "Enforced KMS encryption", + "description": "Yes" + }, + { + "title": "KMS instance creation", + "description": "No" + }, + { + "title": "KMS key ring and key creation", + "description": "Yes" }, { - "title": "Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance.", - "description": "Optionally configure an IBM Secrets Manager IAM credentials engine to an IBM Secrets Manager instance." + "title": "Use existing KMS key", + "description": "Yes" }, { - "title": "Sets up authorization policy.", - "description": "Sets up IBM IAM authorization policy between IBM Secrets Manager instance and IBM Key Management Service (KMS) instance. It also supports Event Notification authorization policy." + "title": "IAM s2s auth policies creation", + "description": "Yes" }, { - "title": "Configures lifecycle notifications for the Secrets Manager instance.", - "description": "Configures lifecycle notifications for the IBM Secrets Manager instance by connecting an IBM Event Notifications service. The DA supports optionally creating a KMS key ring and key, or using an already existing one to encrypt data." + "title": "Event Notifications integration", + "description": "Yes" } ], "diagrams": [ diff --git a/reference-architecture/secrets_manager.svg b/reference-architecture/secrets_manager.svg index dcf003a4..5cb34c79 100644 --- a/reference-architecture/secrets_manager.svg +++ b/reference-architecture/secrets_manager.svg @@ -1,4 +1,4 @@ -
IBM Cloud
Region
Resource Group
Secrets Manager
IAM Engine
Existing KMS
Key Ring
Root  KeyEvent Notifications
+
IBM Cloud
Region
Existing Resource Group
Secrets Manager
s2s IAM auth
Existing KMS
Key Ring
Root  Key
Existing Event NotificationsIAM
\ No newline at end of file diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index a7269842..406aac02 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -57,7 +57,7 @@ module "kms" { providers = { ibm = ibm.kms } - count = (var.existing_secrets_manager_crn != null || var.existing_secrets_manager_kms_key_crn != null) ? 0 : (var.key_management_service_encryption_enabled == false ? 0 : 1) # no need to create any KMS resources if passing an existing key, or bucket + count = (var.existing_secrets_manager_crn != null || var.existing_secrets_manager_kms_key_crn != null) ? 0 : (var.kms_encryption_enabled == false ? 0 : 1) # no need to create any KMS resources if passing an existing key, or bucket source = "terraform-ibm-modules/kms-all-inclusive/ibm" version = "4.20.0" create_key_protect_instance = false @@ -75,7 +75,7 @@ module "kms" { standard_key = false rotation_interval_month = 3 dual_auth_delete_enabled = false - force_delete = true + force_delete = var.force_delete_kms_key } ] } @@ -94,16 +94,17 @@ locals { } module "secrets_manager" { - 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 = try("${local.prefix}-${var.secrets_manager_instance_name}", var.secrets_manager_instance_name) - sm_service_plan = var.service_plan - sm_tags = var.secrets_manager_resource_tags + 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 = try("${local.prefix}-${var.secrets_manager_instance_name}", var.secrets_manager_instance_name) + sm_service_plan = var.service_plan + sm_tags = var.secrets_manager_resource_tags + skip_iam_authorization_policy = var.skip_iam_authorization_policy # kms dependency - kms_encryption_enabled = var.key_management_service_encryption_enabled + kms_encryption_enabled = var.kms_encryption_enabled existing_kms_instance_guid = local.existing_kms_guid kms_key_crn = local.kms_key_crn skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy || local.create_cross_account_auth_policy @@ -111,8 +112,8 @@ module "secrets_manager" { enable_event_notification = var.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 - endpoint_type = var.service_endpoints + cbr_rules = var.secrets_manager_cbr_rules + endpoint_type = var.secrets_manager_endpoint_type allowed_network = var.allowed_network } @@ -150,7 +151,7 @@ resource "ibm_en_topic" "en_topic" { count = var.existing_secrets_manager_crn == null && var.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 diff --git a/solutions/fully-configurable/outputs.tf b/solutions/fully-configurable/outputs.tf index 5a26d726..350be297 100644 --- a/solutions/fully-configurable/outputs.tf +++ b/solutions/fully-configurable/outputs.tf @@ -1,6 +1,6 @@ output "resource_group_name" { description = "Resource group name" - value = var.existing_resource_group_name + value = module.resource_group.resource_group_name } output "resource_group_id" { diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index 3a7a277f..12864c36 100644 --- a/solutions/fully-configurable/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 } @@ -21,7 +21,7 @@ variable "provider_visibility" { variable "existing_resource_group_name" { type = string - description = "Name of the existing resource group." + description = "The name of an existing resource group to provision resource in." } variable "region" { @@ -41,7 +41,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" } @@ -61,18 +61,24 @@ variable "service_plan" { } } +variable "skip_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." + 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 "service_endpoints" { +variable "secrets_manager_endpoint_type" { type = string 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.service_endpoints) + condition = contains(["public", "private"], var.secrets_manager_endpoint_type) error_message = "The specified service endpoint is not a valid selection!" } } @@ -80,7 +86,7 @@ variable "service_endpoints" { variable "allowed_network" { type = string description = "The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`." - default = "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!" @@ -107,10 +113,30 @@ variable "existing_secrets_manager_kms_key_crn" { # KMS properties required when creating an encryption key, rather than passing an existing key CRN. ######################################################################################################################## -variable "key_management_service_encryption_enabled" { +variable "kms_encryption_enabled" { type = bool - description = "Set to true to enable Secrets Manager Secrets Encryption." - default = true + description = "Set to true to enable Secrets Manager Secrets Encryption using customer managed keys. When set to true, a value must be passed for `existing_kms_instance_crn`. Cannot be set to true if passing a value for `existing_secrets_manager_crn` or `existing_secrets_manager_kms_key_crn`." + default = false + + 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'." + } + + validation { + condition = var.kms_encryption_enabled ? var.existing_secrets_manager_kms_key_crn == null : true + error_message = "'kms_encryption_enabled' should be false if passing a value for 'existing_secrets_manager_kms_key_crn'." + } + + 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." + } + + validation { + condition = var.kms_encryption_enabled ? (var.existing_kms_instance_crn != null ? true : false) : true + error_message = "An 'existing_kms_instance_crn' is required if 'kms_encryption_enabled_bucket' is set to true." + } } variable "existing_kms_instance_crn" { @@ -119,9 +145,15 @@ variable "existing_kms_instance_crn" { 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`." } +variable "force_delete_kms_key" { + type = bool + default = false + description = "If creating a new KMS key, toggle whether it should be force deleted or not on undeploy." +} + 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)) @@ -197,7 +229,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 diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf index 782b5241..28c49a8d 100644 --- a/solutions/security-enforced/main.tf +++ b/solutions/security-enforced/main.tf @@ -8,13 +8,15 @@ module "secrets_manager" { secrets_manager_instance_name = var.secrets_manager_instance_name existing_secrets_manager_crn = var.existing_secrets_manager_crn service_plan = var.service_plan + skip_iam_authorization_policy = var.skip_iam_authorization_policy secrets_manager_resource_tags = var.secrets_manager_resource_tags - service_endpoints = "private" + secrets_manager_endpoint_type = "private" allowed_network = "private-only" skip_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy existing_secrets_manager_kms_key_crn = var.existing_secrets_manager_kms_key_crn - key_management_service_encryption_enabled = var.key_management_service_encryption_enabled + kms_encryption_enabled = true existing_kms_instance_crn = var.existing_kms_instance_crn + force_delete_kms_key = var.force_delete_kms_key kms_endpoint_type = "private" kms_key_ring_name = var.kms_key_ring_name kms_key_name = var.kms_key_name @@ -25,5 +27,5 @@ module "secrets_manager" { 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 - cbr_rules = var.cbr_rules + secrets_manager_cbr_rules = var.secrets_manager_cbr_rules } diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf index 88c66553..3a5dd619 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -4,13 +4,13 @@ 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 } variable "existing_resource_group_name" { type = string - description = "Name of the existing resource group." + description = "The name of an existing resource group to provision resource in." } variable "region" { @@ -30,7 +30,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" } @@ -50,9 +50,15 @@ variable "service_plan" { } } +variable "skip_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." + 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 = [] } @@ -76,18 +82,18 @@ variable "existing_secrets_manager_kms_key_crn" { # KMS properties required when creating an encryption key, rather than passing an existing key CRN. ######################################################################################################################## -variable "key_management_service_encryption_enabled" { - type = bool - description = "Set to true to enable Secrets Manager Secrets Encryption." - default = true -} - 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`." } +variable "force_delete_kms_key" { + type = bool + default = false + description = "If creating a new KMS key, toggle whether it should be force deleted or not on undeploy." +} + variable "kms_key_ring_name" { type = string default = "secrets-manager-key-ring" @@ -156,7 +162,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 diff --git a/tests/pr_test.go b/tests/pr_test.go index 77d401bc..d9989a6f 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -111,8 +111,7 @@ func TestRunFullyConfigurableSchematics(t *testing.T) { {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: "public_engine_enabled", Value: true, DataType: "bool"}, - {Name: "private_engine_enabled", Value: true, DataType: "bool"}, + {Name: "kms_encryption_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"}, @@ -178,8 +177,7 @@ func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { {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: "public_engine_enabled", Value: true, DataType: "bool"}, - {Name: "private_engine_enabled", Value: true, DataType: "bool"}, + {Name: "kms_encryption_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"}, @@ -226,8 +224,6 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { {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: "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"}, @@ -271,8 +267,6 @@ func TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(t *testing.T) { {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: "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"}, diff --git a/version.tf b/version.tf index 916ac3bd..cb85c3b3 100644 --- a/version.tf +++ b/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= v1.9.0" + required_version = ">= v1.0.0" required_providers { # Use "greater than or equal to" range in modules ibm = { From a6ee04f34004e9f20f8acd2994c2361512ef86e3 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Fri, 21 Mar 2025 15:57:35 +0530 Subject: [PATCH 10/19] fix: resolve comments --- ibm_catalog.json | 8 +- solutions/fully-configurable/DA-cbr_rules.md | 12 +- solutions/fully-configurable/main.tf | 110 +++++++++++++++---- solutions/fully-configurable/variables.tf | 19 ++-- solutions/security-enforced/main.tf | 2 +- solutions/security-enforced/variables.tf | 19 ++-- 6 files changed, 115 insertions(+), 55 deletions(-) diff --git a/ibm_catalog.json b/ibm_catalog.json index a08c2ac1..18bd9ec4 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -227,10 +227,10 @@ "key": "kms_key_name" }, { - "key": "force_delete_kms_key" + "key": "is_hpcs_key" }, { - "key": "enable_event_notifications" + "key": "force_delete_kms_key" }, { "key": "event_notifications_email_list" @@ -435,10 +435,10 @@ "key": "kms_key_name" }, { - "key": "force_delete_kms_key" + "key": "is_hpcs_key" }, { - "key": "enable_event_notifications" + "key": "force_delete_kms_key" }, { "key": "event_notifications_email_list" diff --git a/solutions/fully-configurable/DA-cbr_rules.md b/solutions/fully-configurable/DA-cbr_rules.md index 155a5368..fc23bbf9 100644 --- a/solutions/fully-configurable/DA-cbr_rules.md +++ b/solutions/fully-configurable/DA-cbr_rules.md @@ -2,18 +2,18 @@ Several optional input variables in the IBM Cloud [Secrets Manager deployable architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You specify these inputs when you configure deployable architecture. -* Context-Based Restrictions Rules (`cbr_rules`) +* Context-Based Restrictions Rules (`secrets_manager_cbr_rules`) -## Rules For Context-Based Restrictions +## Rules For Context-Based Restrictions -The `cbr_rules` input variable allows you to provide a rule for the target service to enforce access restrictions for the service based on the context of access requests. Contexts are criteria that include the network location of access requests, the endpoint type from where the request is sent, etc. +The `secrets_manager_cbr_rules` input variable allows you to provide a rule for the target service to enforce access restrictions for the service based on the context of access requests. Contexts are criteria that include the network location of access requests, the endpoint type from where the request is sent, etc. -- Variable name: `cbr_rules`. +- Variable name: `secrets_manager_cbr_rules`. - Type: A list of objects. Allows only one object representing a rule for the target service - Default value: An empty list (`[]`). -### Options for cbr_rules +### Options for secrets_manager_cbr_rules - `description` (required): The description of the rule to create. - `account_id` (required): The IBM Cloud Account ID @@ -34,7 +34,7 @@ The `cbr_rules` input variable allows you to provide a rule for the target servi ### Example Rule For Context-Based Restrictions Configuration ```hcl -cbr_rules = [ +secrets_manager_cbr_rules = [ { description = "Secrets Manager can be accessed from xyz" account_id = "defc0df06b644a9cabc6e44f55b3880s." diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index 406aac02..ecc6e09c 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -19,36 +19,105 @@ locals { 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) - 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 - existing_kms_guid = length(local.parsed_existing_kms_instance_crn) > 0 ? local.parsed_existing_kms_instance_crn[7] : null - create_cross_account_auth_policy = var.existing_secrets_manager_crn == null && !var.skip_kms_iam_authorization_policy && var.ibmcloud_kms_api_key != null - - kms_service_name = local.kms_key_crn != null ? ( - can(regex(".*kms.*", local.kms_key_crn)) ? "kms" : can(regex(".*hs-crypto.*", local.kms_key_crn)) ? "hs-crypto" : null - ) : null + 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 + existing_kms_guid = length(local.parsed_existing_kms_instance_crn) > 0 ? local.parsed_existing_kms_instance_crn[7] : null + 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_hpcs_auth_policy = local.create_cross_account_auth_policy == true && var.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 } data "ibm_iam_account_settings" "iam_account_settings" { count = local.create_cross_account_auth_policy ? 1 : 0 } +######################################################################################################################## +# Parse KMS info from given CRNs +######################################################################################################################## + +module "kms_instance_crn_parser" { + count = var.existing_kms_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_kms_instance_crn +} + +module "kms_key_crn_parser" { + count = var.existing_secrets_manager_kms_key_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_secrets_manager_kms_key_crn +} + +# Create auth policy (scoped to exact KMS key) resource "ibm_iam_authorization_policy" "kms_policy" { - count = local.create_cross_account_auth_policy ? 1 : 0 + count = local.create_cross_account_auth_policy ? 1 : 0 + provider = ibm.kms + source_service_account = data.ibm_iam_account_settings.iam_account_settings[0].account_id + 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}" + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = local.kms_service_name + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = local.kms_account_id + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = local.kms_instance_guid + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "key" + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = local.kms_key_id + } + # Scope of policy now includes the key, so ensure to create new policy before + # destroying old one to prevent any disruption to every day services. + lifecycle { + create_before_destroy = true + } + +} +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_authorization_policy" { + count = local.create_cross_account_auth_policy ? 1 : 0 + depends_on = [ibm_iam_authorization_policy.kms_policy] + create_duration = "30s" +} + +# if using HPCS ,create a second IAM authorization that assigns the Viewer platform access in Hyper Protect Crypto Services .[Learn more](https://cloud.ibm.com/docs/secrets-manager?topic=secrets-manager-mng-data#using-byok) +resource "ibm_iam_authorization_policy" "secrets_manager_hpcs_policy" { + count = local.create_cross_account_hpcs_auth_policy provider = ibm.kms source_service_account = data.ibm_iam_account_settings.iam_account_settings[0].account_id source_service_name = "secrets-manager" source_resource_group_id = module.resource_group[0].resource_group_id target_service_name = local.kms_service_name - target_resource_instance_id = local.existing_kms_guid - roles = ["Reader"] - description = "Allow all Secrets Manager instances in the resource group ${module.resource_group.resource_group_id} in the account ${data.ibm_iam_account_settings.iam_account_settings[0].account_id} to read from the ${local.kms_service_name} instance GUID ${local.existing_kms_guid}" + 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}" } # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 -resource "time_sleep" "wait_for_authorization_policy" { - count = local.create_cross_account_auth_policy ? 1 : 0 - depends_on = [ibm_iam_authorization_policy.kms_policy] +resource "time_sleep" "wait_for_sm_hpcs_authorization_policy" { + count = local.create_cross_account_hpcs_auth_policy + depends_on = [ibm_iam_authorization_policy.secrets_manager_hpcs_policy] create_duration = "30s" } @@ -91,6 +160,7 @@ 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" { @@ -109,7 +179,7 @@ module "secrets_manager" { kms_key_crn = local.kms_key_crn skip_kms_iam_authorization_policy = var.skip_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.secrets_manager_cbr_rules @@ -133,14 +203,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" @@ -148,7 +218,7 @@ 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 = "Topic for SCC instance ${module.secrets_manager.secrets_manager_guid}" @@ -164,7 +234,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/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index 12864c36..e78431c6 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -109,6 +109,12 @@ variable "existing_secrets_manager_kms_key_crn" { default = null } +variable "is_hpcs_key" { + type = bool + description = "Set it to true if the key is Hyper Protect Crypto Services key." + default = true +} + ######################################################################################################################## # KMS properties required when creating an encryption key, rather than passing an existing key CRN. ######################################################################################################################## @@ -147,7 +153,7 @@ variable "existing_kms_instance_crn" { variable "force_delete_kms_key" { type = bool - default = false + default = true description = "If creating a new KMS key, toggle whether it should be force deleted or not on undeploy." } @@ -184,21 +190,10 @@ 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." default = null - - validation { - condition = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? false : true - error_message = "To enable event notifications, an existing event notifications CRN must be set." - } } variable "skip_event_notifications_iam_authorization_policy" { diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf index 28c49a8d..661df665 100644 --- a/solutions/security-enforced/main.tf +++ b/solutions/security-enforced/main.tf @@ -21,7 +21,7 @@ module "secrets_manager" { 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 - enable_event_notifications = var.enable_event_notifications + is_hpcs_key = var.is_hpcs_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 diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf index 3a5dd619..db410977 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -78,6 +78,12 @@ variable "existing_secrets_manager_kms_key_crn" { default = null } +variable "is_hpcs_key" { + type = bool + description = "Set it to true if the key is Hyper Protect Crypto Services key." + default = true +} + ######################################################################################################################## # KMS properties required when creating an encryption key, rather than passing an existing key CRN. ######################################################################################################################## @@ -90,7 +96,7 @@ variable "existing_kms_instance_crn" { variable "force_delete_kms_key" { type = bool - default = false + default = true description = "If creating a new KMS key, toggle whether it should be force deleted or not on undeploy." } @@ -117,21 +123,10 @@ 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." default = null - - validation { - condition = (var.existing_event_notifications_instance_crn == null && var.enable_event_notifications) ? false : true - error_message = "To enable event notifications, an existing event notifications CRN must be set." - } } variable "skip_event_notifications_iam_authorization_policy" { From 1610d86e56e4ed3611063dd167b2257c5e4446ea Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Fri, 21 Mar 2025 16:00:20 +0530 Subject: [PATCH 11/19] fix: resolve comments --- solutions/fully-configurable/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index ecc6e09c..a0b5570d 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -61,7 +61,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" @@ -111,7 +111,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 From 3d5c6de141cd416c89f3e0e2a966062f6138229b Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Fri, 21 Mar 2025 16:19:37 +0530 Subject: [PATCH 12/19] fix: cra-scan --- cra-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/cra-config.yaml b/cra-config.yaml index b6eef45c..5d485b6b 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -6,6 +6,7 @@ CRA_TARGETS: PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" + TF_VAR_kms_encryption_enabled: "true" TF_VAR_existing_resource_group_name: "geretain-test-secrets-manager" TF_VAR_provider_visibility: "public" TF_VAR_prefix: "test" From a13333202655edc2e0191fb4d21ff1693bf3c3c0 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Mon, 24 Mar 2025 12:29:01 +0530 Subject: [PATCH 13/19] resolve conflicts --- solutions/fully-configurable/DA-cbr_rules.md | 2 +- .../catalogValidationValues.json.template | 1 + solutions/fully-configurable/variables.tf | 25 +++++++++++++++++++ solutions/security-enforced/README.md | 2 -- solutions/security-enforced/variables.tf | 25 +++++++++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/solutions/fully-configurable/DA-cbr_rules.md b/solutions/fully-configurable/DA-cbr_rules.md index fc23bbf9..4ff1ac22 100644 --- a/solutions/fully-configurable/DA-cbr_rules.md +++ b/solutions/fully-configurable/DA-cbr_rules.md @@ -34,7 +34,7 @@ The `secrets_manager_cbr_rules` input variable allows you to provide a rule for ### Example Rule For Context-Based Restrictions Configuration ```hcl -secrets_manager_cbr_rules = [ +[ { description = "Secrets Manager can be accessed from xyz" account_id = "defc0df06b644a9cabc6e44f55b3880s." diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template index cd067095..4b9f962d 100644 --- a/solutions/fully-configurable/catalogValidationValues.json.template +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -2,6 +2,7 @@ "ibmcloud_api_key": $VALIDATION_APIKEY, "existing_resource_group_name": "geretain-test-secrets-manager", "service_plan": "trial", + "kms_encryption_enabled": true, "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, "region": "ca-tor" } diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index e78431c6..feebd01c 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -22,6 +22,8 @@ variable "provider_visibility" { 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" { @@ -33,6 +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." + + 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." + } } ######################################################################################################################## @@ -149,6 +161,19 @@ 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 "force_delete_kms_key" { diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md index 2386ab92..67deacd2 100644 --- a/solutions/security-enforced/README.md +++ b/solutions/security-enforced/README.md @@ -5,6 +5,4 @@ This solution supports the following: - Provisioning and configuring of a Secrets Manager instance. - Configuring KMS encryption using a newly created key, or passing an existing key. -![secret-manager-deployable-architecture](../../reference-architecture/secrets_manager.svg) - **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/security-enforced/variables.tf b/solutions/security-enforced/variables.tf index db410977..d3567d79 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -11,6 +11,8 @@ variable "ibmcloud_api_key" { 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" { @@ -22,6 +24,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." + + 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." + } } ######################################################################################################################## @@ -92,6 +104,19 @@ 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 "force_delete_kms_key" { From 0a31f19544a072220be755a9e0677688a85cd676 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Tue, 25 Mar 2025 03:15:42 +0530 Subject: [PATCH 14/19] fix: resolve comments --- examples/fscloud/version.tf | 2 +- ibm_catalog.json | 10 ++-------- .../catalogValidationValues.json.template | 3 ++- solutions/fully-configurable/main.tf | 10 +++++----- solutions/fully-configurable/outputs.tf | 2 +- solutions/fully-configurable/variables.tf | 12 +++--------- .../catalogValidationValues.json.template | 3 ++- solutions/security-enforced/main.tf | 1 - solutions/security-enforced/outputs.tf | 2 +- solutions/security-enforced/variables.tf | 10 ++-------- tests/pr_test.go | 4 ++++ 11 files changed, 23 insertions(+), 36 deletions(-) diff --git a/examples/fscloud/version.tf b/examples/fscloud/version.tf index 86508b36..8f37dab1 100644 --- a/examples/fscloud/version.tf +++ b/examples/fscloud/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0.0" + required_version = ">= 1.3.0" required_providers { # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { diff --git a/ibm_catalog.json b/ibm_catalog.json index 18bd9ec4..3ef35d48 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -20,7 +20,7 @@ "solution" ], "short_description": "Creates and configures a Secrets Manager instance.", - "long_description": "This solution is used to provision and configure an IBM Cloud Secrets Manager instance.", + "long_description": "This deployable architecture is used to provision and configure an [IBM Cloud Secrets Manager](https://www.ibm.com/products/secrets-manager) instance. Centrally manage your secrets in a single-tenant, dedicated instance.\n\n\n💡 This Terraform-based automation is part of a broader suite of IBM-maintained Infrastructure as Code (IaC) asset collection, each following the naming pattern \"Cloud automation for *servicename*\" and focusing on single IBM Cloud service. These single-service deployable architectures can be used on their own to streamline and automate service deployments through an [IaC approach](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-understanding-projects), or assembled together into a broader [automated IaC stack](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-config-stack) to automate the deployment of an end-to-end solution architecture.", "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/security-enforced/README.md", "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-secrets-manager/main/images/secrets_manager.svg", "provider_name": "IBM", @@ -39,7 +39,7 @@ }, { "title": "Configures lifecycle notifications for the Secrets Manager instance.", - "description": "Configures lifecycle notifications for the IBM Secrets Manager instance by connecting an IBM Event Notifications service. The DA supports optionally creating a KMS key ring and key, or using an already existing one to encrypt data." + "description": "Configures lifecycle notifications for the IBM Secrets Manager instance by connecting an IBM Event Notifications service. The automation supports optionally creating a KMS key ring and key, or using an already existing one to encrypt data." } ], "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues](https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/issues). Please note this product is not supported via the IBM Cloud Support Center.", @@ -229,9 +229,6 @@ { "key": "is_hpcs_key" }, - { - "key": "force_delete_kms_key" - }, { "key": "event_notifications_email_list" }, @@ -437,9 +434,6 @@ { "key": "is_hpcs_key" }, - { - "key": "force_delete_kms_key" - }, { "key": "event_notifications_email_list" }, diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template index 4b9f962d..2adb0113 100644 --- a/solutions/fully-configurable/catalogValidationValues.json.template +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -1,8 +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": "ca-tor" + "region": "eu-de" } diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index a0b5570d..0590d010 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -2,7 +2,7 @@ # Resource Group ######################################################################################################################## locals { - prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null + prefix = var.prefix != null ? trimspace(var.prefix) != "" ? "${var.prefix}-" : "" : "" } module "resource_group" { @@ -16,8 +16,8 @@ module "resource_group" { ####################################################################################################################### 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_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 @@ -144,7 +144,7 @@ module "kms" { standard_key = false rotation_interval_month = 3 dual_auth_delete_enabled = false - force_delete = var.force_delete_kms_key + 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. } ] } @@ -169,7 +169,7 @@ module "secrets_manager" { existing_sm_instance_crn = var.existing_secrets_manager_crn resource_group_id = module.resource_group.resource_group_id region = var.region - secrets_manager_name = try("${local.prefix}-${var.secrets_manager_instance_name}", var.secrets_manager_instance_name) + 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_iam_authorization_policy diff --git a/solutions/fully-configurable/outputs.tf b/solutions/fully-configurable/outputs.tf index 350be297..52332205 100644 --- a/solutions/fully-configurable/outputs.tf +++ b/solutions/fully-configurable/outputs.tf @@ -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/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index feebd01c..7cf70dad 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -123,8 +123,8 @@ variable "existing_secrets_manager_kms_key_crn" { variable "is_hpcs_key" { type = bool - description = "Set it to true if the key is Hyper Protect Crypto Services key." - default = true + description = "Set it to true if the key provided through the `existing_kms_instance_crn` is Hyper Protect Crypto Services key." + default = false } ######################################################################################################################## @@ -153,7 +153,7 @@ variable "kms_encryption_enabled" { validation { condition = var.kms_encryption_enabled ? (var.existing_kms_instance_crn != null ? true : false) : true - error_message = "An 'existing_kms_instance_crn' is required if 'kms_encryption_enabled_bucket' is set to true." + error_message = "An 'existing_kms_instance_crn' is required if 'kms_encryption_enabled' is set to true." } } @@ -176,12 +176,6 @@ variable "existing_kms_instance_crn" { } } -variable "force_delete_kms_key" { - type = bool - default = true - description = "If creating a new KMS key, toggle whether it should be force deleted or not on undeploy." -} - variable "kms_endpoint_type" { type = string 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." diff --git a/solutions/security-enforced/catalogValidationValues.json.template b/solutions/security-enforced/catalogValidationValues.json.template index cd067095..c5b44365 100644 --- a/solutions/security-enforced/catalogValidationValues.json.template +++ b/solutions/security-enforced/catalogValidationValues.json.template @@ -1,7 +1,8 @@ { "ibmcloud_api_key": $VALIDATION_APIKEY, "existing_resource_group_name": "geretain-test-secrets-manager", + "prefix": $PREFIX, "service_plan": "trial", "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, - "region": "ca-tor" + "region": "eu-de" } diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf index 661df665..913c08a0 100644 --- a/solutions/security-enforced/main.tf +++ b/solutions/security-enforced/main.tf @@ -16,7 +16,6 @@ module "secrets_manager" { 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 - force_delete_kms_key = var.force_delete_kms_key kms_endpoint_type = "private" kms_key_ring_name = var.kms_key_ring_name kms_key_name = var.kms_key_name diff --git a/solutions/security-enforced/outputs.tf b/solutions/security-enforced/outputs.tf index b29b7975..f212c92d 100644 --- a/solutions/security-enforced/outputs.tf +++ b/solutions/security-enforced/outputs.tf @@ -14,6 +14,6 @@ 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 = module.secrets_manager.secrets_manager_id } diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf index d3567d79..817c644e 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -92,8 +92,8 @@ variable "existing_secrets_manager_kms_key_crn" { variable "is_hpcs_key" { type = bool - description = "Set it to true if the key is Hyper Protect Crypto Services key." - default = true + description = "Set it to true if the key provided through the `existing_kms_instance_crn` is Hyper Protect Crypto Services key." + default = false } ######################################################################################################################## @@ -119,12 +119,6 @@ variable "existing_kms_instance_crn" { } } -variable "force_delete_kms_key" { - type = bool - default = true - description = "If creating a new KMS key, toggle whether it should be force deleted or not on undeploy." -} - variable "kms_key_ring_name" { type = string default = "secrets-manager-key-ring" diff --git a/tests/pr_test.go b/tests/pr_test.go index 8175e206..5294432e 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -111,6 +111,7 @@ func TestRunFullyConfigurableSchematics(t *testing.T) { {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: "is_hpcs_key", Value: true, DataType: "bool"}, {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, {Name: "cis_id", Value: permanentResources["cisInstanceId"], DataType: "string"}, {Name: "ca_name", Value: permanentResources["certificateAuthorityName"], DataType: "string"}, @@ -177,6 +178,7 @@ func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { {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: "is_hpcs_key", Value: true, DataType: "bool"}, {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, {Name: "cis_id", Value: permanentResources["cisInstanceId"], DataType: "string"}, {Name: "ca_name", Value: permanentResources["certificateAuthorityName"], DataType: "string"}, @@ -224,6 +226,7 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { {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: "is_hpcs_key", 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"}, @@ -267,6 +270,7 @@ func TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(t *testing.T) { {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: "is_hpcs_key", 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"}, From 1208b0618b7ca5a1dbe136bc0bfb6402ffa3fcfe Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Tue, 25 Mar 2025 11:24:14 +0530 Subject: [PATCH 15/19] resolve comments --- solutions/fully-configurable/variables.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index 7cf70dad..efa36464 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -152,8 +152,8 @@ variable "kms_encryption_enabled" { } validation { - condition = var.kms_encryption_enabled ? (var.existing_kms_instance_crn != null ? true : false) : true - error_message = "An 'existing_kms_instance_crn' is required if 'kms_encryption_enabled' is set to true." + 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." } } From 8373ece6642b93995f48642fd834bd25365221ec Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 27 Mar 2025 13:23:48 +0530 Subject: [PATCH 16/19] add tests --- .catalog-onboard-pipeline.yaml | 2 + ibm_catalog.json | 22 ++- solutions/fully-configurable/main.tf | 12 +- solutions/fully-configurable/variables.tf | 6 +- tests/existing-resources/version.tf | 2 +- tests/pr_test.go | 174 +++++++++++----------- tests/resources/README.md | 1 + tests/resources/main.tf | 26 ++++ tests/resources/outputs.tf | 14 ++ tests/resources/provider.tf | 4 + tests/resources/variables.tf | 31 ++++ tests/resources/version.tf | 9 ++ 12 files changed, 206 insertions(+), 97 deletions(-) create mode 100644 tests/resources/README.md create mode 100644 tests/resources/main.tf create mode 100644 tests/resources/outputs.tf create mode 100644 tests/resources/provider.tf create mode 100644 tests/resources/variables.tf create mode 100644 tests/resources/version.tf diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml index aa1b21bd..8b1b246c 100644 --- a/.catalog-onboard-pipeline.yaml +++ b/.catalog-onboard-pipeline.yaml @@ -12,9 +12,11 @@ offerings: scc: instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 region: us-south + scope_resource_group_var_name: existing_resource_group_name - name: fully-configurable mark_ready: true install_type: fullstack scc: instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 region: us-south + scope_resource_group_var_name: existing_resource_group_name diff --git a/ibm_catalog.json b/ibm_catalog.json index d247eb27..7b509ead 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -180,7 +180,16 @@ ] }, { - "key": "existing_resource_group_name" + "key": "existing_resource_group_name", + "required": true, + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } }, { "key": "kms_encryption_enabled" @@ -411,7 +420,16 @@ "key": "skip_iam_authorization_policy" }, { - "key": "existing_resource_group_name" + "key": "existing_resource_group_name", + "required": true, + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } }, { "key": "existing_secrets_manager_kms_key_crn" diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index 444a23fa..317e63c2 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -22,16 +22,16 @@ locals { 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 - 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_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) } data "ibm_iam_account_settings" "iam_account_settings" { @@ -129,7 +129,7 @@ module "kms" { providers = { ibm = ibm.kms } - count = (var.existing_secrets_manager_crn != null || var.existing_secrets_manager_kms_key_crn != null) ? 0 : (var.kms_encryption_enabled == false ? 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.20.0" create_key_protect_instance = false diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index d80bec5a..c09eb174 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -127,7 +127,7 @@ variable "existing_secrets_manager_kms_key_crn" { variable "kms_encryption_enabled" { type = bool - description = "Set to true to enable Secrets Manager Secrets Encryption using customer managed keys. When set to true, a value must be passed for `existing_kms_instance_crn`. Cannot be set to true if passing a value for `existing_secrets_manager_crn` or `existing_secrets_manager_kms_key_crn`." + 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 validation { @@ -136,8 +136,8 @@ variable "kms_encryption_enabled" { } validation { - condition = var.kms_encryption_enabled ? var.existing_secrets_manager_kms_key_crn == null : true - error_message = "'kms_encryption_enabled' should be false if passing a value for 'existing_secrets_manager_kms_key_crn'." + 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." } validation { diff --git a/tests/existing-resources/version.tf b/tests/existing-resources/version.tf index 7db4be46..6323b3e9 100644 --- a/tests/existing-resources/version.tf +++ b/tests/existing-resources/version.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.9.0" + required_version = ">= 1.3.0" required_providers { ibm = { source = "ibm-cloud/ibm" diff --git a/tests/pr_test.go b/tests/pr_test.go index c447de8e..3e14b5be 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" @@ -71,27 +69,9 @@ func setupOptions(t *testing.T, prefix string, checkApplyResultForUpgrade bool) return options } -func TestRunUpgradeExample(t *testing.T) { - t.Parallel() - - options := setupOptions(t, "secrets-mgr-upg", true) - - output, err := options.RunTestUpgrade() - if !options.UpgradeTestSkipped { - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") - } -} - func TestRunFullyConfigurableSchematics(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), - ) - // Set up a schematics test options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, @@ -118,59 +98,111 @@ func TestRunFullyConfigurableSchematics(t *testing.T) { {Name: "service_plan", Value: "trial", DataType: "string"}, {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, {Name: "kms_encryption_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"), +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("sm-exist-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := ".." + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) + tags := common.GetTagsFromTravis() + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir + "/tests/existing-resources", + Vars: map[string]interface{}{ + "prefix": prefix, + "region": region, + "resource_tags": tags, }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, }) - if err != nil { - panic(err) - } - getSecretOptions := secretsManagerService.NewGetSecretOptions( - sm_key_id, - ) + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") + } else { - secret, _, err := secretsManagerService.GetSecret(getSecretOptions) - if err != nil { - panic(err) + // ------------------------------------------------------------------------------------ + // Test passing existing RG, EN, and KMS key + // ------------------------------------------------------------------------------------ + 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-fc", + 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: region, DataType: "string"}, + {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_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"}, + } + + err := options.RunSchematicTest() + assert.NoError(t, err, "Schematic Test had unexpected error") + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (existing resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (existing resources)") } - return secret.(*secretsmanagerv2.ArbitrarySecret).Payload } -func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { +func TestExistingKeyFullyConfigurableSchematics(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), - ) - // Set up a schematics test options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, TarIncludePatterns: []string{ "*.tf", fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir), + fmt.Sprintf("%s/*.tf", fscloudExampleTerraformDir), fmt.Sprintf("%s/*.tf", "modules/secrets"), fmt.Sprintf("%s/*.tf", "modules/fscloud"), }, TemplateFolder: fullyConfigurableTerraformDir, ResourceGroup: resourceGroup, - Prefix: "sm-fc-ug", + Prefix: "sm-ek", Tags: []string{"test-schematic"}, DeleteWorkspaceOnFail: false, WaitJobCompleteMinutes: 60, @@ -182,28 +214,22 @@ func TestRunSecretsManagerFullyConfigurableUpgradeSchematic(t *testing.T) { {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"}, + {Name: "existing_secrets_manager_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, {Name: "kms_encryption_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() - if !options.UpgradeTestSkipped { - assert.Nil(t, err, "This should not have errored") - } + err := options.RunSchematicTest() + assert.NoError(t, err, "Schematic Test had unexpected error") } -func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { +func TestRunExistingSMInstanceFullyConfigurable(t *testing.T) { t.Parallel() // ------------------------------------------------------------------------------------ - // Provision Event Notification, KMS key and resource group first + // Provision SM // ------------------------------------------------------------------------------------ region := validRegions[rand.Intn(len(validRegions))] - prefix := fmt.Sprintf("sm-exist-%s", strings.ToLower(random.UniqueId())) + prefix := fmt.Sprintf("sm-ex-%s", strings.ToLower(random.UniqueId())) realTerraformDir := ".." tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) tags := common.GetTagsFromTravis() @@ -215,7 +241,7 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { require.NotEqual(t, "", val, checkVariable+" environment variable is empty") logger.Log(t, "Tempdir: ", tempTerraformDir) existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ - TerraformDir: tempTerraformDir + "/tests/existing-resources", + TerraformDir: tempTerraformDir + "/tests/resources", Vars: map[string]interface{}{ "prefix": prefix, "region": region, @@ -233,7 +259,7 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { } else { // ------------------------------------------------------------------------------------ - // Test passing existing RG, EN, and KMS key + // Test passing existing RG and SM // ------------------------------------------------------------------------------------ options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, @@ -245,7 +271,7 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { }, TemplateFolder: fullyConfigurableTerraformDir, ResourceGroup: resourceGroup, - Prefix: "ex-fc", + Prefix: "ex-scm", Tags: []string{"test-schematic"}, DeleteWorkspaceOnFail: false, WaitJobCompleteMinutes: 60, @@ -256,9 +282,7 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { {Name: "prefix", Value: options.Prefix, DataType: "string"}, {Name: "region", Value: region, DataType: "string"}, {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_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, - {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, + {Name: "existing_secrets_manager_crn", Value: terraform.Output(t, existingTerraformOptions, "secrets_manager_crn"), DataType: "string"}, {Name: "service_plan", Value: "trial", DataType: "string"}, } @@ -281,12 +305,6 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { func TestRunSecurityEnforcedSchematics(t *testing.T) { - 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), - ) - // Set up a schematics test options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, @@ -313,10 +331,6 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { {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: "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() @@ -325,12 +339,6 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { func TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(t *testing.T) { - 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), - ) - // Set up a schematics test options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, @@ -356,10 +364,6 @@ func TestRunSecretsManagerSecurityEnforcedUpgradeSchematic(t *testing.T) { {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: "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() diff --git a/tests/resources/README.md b/tests/resources/README.md new file mode 100644 index 00000000..4ea14c03 --- /dev/null +++ b/tests/resources/README.md @@ -0,0 +1 @@ +# Existing resources to be used in tests diff --git a/tests/resources/main.tf b/tests/resources/main.tf new file mode 100644 index 00000000..fe8bfb1b --- /dev/null +++ b/tests/resources/main.tf @@ -0,0 +1,26 @@ +############################################################################## +# Resource Group +############################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +############################################################################## +# Secrets Manager +############################################################################## + +module "secrets_manager" { + source = "terraform-ibm-modules/secrets-manager/ibm" + version = "1.26.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + secrets_manager_name = "${var.prefix}-sm" + sm_service_plan = "trial" + sm_tags = var.resource_tags + skip_iam_authorization_policy = true +} diff --git a/tests/resources/outputs.tf b/tests/resources/outputs.tf new file mode 100644 index 00000000..d13e6e59 --- /dev/null +++ b/tests/resources/outputs.tf @@ -0,0 +1,14 @@ +output "resource_group_name" { + value = module.resource_group.resource_group_name + description = "Resource group name" +} + +output "resource_group_id" { + value = module.resource_group.resource_group_id + description = "Resource group ID" +} + +output "secrets_manager_crn" { + value = module.secrets_manager.secrets_manager_crn + description = "CRN of the secrets manager instance" +} diff --git a/tests/resources/provider.tf b/tests/resources/provider.tf new file mode 100644 index 00000000..df45ef50 --- /dev/null +++ b/tests/resources/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/tests/resources/variables.tf b/tests/resources/variables.tf new file mode 100644 index 00000000..441068ee --- /dev/null +++ b/tests/resources/variables.tf @@ -0,0 +1,31 @@ +############################################################################## +# Input variables +############################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources" +} + +variable "resource_group" { + type = string + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + default = null +} + +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} diff --git a/tests/resources/version.tf b/tests/resources/version.tf new file mode 100644 index 00000000..6323b3e9 --- /dev/null +++ b/tests/resources/version.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.3.0" + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.76.0" + } + } +} From c3562caed821fd9771f629b2c8c5bcd8015b37a1 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Thu, 27 Mar 2025 14:45:00 +0530 Subject: [PATCH 17/19] fix: error --- tests/pr_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index 3e14b5be..9886b10b 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -70,7 +70,6 @@ func setupOptions(t *testing.T, prefix string, checkApplyResultForUpgrade bool) } func TestRunFullyConfigurableSchematics(t *testing.T) { - t.Parallel() // Set up a schematics test options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ From 02d9e06461da3e22a9fbb7c48f51859b1f0797e8 Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Fri, 28 Mar 2025 02:17:44 +0530 Subject: [PATCH 18/19] resolve comments --- ibm_catalog.json | 66 +++++++++---------- solutions/fully-configurable/README.md | 78 +++++++++++++++++++++++ solutions/fully-configurable/main.tf | 9 ++- solutions/fully-configurable/variables.tf | 4 +- solutions/security-enforced/README.md | 54 ++++++++++++++++ solutions/security-enforced/main.tf | 4 +- solutions/security-enforced/outputs.tf | 5 ++ solutions/security-enforced/variables.tf | 4 +- tests/pr_test.go | 39 +----------- 9 files changed, 182 insertions(+), 81 deletions(-) diff --git a/ibm_catalog.json b/ibm_catalog.json index 7b509ead..4b89b135 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -20,8 +20,8 @@ "solution" ], "short_description": "Creates and configures a Secrets Manager instance.", - "long_description": "This deployable architecture is used to provision and configure an [IBM Cloud Secrets Manager](https://www.ibm.com/products/secrets-manager) instance. Centrally manage your secrets in a single-tenant, dedicated instance.\n\n\n💡 This Terraform-based automation is part of a broader suite of IBM-maintained Infrastructure as Code (IaC) asset collection, each following the naming pattern \"Cloud automation for *servicename*\" and focusing on single IBM Cloud service. These single-service deployable architectures can be used on their own to streamline and automate service deployments through an [IaC approach](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-understanding-projects), or assembled together into a broader [automated IaC stack](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-config-stack) to automate the deployment of an end-to-end solution architecture.", - "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/solutions/security-enforced/README.md", + "long_description": "This deployable architecture is used to provision and configure an [IBM Cloud Secrets Manager](https://www.ibm.com/products/secrets-manager) instance. Centrally manage your secrets in a single-tenant, dedicated instance. This Terraform-based automation is part of a broader suite of IBM-maintained Infrastructure as Code (IaC) asset collection, each following the naming pattern \"Cloud automation for *servicename*\" and focusing on single IBM Cloud service. These single-service deployable architectures can be used on their own to streamline and automate service deployments through an [IaC approach](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-understanding-projects), or assembled together into a broader [automated IaC stack](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-config-stack) to automate the deployment of an end-to-end solution architecture.", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-secrets-manager/blob/main/README.md", "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-secrets-manager/main/images/secrets_manager.svg", "provider_name": "IBM", "features": [ @@ -113,10 +113,6 @@ "required": true, "description": "Prefix to add to all resources created by this solution. To not use any prefix value, you can enter the string `__NULL__`." }, - { - "key": "existing_kms_instance_crn", - "required": true - }, { "key": "provider_visibility", "options": [ @@ -134,12 +130,37 @@ } ] }, + { + "key": "existing_resource_group_name", + "required": true, + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } + }, { "key": "secrets_manager_instance_name" }, { "key": "existing_secrets_manager_crn" }, + { + "key": "secrets_manager_endpoint_type", + "options": [ + { + "displayname": "public", + "value": "public" + }, + { + "displayname": "private", + "value": "private" + } + ] + }, { "key": "secrets_manager_resource_tags", "custom_config": { @@ -164,7 +185,7 @@ ] }, { - "key": "skip_iam_authorization_policy" + "key": "skip_sm_ce_iam_authorization_policy" }, { "key": "allowed_network", @@ -179,39 +200,18 @@ } ] }, - { - "key": "existing_resource_group_name", - "required": true, - "custom_config": { - "type": "resource_group", - "grouping": "deployment", - "original_grouping": "deployment", - "config_constraints": { - "identifier": "rg_name" - } - } - }, { "key": "kms_encryption_enabled" }, { - "key": "secrets_manager_endpoint_type", - "options": [ - { - "displayname": "public", - "value": "public" - }, - { - "displayname": "private", - "value": "private" - } - ] + "key": "existing_kms_instance_crn", + "required": true }, { "key": "existing_secrets_manager_kms_key_crn" }, { - "key": "skip_kms_iam_authorization_policy" + "key": "skip_sm_kms_iam_authorization_policy" }, { "key": "ibmcloud_kms_api_key" @@ -417,7 +417,7 @@ ] }, { - "key": "skip_iam_authorization_policy" + "key": "skip_sm_ce_iam_authorization_policy" }, { "key": "existing_resource_group_name", @@ -435,7 +435,7 @@ "key": "existing_secrets_manager_kms_key_crn" }, { - "key": "skip_kms_iam_authorization_policy" + "key": "skip_sm_kms_iam_authorization_policy" }, { "key": "ibmcloud_kms_api_key" diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md index 20605e6c..4d60060f 100644 --- a/solutions/fully-configurable/README.md +++ b/solutions/fully-configurable/README.md @@ -8,3 +8,81 @@ This solution supports the following: ![secret-manager-deployable-architecture](../../reference-architecture/secrets_manager.svg) **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 | +| [ibm](#requirement\_ibm) | 1.76.2 | +| [time](#requirement\_time) | 0.13.0 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 4.20.0 | +| [kms\_instance\_crn\_parser](#module\_kms\_instance\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [kms\_key\_crn\_parser](#module\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.1.6 | +| [secrets\_manager](#module\_secrets\_manager) | ../.. | n/a | + +### Resources + +| Name | Type | +|------|------| +| [ibm_en_subscription_email.email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/resources/en_subscription_email) | resource | +| [ibm_en_topic.en_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/resources/en_topic) | resource | +| [ibm_iam_authorization_policy.kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/resources/iam_authorization_policy) | resource | +| [ibm_iam_authorization_policy.secrets_manager_hpcs_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/resources/iam_authorization_policy) | resource | +| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/0.13.0/docs/resources/sleep) | resource | +| [time_sleep.wait_for_secrets_manager](https://registry.terraform.io/providers/hashicorp/time/0.13.0/docs/resources/sleep) | resource | +| [time_sleep.wait_for_sm_hpcs_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/0.13.0/docs/resources/sleep) | resource | +| [ibm_en_destinations.en_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/data-sources/en_destinations) | data source | +| [ibm_iam_account_settings.iam_account_settings](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/data-sources/iam_account_settings) | data source | +| [ibm_resource_instance.existing_sm](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.2/docs/data-sources/resource_instance) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [allowed\_network](#input\_allowed\_network) | The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`. | `string` | `"private-only"` | no | +| [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\_encryption\_enabled](#input\_kms\_encryption\_enabled) | 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`. | `bool` | `false` | no | +| [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | 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. | `string` | `"private"` | 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 | +| [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/main.tf b/solutions/fully-configurable/main.tf index 317e63c2..45051078 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -19,13 +19,12 @@ locals { 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 : (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 : (var.existing_kms_instance_crn != null ? module.kms_instance_crn_parser[0].service_name : null) @@ -175,12 +174,12 @@ module "secrets_manager" { 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_iam_authorization_policy + 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 = local.enable_event_notifications existing_en_instance_crn = var.existing_event_notifications_instance_crn diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index c09eb174..55df6bb1 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -73,7 +73,7 @@ variable "service_plan" { } } -variable "skip_iam_authorization_policy" { +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 @@ -109,7 +109,7 @@ variable "allowed_network" { # Key Protect ######################################################################################################################## -variable "skip_kms_iam_authorization_policy" { +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 diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md index 67deacd2..0932c4e6 100644 --- a/solutions/security-enforced/README.md +++ b/solutions/security-enforced/README.md @@ -6,3 +6,57 @@ This solution supports the following: - 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/security-enforced/main.tf b/solutions/security-enforced/main.tf index b81767fd..b7174343 100644 --- a/solutions/security-enforced/main.tf +++ b/solutions/security-enforced/main.tf @@ -8,11 +8,11 @@ module "secrets_manager" { secrets_manager_instance_name = var.secrets_manager_instance_name existing_secrets_manager_crn = var.existing_secrets_manager_crn service_plan = var.service_plan - skip_iam_authorization_policy = var.skip_iam_authorization_policy + 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_kms_iam_authorization_policy = var.skip_kms_iam_authorization_policy + 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 diff --git a/solutions/security-enforced/outputs.tf b/solutions/security-enforced/outputs.tf index f212c92d..d10dfacc 100644 --- a/solutions/security-enforced/outputs.tf +++ b/solutions/security-enforced/outputs.tf @@ -17,3 +17,8 @@ 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/variables.tf b/solutions/security-enforced/variables.tf index 781b27a2..ad308e4a 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -62,7 +62,7 @@ variable "service_plan" { } } -variable "skip_iam_authorization_policy" { +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 @@ -78,7 +78,7 @@ variable "secrets_manager_resource_tags" { # Key Protect ######################################################################################################################## -variable "skip_kms_iam_authorization_policy" { +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 diff --git a/tests/pr_test.go b/tests/pr_test.go index 9886b10b..52880c55 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -25,7 +25,7 @@ const fscloudExampleTerraformDir = "examples/fscloud" 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" @@ -164,7 +164,7 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { {Name: "region", Value: region, DataType: "string"}, {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_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, + {Name: "existing_secrets_manager_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, {Name: "service_plan", Value: "trial", DataType: "string"}, } @@ -186,41 +186,6 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { } } -func TestExistingKeyFullyConfigurableSchematics(t *testing.T) { - t.Parallel() - - // Set up a schematics test - options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ - Testing: t, - TarIncludePatterns: []string{ - "*.tf", - fmt.Sprintf("%s/*.tf", fullyConfigurableTerraformDir), - fmt.Sprintf("%s/*.tf", fscloudExampleTerraformDir), - fmt.Sprintf("%s/*.tf", "modules/secrets"), - fmt.Sprintf("%s/*.tf", "modules/fscloud"), - }, - TemplateFolder: fullyConfigurableTerraformDir, - ResourceGroup: resourceGroup, - Prefix: "sm-ek", - 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_secrets_manager_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, - {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, - } - - err := options.RunSchematicTest() - assert.NoError(t, err, "Schematic Test had unexpected error") -} - func TestRunExistingSMInstanceFullyConfigurable(t *testing.T) { t.Parallel() From ce593927c3d3e7df819c30959b2bd62e0e65474c Mon Sep 17 00:00:00 2001 From: Aayush-Abhyarthi Date: Fri, 28 Mar 2025 21:04:05 +0530 Subject: [PATCH 19/19] fix: resolve comments --- solutions/fully-configurable/main.tf | 2 +- tests/pr_test.go | 99 +++++++--------------------- tests/resources/README.md | 1 - tests/resources/main.tf | 26 -------- tests/resources/outputs.tf | 14 ---- tests/resources/provider.tf | 4 -- tests/resources/variables.tf | 31 --------- tests/resources/version.tf | 9 --- 8 files changed, 24 insertions(+), 162 deletions(-) delete mode 100644 tests/resources/README.md delete mode 100644 tests/resources/main.tf delete mode 100644 tests/resources/outputs.tf delete mode 100644 tests/resources/provider.tf delete mode 100644 tests/resources/variables.tf delete mode 100644 tests/resources/version.tf diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index 45051078..94b74d59 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -15,7 +15,7 @@ module "resource_group" { # 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_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}" diff --git a/tests/pr_test.go b/tests/pr_test.go index 52880c55..d2300c18 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -93,10 +93,8 @@ func TestRunFullyConfigurableSchematics(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: "existing_resource_group_name", Value: "geretain-test-secrets-manager", 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: "kms_encryption_enabled", Value: true, DataType: "bool"}, } err := options.RunSchematicTest() @@ -187,84 +185,33 @@ func TestRunExistingResourcesInstancesFullyConfigurable(t *testing.T) { } func TestRunExistingSMInstanceFullyConfigurable(t *testing.T) { - t.Parallel() - - // ------------------------------------------------------------------------------------ - // Provision SM - // ------------------------------------------------------------------------------------ - region := validRegions[rand.Intn(len(validRegions))] - prefix := fmt.Sprintf("sm-ex-%s", strings.ToLower(random.UniqueId())) - realTerraformDir := ".." - tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) - tags := common.GetTagsFromTravis() - - // Verify ibmcloud_api_key variable is set - checkVariable := "TF_VAR_ibmcloud_api_key" - val, present := os.LookupEnv(checkVariable) - require.True(t, present, checkVariable+" environment variable not set") - require.NotEqual(t, "", val, checkVariable+" environment variable is empty") - logger.Log(t, "Tempdir: ", tempTerraformDir) - existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ - TerraformDir: tempTerraformDir + "/tests/resources", - Vars: map[string]interface{}{ - "prefix": prefix, - "region": region, - "resource_tags": tags, + 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"), }, - // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. - // This is the same as setting the -upgrade=true flag with terraform. - Upgrade: true, + TemplateFolder: fullyConfigurableTerraformDir, + ResourceGroup: resourceGroup, + Prefix: "ex-scm", + Tags: []string{"test-schematic"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, }) - terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) - _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) - if existErr != nil { - assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") - } else { - - // ------------------------------------------------------------------------------------ - // Test passing existing RG and SM - // ------------------------------------------------------------------------------------ - 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: region, DataType: "string"}, - {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, - {Name: "existing_secrets_manager_crn", Value: terraform.Output(t, existingTerraformOptions, "secrets_manager_crn"), DataType: "string"}, - {Name: "service_plan", Value: "trial", DataType: "string"}, - } - - err := options.RunSchematicTest() - assert.NoError(t, err, "Schematic Test had unexpected error") + 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"}, } - // Check if "DO_NOT_DESTROY_ON_FAILURE" is set - envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") - // Destroy the temporary existing resources if required - if t.Failed() && strings.ToLower(envVal) == "true" { - fmt.Println("Terratest failed. Debug the test and delete resources manually.") - } else { - logger.Log(t, "START: Destroy (existing resources)") - terraform.Destroy(t, existingTerraformOptions) - terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) - logger.Log(t, "END: Destroy (existing resources)") - } + err := options.RunSchematicTest() + assert.NoError(t, err, "Schematic Test had unexpected error") } func TestRunSecurityEnforcedSchematics(t *testing.T) { diff --git a/tests/resources/README.md b/tests/resources/README.md deleted file mode 100644 index 4ea14c03..00000000 --- a/tests/resources/README.md +++ /dev/null @@ -1 +0,0 @@ -# Existing resources to be used in tests diff --git a/tests/resources/main.tf b/tests/resources/main.tf deleted file mode 100644 index fe8bfb1b..00000000 --- a/tests/resources/main.tf +++ /dev/null @@ -1,26 +0,0 @@ -############################################################################## -# Resource Group -############################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.6" - # if an existing resource group is not set (null) create a new one using prefix - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group -} - -############################################################################## -# Secrets Manager -############################################################################## - -module "secrets_manager" { - source = "terraform-ibm-modules/secrets-manager/ibm" - version = "1.26.0" - resource_group_id = module.resource_group.resource_group_id - region = var.region - secrets_manager_name = "${var.prefix}-sm" - sm_service_plan = "trial" - sm_tags = var.resource_tags - skip_iam_authorization_policy = true -} diff --git a/tests/resources/outputs.tf b/tests/resources/outputs.tf deleted file mode 100644 index d13e6e59..00000000 --- a/tests/resources/outputs.tf +++ /dev/null @@ -1,14 +0,0 @@ -output "resource_group_name" { - value = module.resource_group.resource_group_name - description = "Resource group name" -} - -output "resource_group_id" { - value = module.resource_group.resource_group_id - description = "Resource group ID" -} - -output "secrets_manager_crn" { - value = module.secrets_manager.secrets_manager_crn - description = "CRN of the secrets manager instance" -} diff --git a/tests/resources/provider.tf b/tests/resources/provider.tf deleted file mode 100644 index df45ef50..00000000 --- a/tests/resources/provider.tf +++ /dev/null @@ -1,4 +0,0 @@ -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} diff --git a/tests/resources/variables.tf b/tests/resources/variables.tf deleted file mode 100644 index 441068ee..00000000 --- a/tests/resources/variables.tf +++ /dev/null @@ -1,31 +0,0 @@ -############################################################################## -# Input variables -############################################################################## - -variable "ibmcloud_api_key" { - type = string - description = "The IBM Cloud API Key" - sensitive = true -} - -variable "region" { - type = string - description = "Region" -} - -variable "prefix" { - type = string - description = "Prefix to append to all resources" -} - -variable "resource_group" { - type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" - default = null -} - -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} diff --git a/tests/resources/version.tf b/tests/resources/version.tf deleted file mode 100644 index 6323b3e9..00000000 --- a/tests/resources/version.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - required_version = ">= 1.3.0" - required_providers { - ibm = { - source = "ibm-cloud/ibm" - version = ">= 1.76.0" - } - } -}