diff --git a/README.md b/README.md index d2085faf..8aed7643 100644 --- a/README.md +++ b/README.md @@ -64,17 +64,21 @@ You need the following permissions to run this module. | Name | Source | Version | |------|--------|---------| +| [backup\_key\_crn\_parser](#module\_backup\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | | [cbr\_rule](#module\_cbr\_rule) | git::https://github.com/terraform-ibm-modules/terraform-ibm-cbr//modules/cbr-rule-module | v1.29.0 | +| [kms\_key\_crn\_parser](#module\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | ### Resources | Name | Type | |------|------| | [ibm_database.rabbitmq_database](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database) | resource | +| [ibm_iam_authorization_policy.backup_kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | | [ibm_iam_authorization_policy.kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | | [ibm_resource_key.service_credentials](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_key) | resource | | [ibm_resource_tag.rabbitmq_tag](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_tag) | resource | | [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_backup_kms_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [ibm_database_connection.database_connection](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/database_connection) | data source | ### Inputs @@ -85,15 +89,13 @@ You need the following permissions to run this module. | [admin\_pass](#input\_admin\_pass) | The password for the database administrator. If the admin password is null then the admin user ID cannot be accessed. More users can be specified in a user block. | `string` | `null` | no | | [auto\_scaling](#input\_auto\_scaling) | Optional rules to allow the database to increase resources in response to usage. Only a single autoscaling block is allowed. Make sure you understand the effects of autoscaling, especially for production environments. See https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-autoscaling in the IBM Cloud Docs. |
object({
disk = object({
capacity_enabled = optional(bool, false)
free_space_less_than_percent = optional(number, 10)
io_above_percent = optional(number, 90)
io_enabled = optional(bool, false)
io_over_period = optional(string, "15m")
rate_increase_percent = optional(number, 10)
rate_limit_mb_per_member = optional(number, 3670016)
rate_period_seconds = optional(number, 900)
rate_units = optional(string, "mb")
})
memory = object({
io_above_percent = optional(number, 90)
io_enabled = optional(bool, false)
io_over_period = optional(string, "15m")
rate_increase_percent = optional(number, 10)
rate_limit_mb_per_member = optional(number, 114688)
rate_period_seconds = optional(number, 900)
rate_units = optional(string, "mb")
})
}) | `null` | no |
| [backup\_crn](#input\_backup\_crn) | The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:<…>:backup:. If omitted, the database is provisioned empty. | `string` | `null` | no |
-| [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a KMS (Key Protect or Hyper Protect Crypto Services) key to use for encrypting the disk that holds deployment backups. Only used if var.kms\_encryption\_enabled is set to true. There are limitation per region on the type of KMS service (Key Protect or Hyper Protect Crypto Services) and region for those services. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok and https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups | `string` | `null` | no |
+| [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false and `use_same_kms_key_for_backups` is false. If no value is passed, and `use_same_kms_key_for_backups` is true, the value of `kms_key_crn` is used. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no |
| [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of CBR rules to create | list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
})) | `[]` | no |
| [cpu\_count](#input\_cpu\_count) | Allocated dedicated CPU per member. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `0` | no |
| [disk\_mb](#input\_disk\_mb) | Allocated disk per member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `1024` | no |
| [endpoints](#input\_endpoints) | Endpoints available to the database instance (public, private, public-and-private) | `string` | `"private"` | no |
-| [existing\_kms\_instance\_guid](#input\_existing\_kms\_instance\_guid) | The GUID of the Hyper Protect or Key Protect instance in which the key specified in var.kms\_key\_crn and var.backup\_encryption\_key\_crn is coming from. Only required if var.kms\_encryption\_enabled is 'true', var.skip\_iam\_authorization\_policy is 'false', and passing a value for var.kms\_key\_crn and/or var.backup\_encryption\_key\_crn. | `string` | `null` | no |
| [instance\_name](#input\_instance\_name) | The name to give the RabbitMQ instance | `string` | n/a | yes |
-| [kms\_encryption\_enabled](#input\_kms\_encryption\_enabled) | Set this to true to control the encryption keys used to encrypt the data that you store in IBM Cloud® Databases. If set to false, the data is encrypted by using randomly generated keys. For more info on Key Protect integration, see https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect. For more info on HPCS integration, see https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs | `bool` | `false` | no |
-| [kms\_key\_crn](#input\_kms\_key\_crn) | The root key CRN of a Key Management Services like Key Protect or Hyper Protect Crypto Services (HPCS) that you want to use for disk encryption. Only used if var.kms\_encryption\_enabled is set to true. | `string` | `null` | no |
+| [kms\_key\_crn](#input\_kms\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the `use_same_kms_key_for_backups` and `backup_encryption_key_crn` inputs. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no |
| [member\_host\_flavor](#input\_member\_host\_flavor) | Allocated host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor). | `string` | `null` | no |
| [members](#input\_members) | Allocated number of members. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `3` | no |
| [memory\_mb](#input\_memory\_mb) | Allocated memory per-member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `8192` | no |
@@ -102,9 +104,11 @@ You need the following permissions to run this module.
| [region](#input\_region) | The region where you want to deploy your instance. | `string` | `"us-south"` | no |
| [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the RabbitMQ instance will be created. | `string` | n/a | yes |
| [service\_credential\_names](#input\_service\_credential\_names) | Map of name, role for service credentials that you want to create for the database | `map(string)` | `{}` | no |
-| [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of an IAM authorization policy that permits all RabbitMQ instances in the given resource group to read the encryption key from the Hyper Protect or Key Protect instance passed in var.existing\_kms\_instance\_guid. If set to 'false', a value must be passed for var.existing\_kms\_instance\_guid. No policy is created if var.kms\_encryption\_enabled is set to 'false'. | `bool` | `false` | no |
+| [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of IAM authorization policies that permits all Databases for RabbitMQ instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key that was provided in the `kms_key_crn` and `backup_encryption_key_crn` inputs. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `use_ibm_owned_encryption_key` is true. | `bool` | `false` | no |
| [tags](#input\_tags) | Optional list of tags to be added to the RabbitMQ instance. | `list(any)` | `[]` | no |
-| [use\_default\_backup\_encryption\_key](#input\_use\_default\_backup\_encryption\_key) | Set to true to use default ICD randomly generated keys. | `bool` | `false` | no |
+| [use\_default\_backup\_encryption\_key](#input\_use\_default\_backup\_encryption\_key) | When `use_ibm_owned_encryption_key` is set to false, backups will be encrypted with either the key specified in `kms_key_crn`, or in `backup_encryption_key_crn` if a value is passed. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `use_ibm_owned_encryption_key` to true to use the default encryption for both backups and deployment data. | `bool` | `false` | no |
+| [use\_ibm\_owned\_encryption\_key](#input\_use\_ibm\_owned\_encryption\_key) | IBM Cloud Databases will secure your deployment's data at rest automatically with an encryption key that IBM hold. Alternatively, you may select your own Key Management System instance and encryption key (Key Protect or Hyper Protect Crypto Services) by setting this to false. If setting to false, a value must be passed for the `kms_key_crn` input. | `bool` | `true` | no |
+| [use\_same\_kms\_key\_for\_backups](#input\_use\_same\_kms\_key\_for\_backups) | Set this to false if you wan't to use a different key that you own to encrypt backups. When set to false, a value is required for the `backup_encryption_key_crn` input. Alternatiely set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Applies only if `use_ibm_owned_encryption_key` is false. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `bool` | `true` | no |
| [users](#input\_users) | A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters. Be warned that in most case using IAM service credentials (via the var.service\_credential\_names) is sufficient to control access to the RabbitMQ instance. This blocks creates native RabbitMQ database users, more info on that can be found here https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-user-management | list(object({
name = string
password = string # pragma: allowlist secret
type = optional(string)
role = optional(string)
})) | `[]` | no |
### Outputs
diff --git a/cra-config.yaml b/cra-config.yaml
index cb738ed9..fbae9039 100644
--- a/cra-config.yaml
+++ b/cra-config.yaml
@@ -1,9 +1,12 @@
# 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: "examples/fscloud"
+ - CRA_TARGET: "solutions/standard"
CRA_IGNORE_RULES_FILE: "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:
- TF_VAR_existing_kms_instance_guid: "e6dce284-e80f-46e1-a3c1-830f7adff7a9"
- TF_VAR_kms_key_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9:key:76170fae-4e0c-48c3-8ebe-326059ebb533"
+ TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::"
+ TF_VAR_existing_kms_key_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9:key:1368d2eb-3ed0-4a8b-b09c-2155895f01ea"
+ TF_VAR_use_existing_resource_group: true
+ TF_VAR_resource_group_name: "geretain-test-redis"
+ TF_VAR_provider_visibility: "public"
diff --git a/examples/complete/main.tf b/examples/complete/main.tf
index 57e6272a..0a68fefb 100644
--- a/examples/complete/main.tf
+++ b/examples/complete/main.tf
@@ -14,6 +14,11 @@ module "resource_group" {
# Key Protect All Inclusive
##############################################################################
+locals {
+ data_key_name = "${var.prefix}-rabbitmq"
+ backups_key_name = "${var.prefix}-rabbitmq-backups"
+}
+
module "key_protect_all_inclusive" {
source = "terraform-ibm-modules/kms-all-inclusive/ibm"
version = "4.19.2"
@@ -28,7 +33,11 @@ module "key_protect_all_inclusive" {
key_ring_name = "icd"
keys = [
{
- key_name = "${var.prefix}-rabbitmq"
+ key_name = local.data_key_name
+ force_delete = true
+ },
+ {
+ key_name = local.backups_key_name
force_delete = true
}
]
@@ -81,21 +90,28 @@ module "cbr_zone" {
##############################################################################
module "icd_rabbitmq" {
- source = "../../"
- resource_group_id = module.resource_group.resource_group_id
- instance_name = "${var.prefix}-rabbitmq"
- region = var.region
- kms_encryption_enabled = true
- existing_kms_instance_guid = module.key_protect_all_inclusive.kms_guid
- service_credential_names = var.service_credential_names
- admin_pass = var.admin_pass
- users = var.users
- rabbitmq_version = var.rabbitmq_version
- kms_key_crn = module.key_protect_all_inclusive.keys["icd.${var.prefix}-rabbitmq"].crn
- tags = var.resource_tags
- access_tags = var.access_tags
- auto_scaling = var.auto_scaling
- member_host_flavor = "multitenant"
+ source = "../../"
+ resource_group_id = module.resource_group.resource_group_id
+ instance_name = "${var.prefix}-rabbitmq"
+ region = var.region
+ admin_pass = var.admin_pass
+ users = var.users
+ rabbitmq_version = var.rabbitmq_version
+ tags = var.resource_tags
+ access_tags = var.access_tags
+ auto_scaling = var.auto_scaling
+ # Example of how to use different KMS keys for data and backups
+ use_ibm_owned_encryption_key = false
+ use_same_kms_key_for_backups = false
+ kms_key_crn = module.key_protect_all_inclusive.keys["icd.${local.data_key_name}"].crn
+ backup_encryption_key_crn = module.key_protect_all_inclusive.keys["icd.${local.data_key_name}"].crn
+ service_credential_names = {
+ "rabbitmq_admin" : "Administrator",
+ "rabbitmq_operator" : "Operator",
+ "rabbitmq_viewer" : "Viewer",
+ "rabbitmq_editor" : "Editor",
+ }
+ member_host_flavor = "multitenant"
cbr_rules = [
{
description = "${var.prefix}-rabbitmq access only from vpc"
diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf
index c4fc1e1e..2ec2b078 100644
--- a/examples/complete/variables.tf
+++ b/examples/complete/variables.tf
@@ -29,17 +29,6 @@ variable "users" {
description = "A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters."
}
-variable "service_credential_names" {
- description = "Map of name, role for service credentials that you want to create for the database"
- type = map(string)
- default = {
- "rabbit_admin" : "Administrator",
- "rabbit_operator" : "Operator",
- "rabbit_viewer" : "Viewer",
- "rabbit_editor" : "Editor",
- }
-}
-
variable "prefix" {
type = string
description = "Prefix to append to all resources created by this example"
diff --git a/examples/fscloud/main.tf b/examples/fscloud/main.tf
index ef21f49d..d55a0e31 100644
--- a/examples/fscloud/main.tf
+++ b/examples/fscloud/main.tf
@@ -54,20 +54,32 @@ module "cbr_zone" {
##############################################################################
module "rabbitmq_database" {
- source = "../../modules/fscloud"
- resource_group_id = module.resource_group.resource_group_id
- instance_name = "${var.prefix}-rabbitmq"
- region = var.region
- rabbitmq_version = var.rabbitmq_version
- kms_key_crn = var.kms_key_crn
- existing_kms_instance_guid = var.existing_kms_instance_guid
- service_credential_names = var.service_credential_names
- tags = var.tags
- access_tags = var.access_tags
- auto_scaling = var.auto_scaling
- member_host_flavor = "b3c.4x16.encrypted"
- backup_encryption_key_crn = var.backup_encryption_key_crn
- backup_crn = var.backup_crn
+ source = "../../modules/fscloud"
+ resource_group_id = module.resource_group.resource_group_id
+ instance_name = "${var.prefix}-rabbitmq"
+ region = var.region
+ rabbitmq_version = var.rabbitmq_version
+ kms_key_crn = var.kms_key_crn
+ backup_encryption_key_crn = var.backup_encryption_key_crn
+ backup_crn = var.backup_crn
+ service_credential_names = {
+ "rabbitmq_admin" : "Administrator",
+ "rabbitmq_operator" : "Operator",
+ "rabbitmq_viewer" : "Viewer",
+ "rabbitmq_editor" : "Editor",
+ }
+ auto_scaling = {
+ disk = {
+ capacity_enabled : true,
+ io_enabled : true
+ }
+ memory = {
+ io_enabled : true,
+ }
+ }
+ member_host_flavor = "b3c.4x16.encrypted"
+ tags = var.tags
+ access_tags = var.access_tags
cbr_rules = [
{
description = "${var.prefix}-rabbitmq access only from vpc"
diff --git a/examples/fscloud/variables.tf b/examples/fscloud/variables.tf
index 94c0c540..0e8a753a 100644
--- a/examples/fscloud/variables.tf
+++ b/examples/fscloud/variables.tf
@@ -28,11 +28,6 @@ variable "resource_group" {
default = null
}
-variable "existing_kms_instance_guid" {
- description = "The GUID of the Hyper Protect Crypto services in which the key specified in var.kms_key_crn is coming from"
- type = string
-}
-
variable "kms_key_crn" {
type = string
description = "The root key CRN of a Hyper Protect Crypto Services (HPCS) that you want to use for disk encryption. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs&interface=ui for more information on integrating HPCS with RabbitMQ instance."
@@ -44,33 +39,6 @@ variable "rabbitmq_version" {
default = null
}
-variable "auto_scaling" {
- type = object({
- disk = object({
- capacity_enabled = optional(bool, false)
- free_space_less_than_percent = optional(number, 10)
- io_above_percent = optional(number, 90)
- io_enabled = optional(bool, false)
- io_over_period = optional(string, "15m")
- rate_increase_percent = optional(number, 10)
- rate_limit_mb_per_member = optional(number, 3670016)
- rate_period_seconds = optional(number, 900)
- rate_units = optional(string, "mb")
- })
- memory = object({
- io_above_percent = optional(number, 90)
- io_enabled = optional(bool, false)
- io_over_period = optional(string, "15m")
- rate_increase_percent = optional(number, 10)
- rate_limit_mb_per_member = optional(number, 114688)
- rate_period_seconds = optional(number, 900)
- rate_units = optional(string, "mb")
- })
- })
- description = "Optional rules to allow the database to increase resources in response to usage. Only a single autoscaling block is allowed. Make sure you understand the effects of autoscaling, especially for production environments. See https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-autoscaling in the IBM Cloud Docs."
- default = null
-}
-
variable "backup_crn" {
type = string
description = "The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:<…>:backup:. If omitted, the database is provisioned empty."
@@ -84,12 +52,6 @@ variable "backup_encryption_key_crn" {
# Validation happens in the root module
}
-variable "service_credential_names" {
- description = "Map of name, role for service credentials that you want to create for the database"
- type = map(string)
- default = {}
-}
-
variable "tags" {
type = list(any)
description = "Optional list of tags to be added to the RabbitMQ instance."
diff --git a/main.tf b/main.tf
index 0da2eced..100f7149 100644
--- a/main.tf
+++ b/main.tf
@@ -1,50 +1,164 @@
locals {
# Validation (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400)
# tflint-ignore: terraform_unused_declarations
- validate_kms_values = !var.kms_encryption_enabled && (var.kms_key_crn != null || var.backup_encryption_key_crn != null) ? tobool("When passing values for var.backup_encryption_key_crn or var.kms_key_crn, you must set var.kms_encryption_enabled to true. Otherwise unset them to use default encryption") : true
+ validate_kms_values = var.use_ibm_owned_encryption_key && (var.kms_key_crn != null || var.backup_encryption_key_crn != null) ? tobool("When passing values for 'kms_key_crn' or 'backup_encryption_key_crn', you must set 'use_ibm_owned_encryption_key' to false. Otherwise unset them to use default encryption.") : true
# tflint-ignore: terraform_unused_declarations
- validate_kms_vars = var.kms_encryption_enabled && var.kms_key_crn == null && var.backup_encryption_key_crn == null ? tobool("When setting var.kms_encryption_enabled to true, a value must be passed for var.kms_key_crn and/or var.backup_encryption_key_crn") : true
+ validate_kms_vars = !var.use_ibm_owned_encryption_key && var.kms_key_crn == null ? tobool("When setting 'use_ibm_owned_encryption_key' to false, a value must be passed for 'kms_key_crn'.") : true
# tflint-ignore: terraform_unused_declarations
- validate_auth_policy = var.kms_encryption_enabled && var.skip_iam_authorization_policy == false && var.existing_kms_instance_guid == null ? tobool("When var.skip_iam_authorization_policy is set to false, and var.kms_encryption_enabled to true, a value must be passed for var.existing_kms_instance_guid in order to create the auth policy.") : true
+ validate_backup_key = !var.use_ibm_owned_encryption_key && var.backup_encryption_key_crn != null && (var.use_default_backup_encryption_key || var.use_same_kms_key_for_backups) ? tobool("When passing a value for 'backup_encryption_key_crn' you cannot set 'use_default_backup_encryption_key' to true or 'use_ibm_owned_encryption_key' to false.") : true
# tflint-ignore: terraform_unused_declarations
- validate_backup_key = var.backup_encryption_key_crn != null && var.use_default_backup_encryption_key == true ? tobool("When passing a value for 'backup_encryption_key_crn' you cannot set 'use_default_backup_encryption_key' to 'true'") : true
+ validate_backup_key_2 = !var.use_ibm_owned_encryption_key && var.backup_encryption_key_crn == null && !var.use_same_kms_key_for_backups ? tobool("When 'use_same_kms_key_for_backups' is set to false, a value needs to be passed for 'backup_encryption_key_crn'.") : true
# If no value passed for 'backup_encryption_key_crn' use the value of 'kms_key_crn' and perform validation of 'kms_key_crn' to check if region is supported by backup encryption key.
- # For more info, see https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok and https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups"
- backup_encryption_key_crn = var.use_default_backup_encryption_key == true ? null : (var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : var.kms_key_crn)
+
+ # If 'use_ibm_owned_encryption_key' is true or 'use_default_backup_encryption_key' is true, default to null.
+ # If no value is passed for 'backup_encryption_key_crn', then default to use 'kms_key_crn'.
+ backup_encryption_key_crn = var.use_ibm_owned_encryption_key || var.use_default_backup_encryption_key ? null : (var.backup_encryption_key_crn != null ? var.backup_encryption_key_crn : var.kms_key_crn)
# Determine if auto scaling is enabled
auto_scaling_enabled = var.auto_scaling == null ? [] : [1]
# Determine if host_flavor is used
host_flavor_set = var.member_host_flavor != null ? true : false
+}
+
+########################################################################################################################
+# Parse info from KMS key CRNs
+########################################################################################################################
+
+module "kms_key_crn_parser" {
+ count = var.use_ibm_owned_encryption_key ? 0 : 1
+ source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+ version = "1.1.0"
+ crn = var.kms_key_crn
+}
- # Determine what KMS service is being used for database encryption
- kms_service = var.kms_key_crn != null ? (
- can(regex(".*kms.*", var.kms_key_crn)) ? "kms" : (
- can(regex(".*hs-crypto.*", var.kms_key_crn)) ? "hs-crypto" : "unrecognized key type"
- )
- ) : "no key crn"
+module "backup_key_crn_parser" {
+ count = var.use_ibm_owned_encryption_key ? 0 : 1
+ source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+ version = "1.1.0"
+ crn = local.backup_encryption_key_crn
+}
+
+# Put parsed values into locals
+locals {
+ kms_service = !var.use_ibm_owned_encryption_key ? module.kms_key_crn_parser[0].service_name : null
+ kms_account_id = !var.use_ibm_owned_encryption_key ? module.kms_key_crn_parser[0].account_id : null
+ kms_key_id = !var.use_ibm_owned_encryption_key ? module.kms_key_crn_parser[0].resource : null
+ kms_key_instance_guid = !var.use_ibm_owned_encryption_key ? module.kms_key_crn_parser[0].service_instance : null
+ backup_kms_service = !var.use_ibm_owned_encryption_key ? module.backup_key_crn_parser[0].service_name : null
+ backup_kms_account_id = !var.use_ibm_owned_encryption_key ? module.backup_key_crn_parser[0].account_id : null
+ backup_kms_key_id = !var.use_ibm_owned_encryption_key ? module.backup_key_crn_parser[0].resource : null
+ backup_kms_key_instance_guid = !var.use_ibm_owned_encryption_key ? module.backup_key_crn_parser[0].service_instance : null
+}
+
+########################################################################################################################
+# KMS IAM Authorization Policies
+########################################################################################################################
+
+locals {
+ # only create auth policy if 'use_ibm_owned_encryption_key' is false, and 'skip_iam_authorization_policy' is false
+ create_kms_auth_policy = !var.use_ibm_owned_encryption_key && !var.skip_iam_authorization_policy ? 1 : 0
+ # only create backup auth policy if 'use_ibm_owned_encryption_key' is false, 'skip_iam_authorization_policy' is false and 'use_same_kms_key_for_backups' is false
+ create_backup_kms_auth_policy = !var.use_ibm_owned_encryption_key && !var.skip_iam_authorization_policy && !var.use_same_kms_key_for_backups ? 1 : 0
}
# Create IAM Access policy to allow RabbitMQ to access KMS for the encryption key
resource "ibm_iam_authorization_policy" "kms_policy" {
- count = var.kms_encryption_enabled == false || var.skip_iam_authorization_policy ? 0 : 1
- source_service_name = "messages-for-rabbitmq"
- source_resource_group_id = var.resource_group_id
- target_service_name = local.kms_service
- target_resource_instance_id = var.existing_kms_instance_guid
- roles = ["Reader"]
- description = "Allow all RabbitMQ instances in the resource group ${var.resource_group_id} to read from the ${local.kms_service} instance GUID ${var.existing_kms_instance_guid}"
+ count = local.create_kms_auth_policy
+ source_service_name = "messages-for-rabbitmq"
+ source_resource_group_id = var.resource_group_id
+ roles = ["Reader"]
+ description = "Allow all RabbitMQ instances in the resource group ${var.resource_group_id} to read the ${local.kms_service} key ${local.kms_key_id} from the instance GUID ${local.kms_key_instance_guid}"
+ resource_attributes {
+ name = "serviceName"
+ operator = "stringEquals"
+ value = local.kms_service
+ }
+ resource_attributes {
+ name = "accountId"
+ operator = "stringEquals"
+ value = local.kms_account_id
+ }
+ resource_attributes {
+ name = "serviceInstance"
+ operator = "stringEquals"
+ value = local.kms_key_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_kms_auth_policy
depends_on = [ibm_iam_authorization_policy.kms_policy]
create_duration = "30s"
}
+resource "ibm_iam_authorization_policy" "backup_kms_policy" {
+ count = local.create_backup_kms_auth_policy
+ source_service_name = "messages-for-rabbitmq"
+ source_resource_group_id = var.resource_group_id
+ roles = ["Reader"]
+ description = "Allow all RabbitMQ instances in the Resource Group ${var.resource_group_id} to read the ${local.backup_kms_service} key ${local.backup_kms_key_id} from the instance GUID ${local.backup_kms_key_instance_guid}"
+ resource_attributes {
+ name = "serviceName"
+ operator = "stringEquals"
+ value = local.backup_kms_service
+ }
+ resource_attributes {
+ name = "accountId"
+ operator = "stringEquals"
+ value = local.backup_kms_account_id
+ }
+ resource_attributes {
+ name = "serviceInstance"
+ operator = "stringEquals"
+ value = local.backup_kms_key_instance_guid
+ }
+ resource_attributes {
+ name = "resourceType"
+ operator = "stringEquals"
+ value = "key"
+ }
+ resource_attributes {
+ name = "resource"
+ operator = "stringEquals"
+ value = local.backup_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_backup_kms_authorization_policy" {
+ count = local.create_backup_kms_auth_policy
+ depends_on = [ibm_iam_authorization_policy.backup_kms_policy]
+ create_duration = "30s"
+}
+
+########################################################################################################################
+# RabbitMQ instance
+########################################################################################################################
+
resource "ibm_database" "rabbitmq_database" {
depends_on = [time_sleep.wait_for_authorization_policy]
name = var.instance_name
diff --git a/modules/fscloud/README.md b/modules/fscloud/README.md
index 51a28d31..e3111dc2 100644
--- a/modules/fscloud/README.md
+++ b/modules/fscloud/README.md
@@ -34,13 +34,12 @@ No resources.
| [admin\_pass](#input\_admin\_pass) | The password for the database administrator. If the admin password is null then the admin user ID cannot be accessed. More users can be specified in a user block. | `string` | `null` | no |
| [auto\_scaling](#input\_auto\_scaling) | Optional rules to allow the database to increase resources in response to usage. Only a single autoscaling block is allowed. Make sure you understand the effects of autoscaling, especially for production environments. See https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-autoscaling in the IBM Cloud Docs. | object({
disk = object({
capacity_enabled = optional(bool, false)
free_space_less_than_percent = optional(number, 10)
io_above_percent = optional(number, 90)
io_enabled = optional(bool, false)
io_over_period = optional(string, "15m")
rate_increase_percent = optional(number, 10)
rate_limit_mb_per_member = optional(number, 3670016)
rate_period_seconds = optional(number, 900)
rate_units = optional(string, "mb")
})
memory = object({
io_above_percent = optional(number, 90)
io_enabled = optional(bool, false)
io_over_period = optional(string, "15m")
rate_increase_percent = optional(number, 10)
rate_limit_mb_per_member = optional(number, 114688)
rate_period_seconds = optional(number, 900)
rate_units = optional(string, "mb")
})
}) | `null` | no |
| [backup\_crn](#input\_backup\_crn) | The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:<…>:backup:. If omitted, the database is provisioned empty. | `string` | `null` | no |
-| [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a Hyper Protect Crypto Services use for encrypting the disk that holds deployment backups. Only used if var.kms\_encryption\_enabled is set to true. There are limitation per region on the Hyper Protect Crypto Services and region for those services. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups | `string` | `null` | no |
+| [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false and `use_same_kms_key_for_backups` is false. If no value is passed, and `use_same_kms_key_for_backups` is true, the value of `kms_key_crn` is used. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no |
| [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of CBR rules to create | list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
})) | `[]` | no |
| [cpu\_count](#input\_cpu\_count) | Allocated dedicated CPU per member. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `0` | no |
| [disk\_mb](#input\_disk\_mb) | Allocated disk per member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `1024` | no |
-| [existing\_kms\_instance\_guid](#input\_existing\_kms\_instance\_guid) | The GUID of the Hyper Protect Crypto Services instance. | `string` | n/a | yes |
| [instance\_name](#input\_instance\_name) | The name of the RabbitMQ instance | `string` | n/a | yes |
-| [kms\_key\_crn](#input\_kms\_key\_crn) | The root key CRN of a Key Management Services like Key Protect or Hyper Protect Crypto Services (HPCS) that you want to use for disk encryption. Only used if var.kms\_encryption\_enabled is set to true. | `string` | `null` | no |
+| [kms\_key\_crn](#input\_kms\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the `use_same_kms_key_for_backups` and `backup_encryption_key_crn` inputs. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no |
| [member\_host\_flavor](#input\_member\_host\_flavor) | Allocated host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor). | `string` | `null` | no |
| [members](#input\_members) | Allocated number of members. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `3` | no |
| [memory\_mb](#input\_memory\_mb) | Allocated memory per member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling). | `number` | `8192` | no |
@@ -48,8 +47,11 @@ No resources.
| [region](#input\_region) | The region where you want to deploy your instance. | `string` | `"us-south"` | no |
| [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the RabbitMQ instance will be created. | `string` | n/a | yes |
| [service\_credential\_names](#input\_service\_credential\_names) | Map of name, role for service credentials that you want to create for the database | `map(string)` | `{}` | no |
-| [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of an IAM authorization policy that permits all RabbitMQ instances in the resource group to read the encryption key from the Hyper Protect Crypto Services instance. The HPCS instance is passed in through the var.existing\_kms\_instance\_guid variable. | `bool` | `false` | no |
+| [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of IAM authorization policies that permits all Databases for RabbitMQ instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key that was provided in the `kms_key_crn` and `backup_encryption_key_crn` inputs. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `use_ibm_owned_encryption_key` is true. | `bool` | `false` | no |
| [tags](#input\_tags) | Optional list of tags to be added to the RabbitMQ instance. | `list(any)` | `[]` | no |
+| [use\_default\_backup\_encryption\_key](#input\_use\_default\_backup\_encryption\_key) | When `use_ibm_owned_encryption_key` is set to false, backups will be encrypted with either the key specified in `kms_key_crn`, or in `backup_encryption_key_crn` if a value is passed. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `use_ibm_owned_encryption_key` to true to use the default encryption for both backups and deployment data. | `bool` | `false` | no |
+| [use\_ibm\_owned\_encryption\_key](#input\_use\_ibm\_owned\_encryption\_key) | Set to true to use the default IBM Cloud® Databases randomly generated keys for disk and backups encryption. To control the encryption keys, use the `kms_key_crn` and `backup_encryption_key_crn` inputs. | `string` | `false` | no |
+| [use\_same\_kms\_key\_for\_backups](#input\_use\_same\_kms\_key\_for\_backups) | Set this to false if you wan't to use a different key that you own to encrypt backups. When set to false, a value is required for the `backup_encryption_key_crn` input. Alternatiely set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Applies only if `use_ibm_owned_encryption_key` is false. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `bool` | `true` | no |
| [users](#input\_users) | A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters. Be warned that in most case using IAM service credentials (via the var.service\_credential\_names) is sufficient to control access to the RabbitMQ instance. This blocks creates native RabbitMQ database users, more info on that can be found here https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-user-management | list(object({
name = string
password = string # pragma: allowlist secret
type = optional(string)
role = optional(string)
})) | `[]` | no |
### Outputs
diff --git a/modules/fscloud/main.tf b/modules/fscloud/main.tf
index c5c05536..921cebd1 100644
--- a/modules/fscloud/main.tf
+++ b/modules/fscloud/main.tf
@@ -1,26 +1,27 @@
module "rabbitmq_database" {
- source = "../../"
- resource_group_id = var.resource_group_id
- instance_name = var.instance_name
- region = var.region
- skip_iam_authorization_policy = var.skip_iam_authorization_policy
- endpoints = "private"
- rabbitmq_version = var.rabbitmq_version
- tags = var.tags
- access_tags = var.access_tags
- kms_encryption_enabled = true
- existing_kms_instance_guid = var.existing_kms_instance_guid
- service_credential_names = var.service_credential_names
- backup_encryption_key_crn = var.backup_encryption_key_crn
- kms_key_crn = var.kms_key_crn
- admin_pass = var.admin_pass
- members = var.members
- users = var.users
- memory_mb = var.memory_mb
- disk_mb = var.disk_mb
- cpu_count = var.cpu_count
- member_host_flavor = var.member_host_flavor
- auto_scaling = var.auto_scaling
- cbr_rules = var.cbr_rules
- backup_crn = var.backup_crn
+ source = "../../"
+ resource_group_id = var.resource_group_id
+ instance_name = var.instance_name
+ region = var.region
+ skip_iam_authorization_policy = var.skip_iam_authorization_policy
+ endpoints = "private"
+ rabbitmq_version = var.rabbitmq_version
+ tags = var.tags
+ access_tags = var.access_tags
+ use_ibm_owned_encryption_key = var.use_ibm_owned_encryption_key
+ use_same_kms_key_for_backups = var.use_same_kms_key_for_backups
+ use_default_backup_encryption_key = var.use_default_backup_encryption_key
+ kms_key_crn = var.kms_key_crn
+ backup_crn = var.backup_crn
+ backup_encryption_key_crn = var.backup_encryption_key_crn
+ service_credential_names = var.service_credential_names
+ admin_pass = var.admin_pass
+ members = var.members
+ users = var.users
+ memory_mb = var.memory_mb
+ disk_mb = var.disk_mb
+ cpu_count = var.cpu_count
+ member_host_flavor = var.member_host_flavor
+ auto_scaling = var.auto_scaling
+ cbr_rules = var.cbr_rules
}
diff --git a/modules/fscloud/variables.tf b/modules/fscloud/variables.tf
index 10408e18..67e54b32 100644
--- a/modules/fscloud/variables.tf
+++ b/modules/fscloud/variables.tf
@@ -130,27 +130,56 @@ variable "auto_scaling" {
# Encryption
##############################################################
+variable "use_ibm_owned_encryption_key" {
+ type = string
+ description = "Set to true to use the default IBM Cloud® Databases randomly generated keys for disk and backups encryption. To control the encryption keys, use the `kms_key_crn` and `backup_encryption_key_crn` inputs."
+ default = false
+}
+
variable "kms_key_crn" {
type = string
- description = "The root key CRN of a Key Management Services like Key Protect or Hyper Protect Crypto Services (HPCS) that you want to use for disk encryption. Only used if var.kms_encryption_enabled is set to true."
+ description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the `use_same_kms_key_for_backups` and `backup_encryption_key_crn` inputs. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)."
default = null
+ validation {
+ condition = anytrue([
+ var.kms_key_crn == null,
+ can(regex(".*kms.*", var.kms_key_crn)),
+ can(regex(".*hs-crypto.*", var.kms_key_crn)),
+ ])
+ error_message = "Value must be the KMS key CRN from a Key Protect or Hyper Protect Crypto Services instance."
+ }
+}
+
+variable "use_same_kms_key_for_backups" {
+ type = bool
+ description = "Set this to false if you wan't to use a different key that you own to encrypt backups. When set to false, a value is required for the `backup_encryption_key_crn` input. Alternatiely set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Applies only if `use_ibm_owned_encryption_key` is false. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)."
+ default = true
}
variable "backup_encryption_key_crn" {
type = string
- description = "The CRN of a Hyper Protect Crypto Services use for encrypting the disk that holds deployment backups. Only used if var.kms_encryption_enabled is set to true. There are limitation per region on the Hyper Protect Crypto Services and region for those services. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups"
+ description = "The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false and `use_same_kms_key_for_backups` is false. If no value is passed, and `use_same_kms_key_for_backups` is true, the value of `kms_key_crn` is used. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups)."
default = null
+ validation {
+ condition = anytrue([
+ var.backup_encryption_key_crn == null,
+ can(regex(".*kms.*", var.backup_encryption_key_crn)),
+ can(regex(".*hs-crypto.*", var.backup_encryption_key_crn)),
+ ])
+ error_message = "Value must be the KMS key CRN from a Key Protect or Hyper Protect Crypto Services instance in one of the supported backup regions."
+ }
}
-variable "skip_iam_authorization_policy" {
+variable "use_default_backup_encryption_key" {
type = bool
- description = "Set to true to skip the creation of an IAM authorization policy that permits all RabbitMQ instances in the resource group to read the encryption key from the Hyper Protect Crypto Services instance. The HPCS instance is passed in through the var.existing_kms_instance_guid variable."
+ description = "When `use_ibm_owned_encryption_key` is set to false, backups will be encrypted with either the key specified in `kms_key_crn`, or in `backup_encryption_key_crn` if a value is passed. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `use_ibm_owned_encryption_key` to true to use the default encryption for both backups and deployment data."
default = false
}
-variable "existing_kms_instance_guid" {
- type = string
- description = "The GUID of the Hyper Protect Crypto Services instance."
+variable "skip_iam_authorization_policy" {
+ type = bool
+ description = "Set to true to skip the creation of IAM authorization policies that permits all Databases for RabbitMQ instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key that was provided in the `kms_key_crn` and `backup_encryption_key_crn` inputs. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `use_ibm_owned_encryption_key` is true."
+ default = false
}
##############################################################
diff --git a/reference-architecture/deployable-architecture-rabbitmq.svg b/reference-architecture/deployable-architecture-rabbitmq.svg
new file mode 100644
index 00000000..1071c607
--- /dev/null
+++ b/reference-architecture/deployable-architecture-rabbitmq.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/solutions/standard/DA-types.md b/solutions/standard/DA-types.md
new file mode 100644
index 00000000..1b73b9e2
--- /dev/null
+++ b/solutions/standard/DA-types.md
@@ -0,0 +1,203 @@
+# Configuring complex inputs in Databases for RabbitMQ
+
+Several optional input variables in the IBM Cloud [Databases for RabbitMQ deployable architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You specify these inputs when you configure deployable architecture.
+
+- [Service credentials](#svc-credential-name) (`service_credential_names`)
+- [Service credential secrets](#service-credential-secrets) (`service_credential_secrets`)
+- [Users](#users) (`users`)
+- [Autoscaling](#autoscaling) (`auto_scaling`)
+
+## Service credentials
+
+You can specify a set of IAM credentials to connect to the database with the `service_credential_names` input variable. Include a credential name and IAM service role for each key-value pair. Each role provides a specific level of access to the database. For more information, see [Adding and viewing credentials](https://cloud.ibm.com/docs/account?topic=account-service_credentials&interface=ui). If you want to add service credentials to secret manager and to allow secret manager to manage it, you should use `service_credential_secrets` , see [Service credential secrets](#service-credential-secrets)
+
+- Variable name: `service_credential_names`.
+- Type: A map. The key is the name of the service credential. The value is the role that is assigned to that credential.
+- Default value: An empty map (`{}`).
+
+### Options for service_credential_names
+
+- Key (required): The name of the service credential.
+- Value (required): The IAM service role that is assigned to the credential. The following values are valid for service credential roles: "Administrator", "Operator", "Viewer" and "Editor". For more information, see [IBM Cloud IAM roles](https://cloud.ibm.com/docs/account?topic=account-userroles).
+
+### Example service credential
+
+```hcl
+ {
+ "rabbitmq_admin" : "Administrator",
+ "rabbitmq_reader" : "Operator",
+ "rabbitmq_viewer" : "Viewer",
+ "rabbitmq_editor" : "Editor"
+ }
+```
+
+## Service credential secrets
+
+When you add an IBM Database for RabbitMQ deployable architecture from the IBM Cloud catalog to IBM Cloud Project , you can configure service credentials. In edit mode for the projects configuration, from the configure panel click the optional tab.
+
+To enter a custom value, use the edit action to open the "Edit Array" panel. Add the service credential secrets configurations to the array here.
+
+In the configuration, specify the secret group name, whether it already exists or will be created and include all the necessary service credential secrets that need to be created within that secret group.
+
+ [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/sm_service_credentials_secret) about service credential secrets.
+
+- Variable name: `service_credential_secrets`.
+- Type: A list of objects that represent a service credential secret groups and secrets
+- Default value: An empty list (`[]`)
+
+### Options for service_credential_secrets
+
+- `secret_group_name` (required): A unique human-readable name that identifies this service credential secret group.
+- `secret_group_description` (optional, default = `null`): A human-readable description for this secret group.
+- `existing_secret_group`: (optional, default = `false`): Set to true, if secret group name provided in the variable `secret_group_name` already exists.
+- `service_credentials`: (optional, default = `[]`): A list of object that represents a service credential secret.
+
+#### Options for service_credentials
+
+- `secret_name`: (required): A unique human-readable name of the secret to create.
+- `service_credentials_source_service_role`: (required): The role to give the service credential in the Databases for RabbitMQ service. Acceptable values are `Writer`, `Reader`, `Manager`, and `None`
+- `secret_labels`: (optional, default = `[]`): Labels of the secret to create. Up to 30 labels can be created. Labels can be 2 - 30 characters, including spaces. Special characters that are not permitted include the angled brackets (<>), comma (,), colon (:), ampersand (&), and vertical pipe character (|).
+- `secret_auto_rotation`: (optional, default = `true`): Whether to configure automatic rotation of service credential.
+- `secret_auto_rotation_unit`: (optional, default = `day`): Specifies the unit of time for rotation of a secret. Acceptable values are `day` or `month`.
+- `secret_auto_rotation_interval`: (optional, default = `89`): Specifies the rotation interval for the rotation unit.
+- `service_credentials_ttl`: (optional, default = `7776000`): The time-to-live (TTL) to assign to generated service credentials (in seconds).
+- `service_credential_secret_description`: (optional, default = `null`): Description of the secret to create.
+
+The following example includes all the configuration options for four service credentials and two secret groups.
+```hcl
+[
+ {
+ "secret_group_name": "sg-1"
+ "existing_secret_group": true
+ "service_credentials": [ # pragma: allowlist secret
+ {
+ "secret_name": "cred-1"
+ "service_credentials_source_service_role": "Writer"
+ "secret_labels": ["test-writer-1", "test-writer-2"]
+ "secret_auto_rotation": true
+ "secret_auto_rotation_unit": "day"
+ "secret_auto_rotation_interval": 89
+ "service_credentials_ttl": 7776000
+ "service_credential_secret_description": "sample description"
+ },
+ {
+ "secret_name": "cred-2"
+ "service_credentials_source_service_role": "Reader"
+ }
+ ]
+ },
+ {
+ "secret_group_name": "sg-2"
+ "service_credentials": [ # pragma: allowlist secret
+ {
+ "secret_name": "cred-3"
+ "service_credentials_source_service_role": "Editor"
+ },
+ {
+ "secret_name": "cred-4"
+ "service_credentials_source_service_role": "None"
+ }
+ ]
+ }
+]
+```
+
+## Users
+
+If you can't use the IAM-enabled `service_credential_names` input variable for access, you can create users and roles directly in the database. For more information, see [Managing users and roles](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-user-management&interface=ui).
+
+:exclamation: **Important:** The `users` input contains sensitive information (the user's password).
+
+- Variable name: `users`.
+- Type: A list of objects that represent a user
+- Default value: An empty list (`[]`)
+
+### Options for users
+
+ - `name` (required): The username for the user account.
+ - `password` (required): The password for the user account in the range of 10-32 characters.
+ - `type` (required): The user type. The "type" field is required to generate the connection string for the outputs.
+ - `role`: The user role. The role determines the user's access level and permissions.
+
+### Example users
+
+
+```hcl
+[
+ {
+ "name": "es_admin",
+ "password": "securepassword123", # pragma: allowlist secret
+ "type": "database",
+ },
+ {
+ "name": "es_reader",
+ "password": "readpassword123", # pragma: allowlist secret
+ "type": "ops_manager"
+ }
+]
+```
+
+## Autoscaling
+
+The Autoscaling variable sets the rules for how database increase resources in response to usage. Make sure you understand the effects of autoscaling, especially for production environments. For more information, see [Autoscaling](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-autoscaling&interface=ui#autoscaling-consider).
+
+- Variable name: `auto_scaling`
+- Type: An object with `disk` and `memory` configurations.
+
+### Disk options for auto_scaling
+
+Disk autoscaling specifies thresholds when scaling can occur based on disk usage, disk I/O utilization, or both.
+
+The disk object in the `auto_scaling` input contains the following options. All options are optional.
+
+- `capacity_enabled`: Whether disk capacity autoscaling is enabled (default: `false`).
+- `free_space_less_than_percent`: The percentage of free disk space that triggers autoscaling (default: `10`).
+- `io_above_percent`: The percentage of I/O (input/output) disk usage that triggers autoscaling (default: `90`).
+- `io_enabled`: Indicates whether IO-based autoscaling is enabled (default: `false`).
+- `io_over_period`: How long I/O usage is evaluated for autoscaling (default: `"15m"` (15 minutes)).
+- `rate_increase_percent`: The percentage increase in disk capacity when autoscaling is triggered (default: `10`).
+- `rate_limit_mb_per_member`: The limit in megabytes for the rate of disk increase per member (default: `3670016`).
+- `rate_period_seconds`: How long (in seconds) the rate limit is applied for disk (default: `900` (15 minutes)).
+- `rate_units`: The units to use for the rate increase (default: `"mb"` (megabytes)).
+
+
+### Memory options for auto_scaling
+
+The memory object within auto_scaling contains the following options. All options are optional.
+
+- `io_above_percent`: The percentage of I/O memory usage that triggers autoscaling (default: `90`).
+- `io_enabled`: Whether IO-based autoscaling for memory is enabled (default: `false`).
+- `io_over_period`: How long I/O usage is evaluated for memory autoscaling (default: `"15m"` (15 minutes)).
+- `rate_increase_percent`: The percentage increase in memory capacity that triggers autoscaling (default: `10`).
+- `rate_limit_mb_per_member`: The limit in megabytes for the rate of memory increase per member (default: `114688`).
+- `rate_period_seconds`: How long (in seconds) the rate limit is applied for memory (default: `900` (15 minutes)).
+- `rate_units`: The memory size units to use for the rate increase (default: `"mb"` (megabytes)).
+
+### Example autoscaling
+
+The following example shows values for both disk and memory for the `auto_scaling` input.
+
+```hcl
+{
+ "disk": {
+ "capacity_enabled": true,
+ "free_space_less_than_percent": 15,
+ "io_above_percent": 85,
+ "io_enabled": true,
+ "io_over_period": "15m",
+ "rate_increase_percent": 15,
+ "rate_limit_mb_per_member": 3670016,
+ "rate_period_seconds": 900,
+ "rate_units": "mb"
+ },
+ "memory": {
+ "io_above_percent": 90,
+ "io_enabled": true,
+ "io_over_period": "15m",
+ "rate_increase_percent": 10,
+ "rate_limit_mb_per_member": 114688,
+ "rate_period_seconds": 900,
+ "rate_units": "mb"
+ }
+}
+```
diff --git a/solutions/standard/README.md b/solutions/standard/README.md
new file mode 100644
index 00000000..04b4a86a
--- /dev/null
+++ b/solutions/standard/README.md
@@ -0,0 +1,13 @@
+ # IBM Cloud Databases for RabbitMQ
+
+This architecture creates an instance of IBM Cloud Databases for RabbitMQ and supports provisioning of the following resources:
+
+- A resource group, if one is not passed in.
+- A KMS root key, if one is not passed in.
+- An IBM Cloud Databases for RabbitMQ instance with KMS encryption.
+- Autoscaling rules for the database instance, if provided.
+- Service credential secrets and store them in secret manager.
+
+
+
+:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and 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/standard/catalogValidationValues.json.template
new file mode 100644
index 00000000..e69e502f
--- /dev/null
+++ b/solutions/standard/catalogValidationValues.json.template
@@ -0,0 +1,8 @@
+{
+ "ibmcloud_api_key": $VALIDATION_APIKEY,
+ "region": "us-south",
+ "tags": $TAGS,
+ "name": $PREFIX,
+ "resource_group_name": $PREFIX,
+ "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN
+}
diff --git a/solutions/standard/main.tf b/solutions/standard/main.tf
new file mode 100644
index 00000000..614d7447
--- /dev/null
+++ b/solutions/standard/main.tf
@@ -0,0 +1,336 @@
+#######################################################################################################################
+# Resource Group
+#######################################################################################################################
+
+module "resource_group" {
+ source = "terraform-ibm-modules/resource-group/ibm"
+ version = "1.1.6"
+ resource_group_name = var.use_existing_resource_group == false ? (var.prefix != null ? "${var.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
+}
+
+#######################################################################################################################
+# KMS related variable validation
+# (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400)
+#
+# TODO: Replace with terraform cross variable validation: https://github.ibm.com/GoldenEye/issues/issues/10836
+#######################################################################################################################
+
+locals {
+ # tflint-ignore: terraform_unused_declarations
+ validate_kms_1 = var.use_ibm_owned_encryption_key && (var.existing_kms_instance_crn != null || var.existing_kms_key_crn != null || var.existing_backup_kms_key_crn != null) ? tobool("When setting values for 'existing_kms_instance_crn', 'existing_kms_key_crn' or 'existing_backup_kms_key_crn', the 'use_ibm_owned_encryption_key' input must be set to false.") : true
+ # tflint-ignore: terraform_unused_declarations
+ validate_kms_2 = !var.use_ibm_owned_encryption_key && (var.existing_kms_instance_crn == null && var.existing_kms_key_crn == null) ? tobool("When 'use_ibm_owned_encryption_key' is false, a value is required for either 'existing_kms_instance_crn' (to create a new key), or 'existing_kms_key_crn' to use an existing key.") : true
+}
+
+#######################################################################################################################
+# KMS encryption key
+#######################################################################################################################
+
+locals {
+ create_new_kms_key = !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
+ rabbitmq_key_name = var.prefix != null ? "${var.prefix}-${var.key_name}" : var.key_name
+ rabbitmq_key_ring_name = var.prefix != null ? "${var.prefix}-${var.key_ring_name}" : var.key_ring_name
+}
+
+module "kms" {
+ providers = {
+ ibm = ibm.kms
+ }
+ count = local.create_new_kms_key ? 1 : 0
+ source = "terraform-ibm-modules/kms-all-inclusive/ibm"
+ version = "4.19.2"
+ 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.rabbitmq_key_ring_name
+ existing_key_ring = false
+ keys = [
+ {
+ key_name = local.rabbitmq_key_name
+ standard_key = false
+ rotation_interval_month = 3
+ dual_auth_delete_enabled = false
+ force_delete = true
+ }
+ ]
+ }
+ ]
+}
+
+########################################################################################################################
+# 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_kms_key_crn != null ? 1 : 0
+ source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+ version = "1.1.0"
+ crn = var.existing_kms_key_crn
+}
+
+module "kms_backup_key_crn_parser" {
+ count = var.existing_backup_kms_key_crn != null ? 1 : 0
+ source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+ version = "1.1.0"
+ crn = var.existing_backup_kms_key_crn
+}
+
+#######################################################################################################################
+# KMS IAM Authorization Policies
+# - only created if user passes a value for 'ibmcloud_kms_api_key' (used when KMS is in different account to RabbitMQ)
+# - if no value passed for 'ibmcloud_kms_api_key', the auth policy is created by the RabbitMQ module
+#######################################################################################################################
+
+# Lookup account ID
+data "ibm_iam_account_settings" "iam_account_settings" {
+}
+
+locals {
+ account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
+ create_cross_account_kms_auth_policy = !var.skip_rabbitmq_kms_auth_policy && var.ibmcloud_kms_api_key != null && !var.use_ibm_owned_encryption_key
+ create_cross_account_backup_kms_auth_policy = !var.skip_rabbitmq_kms_auth_policy && 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.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.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
+ kms_instance_guid = var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_instance : module.kms_instance_crn_parser[0].service_instance
+ kms_key_crn = var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? var.existing_kms_key_crn : module.kms[0].keys[format("%s.%s", local.rabbitmq_key_ring_name, local.rabbitmq_key_name)].crn
+ kms_key_id = 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.rabbitmq_key_ring_name, local.rabbitmq_key_name)].key_id
+ kms_region = 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
+ backup_kms_instance_guid = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].service_instance : local.kms_instance_guid
+ backup_kms_key_id = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].resource : local.kms_key_id
+ backup_kms_key_crn = var.use_ibm_owned_encryption_key ? null : var.existing_backup_kms_key_crn
+ # Always use same key for backups unless user explicially passed a value for 'existing_backup_kms_key_crn'
+ use_same_kms_key_for_backups = var.existing_backup_kms_key_crn == null ? true : false
+}
+
+# Create auth policy (scoped to exact KMS key)
+resource "ibm_iam_authorization_policy" "kms_policy" {
+ count = local.create_cross_account_kms_auth_policy ? 1 : 0
+ provider = ibm.kms
+ source_service_account = local.account_id
+ source_service_name = "messages-for-rabbitmq"
+ source_resource_group_id = module.resource_group.resource_group_id
+ roles = ["Reader"]
+ description = "Allow all RabbitMQ instances in the resource group ${module.resource_group.resource_group_id} in the account ${local.account_id} to read the ${local.kms_service} key ${local.kms_key_id} from the instance GUID ${local.kms_instance_guid}"
+ resource_attributes {
+ name = "serviceName"
+ operator = "stringEquals"
+ value = local.kms_service
+ }
+ 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_kms_auth_policy ? 1 : 0
+ depends_on = [ibm_iam_authorization_policy.kms_policy]
+ create_duration = "30s"
+}
+
+# Create auth policy (scoped to exact KMS key for backups)
+resource "ibm_iam_authorization_policy" "backup_kms_policy" {
+ count = local.create_cross_account_backup_kms_auth_policy ? 1 : 0
+ provider = ibm.kms
+ source_service_account = local.account_id
+ source_service_name = "messages-for-rabbitmq"
+ source_resource_group_id = module.resource_group.resource_group_id
+ roles = ["Reader"]
+ description = "Allow all RabbitMQ instances in the resource group ${module.resource_group.resource_group_id} in the account ${local.account_id} to read the ${local.backup_kms_service} key ${local.backup_kms_key_id} from the instance GUID ${local.backup_kms_instance_guid}"
+ resource_attributes {
+ name = "serviceName"
+ operator = "stringEquals"
+ value = local.backup_kms_service
+ }
+ resource_attributes {
+ name = "accountId"
+ operator = "stringEquals"
+ value = local.backup_kms_account_id
+ }
+ resource_attributes {
+ name = "serviceInstance"
+ operator = "stringEquals"
+ value = local.backup_kms_instance_guid
+ }
+ resource_attributes {
+ name = "resourceType"
+ operator = "stringEquals"
+ value = "key"
+ }
+ resource_attributes {
+ name = "resource"
+ operator = "stringEquals"
+ value = local.backup_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_backup_kms_authorization_policy" {
+ count = local.create_cross_account_backup_kms_auth_policy ? 1 : 0
+ depends_on = [ibm_iam_authorization_policy.backup_kms_policy]
+ create_duration = "30s"
+}
+
+#######################################################################################################################
+# RabbitMQ admin password
+#######################################################################################################################
+
+resource "random_password" "admin_password" {
+ count = var.admin_pass == null ? 1 : 0
+ length = 32
+ special = true
+ override_special = "-_"
+ min_numeric = 1
+}
+
+locals {
+ # _- are invalid first characters
+ # if - replace first char with J
+ # 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
+}
+
+#######################################################################################################################
+# RabbitMQ
+#######################################################################################################################
+
+# Create new instance
+module "rabbitmq" {
+ source = "../../modules/fscloud"
+ depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy]
+ resource_group_id = module.resource_group.resource_group_id
+ instance_name = var.prefix != null ? "${var.prefix}-${var.name}" : var.name
+ region = var.region
+ rabbitmq_version = var.rabbitmq_version
+ skip_iam_authorization_policy = var.skip_rabbitmq_kms_auth_policy
+ use_ibm_owned_encryption_key = var.use_ibm_owned_encryption_key
+ kms_key_crn = local.kms_key_crn
+ backup_encryption_key_crn = local.backup_kms_key_crn
+ use_same_kms_key_for_backups = local.use_same_kms_key_for_backups
+ use_default_backup_encryption_key = var.use_default_backup_encryption_key
+ access_tags = var.access_tags
+ tags = var.tags
+ admin_pass = local.admin_pass
+ users = var.users
+ members = var.members
+ member_host_flavor = var.member_host_flavor
+ memory_mb = var.member_memory_mb
+ disk_mb = var.member_disk_mb
+ cpu_count = var.member_cpu_count
+ auto_scaling = var.auto_scaling
+ service_credential_names = var.service_credential_names
+ backup_crn = var.backup_crn
+}
+
+locals {
+ create_sm_auth_policy = var.skip_rabbitmq_sm_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1
+}
+
+# create a service authorization between Secrets Manager and the target service (Databases for RabbitMQ)
+resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" {
+ count = local.create_sm_auth_policy
+ source_service_name = "secrets-manager"
+ source_resource_instance_id = local.existing_secrets_manager_instance_guid
+ target_service_name = "messages-for-rabbitmq"
+ target_resource_instance_id = module.rabbitmq.guid
+ roles = ["Key Manager"]
+ description = "Allow Secrets Manager with instance id ${local.existing_secrets_manager_instance_guid} to manage key for the messages-for-rabbitmq instance"
+}
+
+# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
+resource "time_sleep" "wait_for_rabbitmq_authorization_policy" {
+ count = local.create_sm_auth_policy
+ depends_on = [ibm_iam_authorization_policy.secrets_manager_key_manager]
+ create_duration = "30s"
+}
+
+locals {
+ service_credential_secrets = [
+ for service_credentials in var.service_credential_secrets : {
+ secret_group_name = service_credentials.secret_group_name
+ secret_group_description = service_credentials.secret_group_description
+ existing_secret_group = service_credentials.existing_secret_group
+ secrets = [
+ for secret in service_credentials.service_credentials : {
+ secret_name = secret.secret_name
+ secret_labels = secret.secret_labels
+ secret_auto_rotation = secret.secret_auto_rotation
+ secret_auto_rotation_unit = secret.secret_auto_rotation_unit
+ secret_auto_rotation_interval = secret.secret_auto_rotation_interval
+ service_credentials_ttl = secret.service_credentials_ttl
+ service_credential_secret_description = secret.service_credential_secret_description
+ service_credentials_source_service_role = secret.service_credentials_source_service_role
+ service_credentials_source_service_crn = module.rabbitmq.crn
+ secret_type = "service_credentials" #checkov:skip=CKV_SECRET_6
+ }
+ ]
+ }
+ ]
+
+ existing_secrets_manager_instance_crn_split = var.existing_secrets_manager_instance_crn != null ? split(":", var.existing_secrets_manager_instance_crn) : null
+ existing_secrets_manager_instance_guid = var.existing_secrets_manager_instance_crn != null ? element(local.existing_secrets_manager_instance_crn_split, length(local.existing_secrets_manager_instance_crn_split) - 3) : null
+ existing_secrets_manager_instance_region = var.existing_secrets_manager_instance_crn != null ? element(local.existing_secrets_manager_instance_crn_split, length(local.existing_secrets_manager_instance_crn_split) - 5) : null
+
+ # tflint-ignore: terraform_unused_declarations
+ validate_sm_crn = length(local.service_credential_secrets) > 0 && var.existing_secrets_manager_instance_crn == null ? tobool("`existing_secrets_manager_instance_crn` is required when adding service credentials to a secrets manager secret.") : false
+}
+
+module "secrets_manager_service_credentials" {
+ count = length(local.service_credential_secrets) > 0 ? 1 : 0
+ depends_on = [time_sleep.wait_for_rabbitmq_authorization_policy]
+ source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets"
+ version = "1.19.10"
+ existing_sm_instance_guid = local.existing_secrets_manager_instance_guid
+ existing_sm_instance_region = local.existing_secrets_manager_instance_region
+ endpoint_type = var.existing_secrets_manager_endpoint_type
+ secrets = local.service_credential_secrets
+}
diff --git a/solutions/standard/outputs.tf b/solutions/standard/outputs.tf
new file mode 100644
index 00000000..8c8f2ca3
--- /dev/null
+++ b/solutions/standard/outputs.tf
@@ -0,0 +1,66 @@
+##############################################################################
+# Outputs
+##############################################################################
+
+output "id" {
+ description = "RabbitMQ instance id"
+ value = module.rabbitmq.id
+}
+
+output "version" {
+ description = "RabbitMQ instance version"
+ value = module.rabbitmq.version
+}
+
+output "guid" {
+ description = "RabbitMQ instance guid"
+ value = module.rabbitmq.guid
+}
+
+output "crn" {
+ description = "RabbitMQ instance crn"
+ value = module.rabbitmq.crn
+}
+
+output "cbr_rule_ids" {
+ description = "CBR rule ids created to restrict RabbitMQ"
+ value = module.rabbitmq.cbr_rule_ids
+}
+
+output "service_credentials_json" {
+ description = "Service credentials json map"
+ value = module.rabbitmq.service_credentials_json
+ sensitive = true
+}
+
+output "service_credentials_object" {
+ description = "Service credentials object"
+ value = module.rabbitmq.service_credentials_object
+ sensitive = true
+}
+
+output "adminuser" {
+ description = "Database admin user name"
+ value = module.rabbitmq.adminuser
+}
+
+output "hostname" {
+ description = "Database connection hostname"
+ value = module.rabbitmq.hostname
+}
+
+output "port" {
+ description = "Database connection port"
+ value = module.rabbitmq.port
+}
+
+output "certificate_base64" {
+ description = "Database connection certificate"
+ value = module.rabbitmq.certificate_base64
+ sensitive = true
+}
+
+output "secrets_manager_secrets" {
+ description = "Service credential secrets"
+ value = length(local.service_credential_secrets) > 0 ? module.secrets_manager_service_credentials[0].secrets : null
+}
diff --git a/solutions/standard/provider.tf b/solutions/standard/provider.tf
new file mode 100644
index 00000000..65c38f7d
--- /dev/null
+++ b/solutions/standard/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/standard/variables.tf
new file mode 100644
index 00000000..37130c0c
--- /dev/null
+++ b/solutions/standard/variables.tf
@@ -0,0 +1,297 @@
+##############################################################################
+# Input Variables
+##############################################################################
+
+variable "ibmcloud_api_key" {
+ type = string
+ description = "The IBM Cloud API key to deploy resources."
+ sensitive = true
+}
+variable "use_existing_resource_group" {
+ type = bool
+ description = "Whether to use an existing resource group."
+ default = false
+}
+
+variable "resource_group_name" {
+ type = string
+ description = "The name of a new or an existing resource group to provision the Databases for RabbitMQ in. If a prefix input variable is specified, the prefix is added to the name in the `