diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 4d2c20d6..5425bb0a 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -3,8 +3,8 @@ ############################################################################## locals { - secret_manager_guid = var.existing_secret_manager_instance_guid == null ? module.secrets_manager[0].secrets_manager_guid : var.existing_secret_manager_instance_guid - secret_manager_region = var.existing_secret_manager_instance_region == null ? var.region : var.existing_secret_manager_instance_region + secrets_manager_guid = var.existing_secrets_manager_instance_guid == null ? module.secrets_manager[0].secrets_manager_guid : var.existing_secrets_manager_instance_guid + secrets_manager_region = var.existing_secrets_manager_instance_region == null ? var.region : var.existing_secrets_manager_instance_region service_credential_names = { "es_admin" : "Administrator", "es_operator" : "Operator", @@ -131,7 +131,7 @@ module "icd_mongodb" { # Create Secrets Manager Instance (if not using existing one) module "secrets_manager" { - count = var.existing_secret_manager_instance_guid == null ? 1 : 0 + count = var.existing_secrets_manager_instance_guid == null ? 1 : 0 source = "terraform-ibm-modules/secrets-manager/ibm" version = "2.2.6" resource_group_id = module.resource_group.resource_group_id @@ -146,8 +146,8 @@ module "secrets_manager" { module "secrets_manager_secrets_group" { source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" version = "1.3.4" - region = local.secret_manager_region - secrets_manager_guid = local.secret_manager_guid + region = local.secrets_manager_region + secrets_manager_guid = local.secrets_manager_guid #tfsec:ignore:general-secrets-no-plaintext-exposure secret_group_name = "${var.prefix}-es-secrets" secret_group_description = "service secret-group" #tfsec:ignore:general-secrets-no-plaintext-exposure @@ -158,8 +158,8 @@ module "secrets_manager_service_credentials_user_pass" { source = "terraform-ibm-modules/secrets-manager-secret/ibm" version = "1.7.0" for_each = local.service_credential_names - region = local.secret_manager_region - secrets_manager_guid = local.secret_manager_guid + region = local.secrets_manager_region + secrets_manager_guid = local.secrets_manager_guid secret_group_id = module.secrets_manager_secrets_group.secret_group_id secret_name = "${var.prefix}-${each.key}-credentials" secret_description = "MongoDB Service Credentials for ${each.key}" @@ -172,8 +172,8 @@ module "secrets_manager_service_credentials_user_pass" { module "secrets_manager_service_credentials_cert" { source = "terraform-ibm-modules/secrets-manager-secret/ibm" version = "1.7.0" - region = local.secret_manager_region - secrets_manager_guid = local.secret_manager_guid + region = local.secrets_manager_region + secrets_manager_guid = local.secrets_manager_guid secret_group_id = module.secrets_manager_secrets_group.secret_group_id secret_name = "${var.prefix}-es-cert" secret_description = "MongoDB Service Credential Certificate" diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 4d6df5f4..662f4afc 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -47,15 +47,15 @@ variable "plan" { default = "enterprise" } -variable "existing_secret_manager_instance_guid" { +variable "existing_secrets_manager_instance_guid" { type = string description = "Existing Secrets Manager GUID. If not provided an new instance will be provisioned" default = null } -variable "existing_secret_manager_instance_region" { +variable "existing_secrets_manager_instance_region" { type = string - description = "Required if value is passed into var.existing_secret_manager_instance_guid" + description = "Required if value is passed into var.existing_secrets_manager_instance_guid" default = null } diff --git a/ibm_catalog.json b/ibm_catalog.json index 38bda124..cfd13a06 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -226,16 +226,16 @@ "key": "admin_pass" }, { - "key": "admin_pass_secret_manager_secret_group" + "key": "admin_pass_secrets_manager_secret_group" }, { - "key": "admin_pass_secret_manager_secret_name" + "key": "admin_pass_secrets_manager_secret_name" }, { "key": "existing_mongodb_instance_crn" }, { - "key": "use_existing_admin_pass_secret_manager_secret_group" + "key": "use_existing_admin_pass_secrets_manager_secret_group" }, { "key": "users" @@ -292,7 +292,7 @@ "key": "service_credential_secrets" }, { - "key": "skip_mongodb_secret_manager_auth_policy" + "key": "skip_mongodb_secrets_manager_auth_policy" } ] } diff --git a/solutions/standard/main.tf b/solutions/standard/main.tf index e2c18b01..f8285f8d 100644 --- a/solutions/standard/main.tf +++ b/solutions/standard/main.tf @@ -9,13 +9,12 @@ module "resource_group" { existing_resource_group_name = var.use_existing_resource_group == true ? var.resource_group_name : null } - ####################################################################################################################### # KMS encryption key ####################################################################################################################### locals { - create_new_kms_key = var.existing_mongodb_instance_crn == null && !var.use_ibm_owned_encryption_key && var.existing_kms_key_crn == null ? 1 : 0 # no need to create any KMS resources if passing an existing key, or using IBM owned keys + create_new_kms_key = var.existing_mongodb_instance_crn == null && !var.use_ibm_owned_encryption_key && var.existing_kms_key_crn == null ? true : false # no need to create any KMS resources if passing an existing key, or using IBM owned keys mongodb_key_name = var.prefix != null ? "${var.prefix}-${var.key_name}" : var.key_name mongodb_key_ring_name = var.prefix != null ? "${var.prefix}-${var.key_ring_name}" : var.key_ring_name } @@ -24,7 +23,7 @@ module "kms" { providers = { ibm = ibm.kms } - count = local.create_new_kms_key + count = local.create_new_kms_key ? 1 : 0 source = "terraform-ibm-modules/kms-all-inclusive/ibm" version = "5.0.2" create_key_protect_instance = false @@ -89,7 +88,6 @@ locals { create_cross_account_kms_auth_policy = var.existing_mongodb_instance_crn == null && var.ibmcloud_kms_api_key != null && !var.use_ibm_owned_encryption_key create_cross_account_backup_kms_auth_policy = var.existing_mongodb_instance_crn == null && var.ibmcloud_kms_api_key != null && !var.use_ibm_owned_encryption_key && var.existing_backup_kms_key_crn != null - # If KMS encryption enabled (and existing ES instance is not being passed), parse details from the existing key if being passed, otherwise get it from the key that the DA creates kms_account_id = var.existing_mongodb_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : module.kms_instance_crn_parser[0].account_id kms_service = var.existing_mongodb_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : module.kms_instance_crn_parser[0].service_name @@ -98,7 +96,6 @@ locals { kms_key_id = var.existing_mongodb_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].resource : module.kms[0].keys[format("%s.%s", local.mongodb_key_ring_name, local.mongodb_key_name)].key_id kms_region = var.existing_mongodb_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].region : module.kms_instance_crn_parser[0].region - # If creating KMS cross account policy for backups, parse backup key details from passed in key CRN backup_kms_account_id = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].account_id : local.kms_account_id backup_kms_service = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].service_name : local.kms_service @@ -223,8 +220,6 @@ locals { # elseif _ replace first char with K # else use asis generated_admin_password = startswith(random_password.admin_password[0].result, "-") ? "J${substr(random_password.admin_password[0].result, 1, -1)}" : startswith(random_password.admin_password[0].result, "_") ? "K${substr(random_password.admin_password[0].result, 1, -1)}" : random_password.admin_password[0].result - - # admin password to use admin_pass = var.admin_pass == null ? local.generated_admin_password : var.admin_pass } @@ -315,21 +310,20 @@ locals { ####################################################################################################################### locals { - create_secret_manager_auth_policy = var.skip_mongodb_secret_manager_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1 + create_secrets_manager_auth_policy = var.skip_mongodb_secrets_manager_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1 } # Parse the Secrets Manager CRN -module "secret_manager_instance_crn_parser" { +module "secrets_manager_instance_crn_parser" { count = var.existing_secrets_manager_instance_crn != null ? 1 : 0 source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" version = "1.1.0" crn = var.existing_secrets_manager_instance_crn } - # create a service authorization between Secrets Manager and the target service (Databases for MongoDB) resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { - count = local.create_secret_manager_auth_policy + count = local.create_secrets_manager_auth_policy depends_on = [module.mongodb] source_service_name = "secrets-manager" source_resource_instance_id = local.existing_secrets_manager_instance_guid @@ -341,7 +335,7 @@ resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 resource "time_sleep" "wait_for_mongodb_authorization_policy" { - count = local.create_secret_manager_auth_policy + count = local.create_secrets_manager_auth_policy depends_on = [ibm_iam_authorization_policy.secrets_manager_key_manager] create_duration = "30s" } @@ -371,10 +365,10 @@ locals { # Build the structure of the arbitrary credential type secret for admin password admin_pass_secret = [{ - secret_group_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secret_manager_secret_group != null ? "${var.prefix}-${var.admin_pass_secret_manager_secret_group}" : var.admin_pass_secret_manager_secret_group - existing_secret_group = var.use_existing_admin_pass_secret_manager_secret_group + secret_group_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secrets_manager_secret_group != null ? "${var.prefix}-${var.admin_pass_secrets_manager_secret_group}" : var.admin_pass_secrets_manager_secret_group + existing_secret_group = var.use_existing_admin_pass_secrets_manager_secret_group secrets = [{ - secret_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secret_manager_secret_name != null ? "${var.prefix}-${var.admin_pass_secret_manager_secret_name}" : var.admin_pass_secret_manager_secret_name + secret_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secrets_manager_secret_name != null ? "${var.prefix}-${var.admin_pass_secrets_manager_secret_name}" : var.admin_pass_secrets_manager_secret_name secret_type = "arbitrary" secret_payload_password = local.admin_pass } @@ -384,8 +378,8 @@ locals { # Concatinate into 1 secrets object secrets = concat(local.service_credential_secrets, local.admin_pass_secret) # Parse Secrets Manager details from the CRN - existing_secrets_manager_instance_guid = var.existing_secrets_manager_instance_crn != null ? module.secret_manager_instance_crn_parser[0].service_instance : null - existing_secrets_manager_instance_region = var.existing_secrets_manager_instance_crn != null ? module.secret_manager_instance_crn_parser[0].region : null + existing_secrets_manager_instance_guid = var.existing_secrets_manager_instance_crn != null ? module.secrets_manager_instance_crn_parser[0].service_instance : null + existing_secrets_manager_instance_region = var.existing_secrets_manager_instance_crn != null ? module.secrets_manager_instance_crn_parser[0].region : null } module "secrets_manager_service_credentials" { diff --git a/solutions/standard/variables.tf b/solutions/standard/variables.tf index 243aa0df..585da345 100644 --- a/solutions/standard/variables.tf +++ b/solutions/standard/variables.tf @@ -192,6 +192,7 @@ 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_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'." @@ -304,6 +305,7 @@ variable "existing_secrets_manager_endpoint_type" { type = string description = "The endpoint type to use if `existing_secrets_manager_instance_crn` is specified. Possible values: public, private." default = "private" + validation { condition = contains(["public", "private"], var.existing_secrets_manager_endpoint_type) error_message = "Only \"public\" and \"private\" are allowed values for 'existing_secrets_endpoint_type'." @@ -350,13 +352,13 @@ variable "service_credential_secrets" { } } -variable "skip_mongodb_secret_manager_auth_policy" { +variable "skip_mongodb_secrets_manager_auth_policy" { type = bool description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Databases for MongoDB. If set to false, the Secrets Manager instance passed by the user is granted the Key Manager access to the MongoDB instance created by the Deployable Architecture. Set to `true` to use an existing policy. The value of this is ignored if any value for 'existing_secrets_manager_instance_crn' is not passed." default = false } -variable "admin_pass_secret_manager_secret_group" { +variable "admin_pass_secrets_manager_secret_group" { type = string description = "The name of a new or existing secrets manager secret group for admin password. To use existing secret group, `use_existing_admin_pass_secrets_manager_secret_group` must be set to `true`. If a prefix input variable is specified, the prefix is added to the name in the `-` format." default = "mongodb-secrets" @@ -364,27 +366,28 @@ variable "admin_pass_secret_manager_secret_group" { validation { condition = ( var.existing_secrets_manager_instance_crn == null || - var.admin_pass_secret_manager_secret_group != null + var.admin_pass_secrets_manager_secret_group != null ) - error_message = "`admin_pass_secret_manager_secret_group` is required when `existing_secrets_manager_instance_crn` is set." + error_message = "`admin_pass_secrets_manager_secret_group` is required when `existing_secrets_manager_instance_crn` is set." } } -variable "use_existing_admin_pass_secret_manager_secret_group" { +variable "use_existing_admin_pass_secrets_manager_secret_group" { type = bool description = "Whether to use an existing secrets manager secret group for admin password." default = false } -variable "admin_pass_secret_manager_secret_name" { +variable "admin_pass_secrets_manager_secret_name" { type = string description = "The name of a new mongodb administrator secret. If a prefix input variable is specified, the prefix is added to the name in the `-` format." default = "mongodb-admin-password" + validation { condition = ( var.existing_secrets_manager_instance_crn == null || - var.admin_pass_secret_manager_secret_name != null + var.admin_pass_secrets_manager_secret_name != null ) - error_message = "`admin_pass_secret_manager_secret_name` is required when `existing_secrets_manager_instance_crn` is set." + error_message = "`admin_pass_secrets_manager_secret_name` is required when `existing_secrets_manager_instance_crn` is set." } } diff --git a/tests/other_test.go b/tests/other_test.go index 47868c1d..96da1cf4 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -2,11 +2,14 @@ package test import ( + "crypto/rand" + "encoding/base64" "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" ) @@ -55,3 +58,41 @@ func TestRunRestoredDBExample(t *testing.T) { assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } + +func TestRunCompleteExample(t *testing.T) { + t.Parallel() + + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: "examples/complete", + Prefix: "mongodb-upg", + BestRegionYAMLPath: regionSelectionPath, + ResourceGroup: resourceGroup, + TerraformVars: map[string]interface{}{ + "mongodb_version": "6.0", // Always lock to the lowest supported MongoDB version + "plan": "standard", + "users": []map[string]interface{}{ + { + "name": "testuser", + "password": GetRandomAdminPassword(t), + "type": "database", + }, + }, + "admin_pass": GetRandomAdminPassword(t), + }, + CloudInfoService: sharedInfoSvc, + }) + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} + +func GetRandomAdminPassword(t *testing.T) string { + // Generate a 15 char long random string for the admin_pass + randomBytes := make([]byte, 13) + _, randErr := rand.Read(randomBytes) + require.Nil(t, randErr) // do not proceed if we can't gen a random password + randomPass := "A1" + base64.URLEncoding.EncodeToString(randomBytes)[:13] + return randomPass +} diff --git a/tests/pr_test.go b/tests/pr_test.go index f793b26d..8c3c5cb2 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -103,8 +103,8 @@ func TestRunStandardSolutionSchematics(t *testing.T) { {Name: "service_credential_names", Value: "{\"admin_test\": \"Administrator\", \"editor_test\": \"Editor\"}", DataType: "map(string)"}, {Name: "existing_secrets_manager_instance_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"}, {Name: "service_credential_secrets", Value: serviceCredentialSecrets, DataType: "list(object)"}, - {Name: "admin_pass_secret_manager_secret_group", Value: options.Prefix, DataType: "string"}, - {Name: "admin_pass_secret_manager_secret_name", Value: options.Prefix, DataType: "string"}, + {Name: "admin_pass_secrets_manager_secret_group", Value: options.Prefix, DataType: "string"}, + {Name: "admin_pass_secrets_manager_secret_name", Value: options.Prefix, DataType: "string"}, {Name: "provider_visibility", Value: "private", DataType: "string"}, {Name: "prefix", Value: options.Prefix, DataType: "string"}, }