diff --git a/README.md b/README.md index 6d5dfab1..1cd4be7b 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ You need the following permissions to run this module. | [kms\_key\_crn](#input\_kms\_key\_crn) | The root key CRN of a key management service like Key Protect or Hyper Protect Crypto Services that you want to use for encryption. Only used if `kms_encryption_enabled` is set to `true`. | `string` | `null` | no | | [region](#input\_region) | The region where the instance is created. Not required if passing a value for `existing_sm_instance_crn`. | `string` | `null` | no | | [resource\_group\_id](#input\_resource\_group\_id) | The ID of the resource group that contains the Secrets Manager instance. | `string` | n/a | yes | -| [secrets](#input\_secrets) | Secret Manager secrets configurations. |
list(object({
secret_group_name = string
secret_group_description = optional(string)
existing_secret_group = optional(bool, false)
create_access_group = optional(bool, false)
access_group_name = optional(string)
access_group_roles = optional(list(string))
access_group_tags = optional(list(string))
secrets = optional(list(object({
secret_name = string
secret_description = optional(string)
secret_type = optional(string)
imported_cert_certificate = optional(string)
imported_cert_private_key = optional(string)
imported_cert_intermediate = optional(string)
secret_username = optional(string)
secret_labels = optional(list(string), [])
secret_payload_password = optional(string, "")
secret_auto_rotation = optional(bool, true)
secret_auto_rotation_unit = optional(string, "day")
secret_auto_rotation_interval = optional(number, 89)
service_credentials_ttl = optional(string, "7776000") # 90 days
service_credentials_source_service_crn = optional(string)
service_credentials_source_service_role_crn = optional(string)
})))
}))
| `[]` | no | +| [secrets](#input\_secrets) | Secret Manager secrets configurations. |
list(object({
secret_group_name = string
secret_group_description = optional(string)
existing_secret_group = optional(bool, false)
create_access_group = optional(bool, false)
access_group_name = optional(string)
access_group_roles = optional(list(string))
access_group_tags = optional(list(string))
secrets = optional(list(object({
secret_name = string
secret_description = optional(string)
secret_type = optional(string)
imported_cert_certificate = optional(string)
imported_cert_private_key = optional(string)
imported_cert_intermediate = optional(string)
secret_username = optional(string)
secret_labels = optional(list(string), [])
secret_payload_password = optional(string, "")
secret_auto_rotation = optional(bool, true)
secret_auto_rotation_unit = optional(string, "day")
secret_auto_rotation_interval = optional(number, 89)
service_credentials_ttl = optional(string, "7776000") # 90 days
service_credentials_source_service_crn = optional(string)
service_credentials_source_service_role_crn = optional(string)
custom_credentials_configurations = optional(string)
custom_credentials_parameters = optional(bool, false)
job_parameters = optional(object({
integer_values = optional(map(number))
string_values = optional(map(string))
boolean_values = optional(map(bool))
}), {})
})))
}))
| `[]` | no | | [secrets\_manager\_name](#input\_secrets\_manager\_name) | The name of the Secrets Manager instance to create | `string` | n/a | yes | | [skip\_en\_iam\_authorization\_policy](#input\_skip\_en\_iam\_authorization\_policy) | Set to true to skip creating an IAM authorization policy that permits all Secrets Manager instances (scoped to the resource group) an 'Event Source Manager' role to the given Event Notifications instance passed in the `existing_en_instance_crn` input variable. No policy is created if `enable_event_notification` is set to `false`. | `bool` | `false` | no | | [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Whether to skip creating the IAM authorization policies that are required to enable the IAM credentials engine. If set to `false`, policies are created that grant the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manager' access to the IAM groups service. | `bool` | `false` | no | diff --git a/examples/complete/README.md b/examples/complete/README.md index b73ce85f..825d5ece 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -8,6 +8,7 @@ This examples handles the provisioning of a new Secrets Manager instance. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= v1.9.0 | +| [http](#requirement\_http) | 3.2.1 | | [ibm](#requirement\_ibm) | >=1.79.0 | | [time](#requirement\_time) | 0.12.1 | @@ -15,17 +16,25 @@ This examples handles the provisioning of a new Secrets Manager instance. | Name | Source | Version | |------|--------|---------| +| [code\_engine\_build](#module\_code\_engine\_build) | terraform-ibm-modules/code-engine/ibm//modules/build | 4.5.8 | +| [code\_engine\_job](#module\_code\_engine\_job) | terraform-ibm-modules/code-engine/ibm//modules/job | 4.5.8 | +| [code\_engine\_project](#module\_code\_engine\_project) | terraform-ibm-modules/code-engine/ibm//modules/project | 4.5.8 | +| [code\_engine\_secret](#module\_code\_engine\_secret) | terraform-ibm-modules/code-engine/ibm//modules/secret | 4.5.8 | +| [custom\_credential\_engine](#module\_custom\_credential\_engine) | terraform-ibm-modules/secrets-manager-custom-credentials-engine/ibm | 1.0.0 | | [event\_notification](#module\_event\_notification) | terraform-ibm-modules/event-notifications/ibm | 2.6.24 | | [key\_protect](#module\_key\_protect) | terraform-ibm-modules/kms-all-inclusive/ibm | 5.1.24 | | [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.3.0 | +| [secret\_manager\_custom\_credential](#module\_secret\_manager\_custom\_credential) | terraform-ibm-modules/secrets-manager-secret/ibm | 1.9.0 | | [secrets\_manager](#module\_secrets\_manager) | ../.. | n/a | ### Resources | Name | Type | |------|------| +| [ibm_cr_namespace.rg_namespace](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/cr_namespace) | resource | | [ibm_iam_authorization_policy.en_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | | [time_sleep.wait_for_en_policy](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | +| [http_http.job_config](https://registry.terraform.io/providers/hashicorp/http/3.2.1/docs/data-sources/http) | data source | ### Inputs diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 941c9f2c..f1b8eac7 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -81,6 +81,11 @@ module "secrets_manager" { secret_description = "Created by secrets-manager-module complete example" service_credentials_source_service_crn = module.event_notification.crn service_credentials_source_service_role_crn = "crn:v1:bluemix:public:event-notifications::::serviceRole:Event-Notification-Publisher" + }, + { + secret_name = "${var.prefix}-custom-service-credential" + secret_type = "arbitrary" + secret_payload_password = var.ibmcloud_api_key } ] }, @@ -96,3 +101,135 @@ module "secrets_manager" { } ] } + +############################################################################## +# Code Engine Project +############################################################################## +module "code_engine_project" { + source = "terraform-ibm-modules/code-engine/ibm//modules/project" + version = "4.5.8" + name = "${var.prefix}-project" + resource_group_id = module.resource_group.resource_group_id +} + +############################################################################## +# Code Engine Secret +############################################################################## +locals { + registry_hostname = "private.de.icr.io" + output_image = "${local.registry_hostname}/${resource.ibm_cr_namespace.rg_namespace.name}/custom-engine-job" +} + +module "code_engine_secret" { + source = "terraform-ibm-modules/code-engine/ibm//modules/secret" + version = "4.5.8" + name = "${var.prefix}-rs" + project_id = module.code_engine_project.id + format = "registry" + data = { + "server" = local.registry_hostname, + "username" = "iamapikey", + "password" = var.ibmcloud_api_key, + } +} + +############################################################################## +# Container Registry Namespace +############################################################################## +resource "ibm_cr_namespace" "rg_namespace" { + name = "${var.prefix}-crn" + resource_group_id = module.resource_group.resource_group_id +} + +############################################################################## +# Code Engine Build +############################################################################## + +# For example the region is hardcoded to us-south in order to hardcode the output image and region for creating Code Engine Project and build +module "code_engine_build" { + source = "terraform-ibm-modules/code-engine/ibm//modules/build" + version = "4.5.8" + name = "${var.prefix}-build" + region = var.region + ibmcloud_api_key = var.ibmcloud_api_key + project_id = module.code_engine_project.id + existing_resource_group_id = module.resource_group.resource_group_id + source_url = "https://github.com/IBM/secrets-manager-custom-credentials-providers" + source_context_dir = "ibmcloud-iam-user-apikey-provider-go" + strategy_type = "dockerfile" + output_secret = module.code_engine_secret.name + output_image = local.output_image +} + +############################################################################## +# Code Engine Job +############################################################################## + +data "http" "job_config" { + url = "https://raw.githubusercontent.com/IBM/secrets-manager-custom-credentials-providers/refs/heads/main/ibmcloud-iam-user-apikey-provider-go/job_config.json" + request_headers = { + Accept = "application/json" + } +} + +locals { + job_env_variables = jsondecode(data.http.job_config.response_body).job_env_variables +} + +module "code_engine_job" { + depends_on = [module.code_engine_build] + source = "terraform-ibm-modules/code-engine/ibm//modules/job" + version = "4.5.8" + name = "${var.prefix}-job" + image_reference = local.output_image + image_secret = module.code_engine_secret.name + project_id = module.code_engine_project.id + run_env_variables = [ + for env_var in local.job_env_variables : { + type = "literal" + name = env_var.name + value = tostring(env_var.value) + } + ] +} + +############################################################################## +# Custom Credential Engine and secret +############################################################################## + +module "custom_credential_engine" { + depends_on = [module.secrets_manager, module.code_engine_job] + source = "terraform-ibm-modules/secrets-manager-custom-credentials-engine/ibm" + version = "1.0.0" + secrets_manager_guid = module.secrets_manager.secrets_manager_guid + secrets_manager_region = module.secrets_manager.secrets_manager_region + custom_credential_engine_name = "${var.prefix}-test-custom-engine" + endpoint_type = "public" + code_engine_project_id = module.code_engine_project.project_id + code_engine_job_name = module.code_engine_job.name + code_engine_region = var.region + task_timeout = "10m" + service_id_name = "${var.prefix}-test-service-id" + iam_credential_secret_name = "${var.prefix}-test-iam-secret" +} + +# Currently the main module cannot be called again as some of the count for resources depends on a computable input existing_en_instance_crn which will give error if the value is not available during planning +# As a workaround the secret manager secret is directly being created via module call +module "secret_manager_custom_credential" { + depends_on = [module.secrets_manager, module.custom_credential_engine] + source = "terraform-ibm-modules/secrets-manager-secret/ibm" + version = "1.9.0" + secret_type = "custom_credentials" #checkov:skip=CKV_SECRET_6 + region = module.secrets_manager.secrets_manager_region + secrets_manager_guid = module.secrets_manager.secrets_manager_guid + secret_name = "${var.prefix}-custom-credentials" + secret_description = "created by secrets-manager module complete example" + custom_credentials_configurations = module.custom_credential_engine.custom_config_engine_name + custom_metadata = { "metadata_custom_key" : "metadata_custom_value" } # can add any custom metadata here + custom_credentials_parameters = true + job_parameters = { + string_values = { + apikey_secret_id = module.secrets_manager.secrets["${var.prefix}-custom-service-credential"].secret_id + } + } +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index ae1c3008..e1a421e3 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -18,7 +18,7 @@ variable "sm_service_plan" { variable "region" { type = string description = "Region where resources will be created" - default = "eu-de" + default = "eu-de" # Region is defaulted to eu-de in order to restrict the code engine project and build creation with a hardcoded output image `private.de` } variable "resource_group" { diff --git a/examples/complete/version.tf b/examples/complete/version.tf index b5dd453f..d9f2ee1a 100644 --- a/examples/complete/version.tf +++ b/examples/complete/version.tf @@ -9,5 +9,9 @@ terraform { source = "hashicorp/time" version = "0.12.1" } + http = { + source = "hashicorp/http" + version = "3.2.1" + } } } diff --git a/modules/secrets/README.md b/modules/secrets/README.md index 9b444465..6feaf8a6 100644 --- a/modules/secrets/README.md +++ b/modules/secrets/README.md @@ -51,7 +51,7 @@ module "secrets_manager" { | Name | Source | Version | |------|--------|---------| | [secret\_groups](#module\_secret\_groups) | terraform-ibm-modules/secrets-manager-secret-group/ibm | 1.3.15 | -| [secrets](#module\_secrets) | terraform-ibm-modules/secrets-manager-secret/ibm | 1.8.0 | +| [secrets](#module\_secrets) | terraform-ibm-modules/secrets-manager-secret/ibm | 1.9.0 | ### Resources @@ -66,7 +66,7 @@ module "secrets_manager" { | [endpoint\_type](#input\_endpoint\_type) | The service endpoint type to communicate with the provided secrets manager instance. Possible values are `public` or `private` | `string` | `"public"` | no | | [existing\_sm\_instance\_guid](#input\_existing\_sm\_instance\_guid) | Instance ID of Secrets Manager instance in which the Secret will be added. | `string` | n/a | yes | | [existing\_sm\_instance\_region](#input\_existing\_sm\_instance\_region) | Region which the Secret Manager is deployed. | `string` | n/a | yes | -| [secrets](#input\_secrets) | Secret Manager secrets configurations. |
list(object({
secret_group_name = string
secret_group_description = optional(string)
existing_secret_group = optional(bool, false)
create_access_group = optional(bool, false)
access_group_name = optional(string)
access_group_roles = optional(list(string))
access_group_tags = optional(list(string))
secrets = optional(list(object({
secret_name = string
secret_description = optional(string)
secret_type = optional(string)
imported_cert_certificate = optional(string)
imported_cert_private_key = optional(string)
imported_cert_intermediate = optional(string)
secret_username = optional(string)
secret_labels = optional(list(string), [])
secret_payload_password = optional(string, "")
secret_auto_rotation = optional(bool, true)
secret_auto_rotation_unit = optional(string, "day")
secret_auto_rotation_interval = optional(number, 89)
service_credentials_ttl = optional(string, "7776000") # 90 days
service_credentials_source_service_crn = optional(string)
service_credentials_source_service_role_crn = optional(string)
service_credentials_source_service_hmac = optional(bool, false)
})), [])
}))
| `[]` | no | +| [secrets](#input\_secrets) | Secret Manager secrets configurations. |
list(object({
secret_group_name = string
secret_group_description = optional(string)
existing_secret_group = optional(bool, false)
create_access_group = optional(bool, false)
access_group_name = optional(string)
access_group_roles = optional(list(string))
access_group_tags = optional(list(string))
secrets = optional(list(object({
secret_name = string
secret_description = optional(string)
secret_type = optional(string)
imported_cert_certificate = optional(string)
imported_cert_private_key = optional(string)
imported_cert_intermediate = optional(string)
secret_username = optional(string)
secret_labels = optional(list(string), [])
secret_payload_password = optional(string, "")
secret_auto_rotation = optional(bool, true)
secret_auto_rotation_unit = optional(string, "day")
secret_auto_rotation_interval = optional(number, 89)
service_credentials_ttl = optional(string, "7776000") # 90 days
service_credentials_source_service_crn = optional(string)
service_credentials_source_service_role_crn = optional(string)
service_credentials_source_service_hmac = optional(bool, false)
custom_credentials_configurations = optional(string)
custom_credentials_parameters = optional(bool, false)
job_parameters = optional(object({
integer_values = optional(map(number))
string_values = optional(map(string))
boolean_values = optional(map(bool))
}), {})
})), [])
}))
| `[]` | no | ### Outputs diff --git a/modules/secrets/main.tf b/modules/secrets/main.tf index 3855ef84..55a55381 100644 --- a/modules/secrets/main.tf +++ b/modules/secrets/main.tf @@ -60,7 +60,7 @@ locals { module "secrets" { for_each = { for obj in local.secrets : obj.secret_name => obj } source = "terraform-ibm-modules/secrets-manager-secret/ibm" - version = "1.8.0" + version = "1.9.0" region = var.existing_sm_instance_region secrets_manager_guid = var.existing_sm_instance_guid secret_group_id = each.value.secret_group_id @@ -81,4 +81,7 @@ module "secrets" { service_credentials_source_service_crn = each.value.service_credentials_source_service_crn service_credentials_source_service_role_crn = each.value.service_credentials_source_service_role_crn service_credentials_source_service_hmac = each.value.service_credentials_source_service_hmac + custom_credentials_configurations = each.value.custom_credentials_configurations + custom_credentials_parameters = each.value.custom_credentials_parameters + job_parameters = each.value.job_parameters } diff --git a/modules/secrets/variables.tf b/modules/secrets/variables.tf index 9097de9d..634b52a3 100644 --- a/modules/secrets/variables.tf +++ b/modules/secrets/variables.tf @@ -44,6 +44,13 @@ variable "secrets" { service_credentials_source_service_crn = optional(string) service_credentials_source_service_role_crn = optional(string) service_credentials_source_service_hmac = optional(bool, false) + custom_credentials_configurations = optional(string) + custom_credentials_parameters = optional(bool, false) + job_parameters = optional(object({ + integer_values = optional(map(number)) + string_values = optional(map(string)) + boolean_values = optional(map(bool)) + }), {}) })), []) })) description = "Secret Manager secrets configurations." diff --git a/tests/other_test.go b/tests/other_test.go index 20d80c72..7aba4f5f 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -35,6 +35,13 @@ func TestRunCompleteExample(t *testing.T) { options := setupOptions(t, "secrets-mgr", false) + // need to ignore because of a provider issue: https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4719 + options.IgnoreUpdates = testhelper.Exemptions{ + List: []string{ + "module.code_engine_job.ibm_code_engine_job.ce_job", + }, + } + output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") diff --git a/tests/pr_test.go b/tests/pr_test.go index bc62b5a5..03016786 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -446,7 +446,7 @@ func TestSecretsManagerDefaultConfiguration(t *testing.T) { // TestDependencyPermutations runs dependency permutations for the Secrets Manager and all its dependencies func TestDependencyPermutations(t *testing.T) { - t.Skip() // skipping permutations test untill we do a refactor + t.Skip() // skipping permutations test until we do a refactor options := testaddons.TestAddonsOptionsDefault(&testaddons.TestAddonOptions{ Testing: t, diff --git a/variables.tf b/variables.tf index 04956472..182a854e 100644 --- a/variables.tf +++ b/variables.tf @@ -190,6 +190,13 @@ variable "secrets" { service_credentials_ttl = optional(string, "7776000") # 90 days service_credentials_source_service_crn = optional(string) service_credentials_source_service_role_crn = optional(string) + custom_credentials_configurations = optional(string) + custom_credentials_parameters = optional(bool, false) + job_parameters = optional(object({ + integer_values = optional(map(number)) + string_values = optional(map(string)) + boolean_values = optional(map(bool)) + }), {}) }))) })) description = "Secret Manager secrets configurations."