diff --git a/README.md b/README.md index 8aed7643..2c26c385 100644 --- a/README.md +++ b/README.md @@ -90,20 +90,20 @@ You need the following permissions to run this module. | [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 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 |
+| [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of context-based restrictions 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
tags = optional(list(object({
name = string
value = string
})))
operations = optional(list(object({
api_types = list(object({
api_type_id = 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 |
-| [instance\_name](#input\_instance\_name) | The name to give the RabbitMQ instance | `string` | n/a | yes |
| [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 |
+| [name](#input\_name) | The name to give the RabbitMQ instance | `string` | n/a | yes |
| [plan](#input\_plan) | The name of the service plan that you choose for your RabbitMQ instance | `string` | `"standard"` | no |
| [rabbitmq\_version](#input\_rabbitmq\_version) | The version of RabbitMQ to deploy. If no value passed, the current ICD preferred version is used. | `string` | `null` | no |
| [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 |
+| [service\_endpoints](#input\_service\_endpoints) | Specify whether you want to enable the public, private, or both service endpoints. Supported values are 'public', 'private', or 'public-and-private'. | `string` | `"private"` | 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 |
diff --git a/examples/backup-restore/main.tf b/examples/backup-restore/main.tf
index 89daf104..9dc3f366 100644
--- a/examples/backup-restore/main.tf
+++ b/examples/backup-restore/main.tf
@@ -18,7 +18,7 @@ data "ibm_database_backups" "backup_database" {
module "restored_rabbitmq_db" {
source = "../.."
resource_group_id = module.resource_group.resource_group_id
- instance_name = "${var.prefix}-rabbitmq-restored"
+ name = "${var.prefix}-rabbitmq-restored"
region = var.region
rabbitmq_version = var.rabbitmq_version
access_tags = var.access_tags
diff --git a/examples/basic/main.tf b/examples/basic/main.tf
index fe7c4ffc..81e45ac9 100644
--- a/examples/basic/main.tf
+++ b/examples/basic/main.tf
@@ -14,12 +14,13 @@ module "resource_group" {
# RabbitMQ
##############################################################################
-module "icd_rabbitmq" {
+module "database" {
source = "../.."
resource_group_id = module.resource_group.resource_group_id
- instance_name = "${var.prefix}-rabbitmq"
+ name = "${var.prefix}-rabbitmq"
region = var.region
tags = var.resource_tags
access_tags = var.access_tags
rabbitmq_version = var.rabbitmq_version
+ service_endpoints = var.service_endpoints
}
diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf
index 628d1f13..bdf38107 100644
--- a/examples/basic/outputs.tf
+++ b/examples/basic/outputs.tf
@@ -2,32 +2,37 @@
# Outputs
##############################################################################
output "id" {
- description = "rabbitmq instance id"
- value = module.icd_rabbitmq.id
+ description = "RabbitMQ instance id"
+ value = module.database.id
+}
+
+output "rabbitmq_crn" {
+ description = "RabbitMQ CRN"
+ value = module.database.crn
}
output "version" {
- description = "rabbitmq instance version"
- value = module.icd_rabbitmq.version
+ description = "RabbitMQ instance version"
+ value = module.database.version
}
output "adminuser" {
description = "Database admin user name"
- value = module.icd_rabbitmq.adminuser
+ value = module.database.adminuser
}
output "hostname" {
description = "Database hostname"
- value = module.icd_rabbitmq.hostname
+ value = module.database.hostname
}
output "port" {
description = "Database port"
- value = module.icd_rabbitmq.port
+ value = module.database.port
}
output "certificate_base64" {
description = "Database connection certificate"
- value = module.icd_rabbitmq.certificate_base64
+ value = module.database.certificate_base64
sensitive = true
}
diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf
index 7f831954..e8d3aa6b 100644
--- a/examples/basic/variables.tf
+++ b/examples/basic/variables.tf
@@ -39,3 +39,14 @@ variable "access_tags" {
description = "A list of access tags to apply to the rabbitmq instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details"
default = []
}
+
+variable "service_endpoints" {
+ type = string
+ description = "Specify whether you want to enable the public, private, or both service endpoints. Supported values are 'public', 'private', or 'public-and-private'."
+ default = "public"
+
+ validation {
+ condition = can(regex("public|public-and-private|private", var.service_endpoints))
+ error_message = "Valid values for service_endpoints are 'public', 'public-and-private', and 'private'"
+ }
+}
diff --git a/examples/complete/main.tf b/examples/complete/main.tf
index a43c0ee6..450799a5 100644
--- a/examples/complete/main.tf
+++ b/examples/complete/main.tf
@@ -92,7 +92,7 @@ module "cbr_zone" {
module "icd_rabbitmq" {
source = "../../"
resource_group_id = module.resource_group.resource_group_id
- instance_name = "${var.prefix}-rabbitmq"
+ name = "${var.prefix}-rabbitmq"
region = var.region
admin_pass = var.admin_pass
users = var.users
diff --git a/examples/fscloud/main.tf b/examples/fscloud/main.tf
index d55a0e31..271417a6 100644
--- a/examples/fscloud/main.tf
+++ b/examples/fscloud/main.tf
@@ -56,7 +56,7 @@ module "cbr_zone" {
module "rabbitmq_database" {
source = "../../modules/fscloud"
resource_group_id = module.resource_group.resource_group_id
- instance_name = "${var.prefix}-rabbitmq"
+ name = "${var.prefix}-rabbitmq"
region = var.region
rabbitmq_version = var.rabbitmq_version
kms_key_crn = var.kms_key_crn
diff --git a/ibm_catalog.json b/ibm_catalog.json
index ca71b6b6..f13c2efa 100644
--- a/ibm_catalog.json
+++ b/ibm_catalog.json
@@ -317,6 +317,21 @@
},
{
"key": "use_default_backup_encryption_key"
+ },
+ {
+ "key": "admin_pass_secrets_manager_secret_group"
+ },
+ {
+ "key": "admin_pass_secrets_manager_secret_name"
+ },
+ {
+ "key": "use_existing_admin_pass_secrets_manager_secret_group"
+ },
+ {
+ "key": "cbr_rules"
+ },
+ {
+ "key": "existing_rabbitmq_instance_crn"
}
]
}
diff --git a/main.tf b/main.tf
index 39562563..204112ac 100644
--- a/main.tf
+++ b/main.tf
@@ -1,3 +1,10 @@
+########################################################################################################################
+# Input 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 {
# Validation (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400)
# tflint-ignore: terraform_unused_declarations
@@ -8,9 +15,13 @@ locals {
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_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.
+########################################################################################################################
+# Locals
+########################################################################################################################
+locals {
# 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)
@@ -20,6 +31,7 @@ locals {
# Determine if host_flavor is used
host_flavor_set = var.member_host_flavor != null ? true : false
+
}
########################################################################################################################
@@ -165,14 +177,14 @@ resource "time_sleep" "wait_for_backup_kms_authorization_policy" {
########################################################################################################################
resource "ibm_database" "rabbitmq_database" {
- depends_on = [time_sleep.wait_for_authorization_policy]
- name = var.instance_name
+ depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy]
+ name = var.name
plan = var.plan
location = var.region
service = "messages-for-rabbitmq"
version = var.rabbitmq_version
resource_group_id = var.resource_group_id
- service_endpoints = var.endpoints
+ service_endpoints = var.service_endpoints
tags = var.tags
key_protect_key = var.kms_key_crn
backup_encryption_key_crn = local.backup_encryption_key_crn
@@ -373,7 +385,7 @@ locals {
}
data "ibm_database_connection" "database_connection" {
- endpoint_type = var.endpoints == "public-and-private" ? "public" : var.endpoints
+ endpoint_type = var.service_endpoints == "public-and-private" ? "public" : var.service_endpoints
deployment_id = ibm_database.rabbitmq_database.id
user_id = ibm_database.rabbitmq_database.adminuser
user_type = "database"
diff --git a/modules/fscloud/README.md b/modules/fscloud/README.md
index e3111dc2..8dd05ef0 100644
--- a/modules/fscloud/README.md
+++ b/modules/fscloud/README.md
@@ -38,11 +38,11 @@ No resources.
| [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 |
-| [instance\_name](#input\_instance\_name) | The name of the RabbitMQ instance | `string` | n/a | yes |
| [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 |
+| [name](#input\_name) | The name of the RabbitMQ instance | `string` | n/a | yes |
| [rabbitmq\_version](#input\_rabbitmq\_version) | The version of RabbitMQ to deploy. If no value passed, the current ICD preferred version is used. | `string` | `null` | no |
| [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 |
diff --git a/modules/fscloud/main.tf b/modules/fscloud/main.tf
index 921cebd1..3cae4fcf 100644
--- a/modules/fscloud/main.tf
+++ b/modules/fscloud/main.tf
@@ -1,10 +1,10 @@
module "rabbitmq_database" {
source = "../../"
resource_group_id = var.resource_group_id
- instance_name = var.instance_name
+ name = var.name
region = var.region
skip_iam_authorization_policy = var.skip_iam_authorization_policy
- endpoints = "private"
+ service_endpoints = "private"
rabbitmq_version = var.rabbitmq_version
tags = var.tags
access_tags = var.access_tags
diff --git a/modules/fscloud/variables.tf b/modules/fscloud/variables.tf
index 67e54b32..94045766 100644
--- a/modules/fscloud/variables.tf
+++ b/modules/fscloud/variables.tf
@@ -7,7 +7,7 @@ variable "resource_group_id" {
description = "The resource group ID where the RabbitMQ instance will be created."
}
-variable "instance_name" {
+variable "name" {
type = string
description = "The name of the RabbitMQ instance"
}
diff --git a/solutions/standard/DA-cbr_rules.md b/solutions/standard/DA-cbr_rules.md
new file mode 100644
index 00000000..6ddb077b
--- /dev/null
+++ b/solutions/standard/DA-cbr_rules.md
@@ -0,0 +1,64 @@
+# Configuring complex inputs for ICD Elastic Search in IBM Cloud projects
+
+Several optional input variables in the IBM Cloud [ICD Messages for Rabbitmq Deployable Architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You specify these inputs when you configure deployable architecture.
+
+* Context-Based Restrictions Rules (`cbr_rules`)
+
+
+## Rules For Context-Based Restrictions
+
+The `cbr_rules` input variable allows you to provide a rule for the target service to enforce access restrictions for the service based on the context of access requests. Contexts are criteria that include the network location of access requests, the endpoint type from where the request is sent, etc.
+
+- Variable name: `cbr_rules`.
+- Type: A list of objects. Allows only one object representing a rule for the target service
+- Default value: An empty list (`[]`).
+
+### Options for cbr_rules
+
+ - `description` (required): The description of the rule to create.
+ - `account_id` (required): The IBM Cloud Account ID
+ - `rule_contexts` (required): (List) The contexts the rule applies to
+ - `attributes` (optional): (List) Individual context attributes
+ - `name` (required): The attribute name.
+ - `value`(required): The attribute value.
+
+ - `enforcement_mode` (required): The rule enforcement mode can have the following values:
+ - `enabled` - The restrictions are enforced and reported. This is the default.
+ - `disabled` - The restrictions are disabled. Nothing is enforced or reported.
+ - `report` - The restrictions are evaluated and reported, but not enforced.
+ - `tags` (required): The tag can have the following values:
+ - `name` - The name of the tag.
+ - `value` - The value of the tag.
+ - `operations` (optional): The operations this rule applies to
+ - `api_types`(required): (List) The API types this rule applies to.
+ - `api_type_id`(required):The API type ID
+
+
+### Example Rule For Context-Based Restrictions Configuration
+
+```hcl
+cbr_rules = [
+ {
+ "description" : "SCC Instance can be accessed from xyz"
+ "account_id" : "defc0df06b644a9cabc6e44f55b3880s."
+ "rule_contexts" : [{
+ "attributes" : [
+ {
+ "name" : "endpointType",
+ "value" : "private"
+ },
+ {
+ "name" : "networkZoneId"
+ "value" : "93a51a1debe2674193217209601dde6f" # pragma: allowlist secret
+ }
+ ]
+ }]
+ "enforcement_mode" : "enabled"
+ "operations" : [{
+ "api_types" : [{
+ "api_type_id" : "crn:v1:bluemix:public:context-based-restrictions::::api-type:"
+ }]
+ }]
+ }
+]
+```
diff --git a/solutions/standard/main.tf b/solutions/standard/main.tf
index f8bf2133..228c3c03 100644
--- a/solutions/standard/main.tf
+++ b/solutions/standard/main.tf
@@ -18,9 +18,9 @@ module "resource_group" {
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
+ validate_kms_1 = var.existing_rabbitmq_instance_crn != null ? true : 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
+ validate_kms_2 = var.existing_rabbitmq_instance_crn != null ? true : !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
}
#######################################################################################################################
@@ -28,7 +28,7 @@ locals {
#######################################################################################################################
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
+ create_new_kms_key = var.existing_rabbitmq_instance_crn == null && !var.use_ibm_owned_encryption_key && var.existing_kms_key_crn == null ? true : false # no need to create any KMS resources if passing an existing key, or using IBM owned keys
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
}
@@ -99,23 +99,24 @@ 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
+ create_cross_account_kms_auth_policy = var.existing_rabbitmq_instance_crn == null && !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.existing_rabbitmq_instance_crn == null && !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
+ kms_account_id = var.existing_rabbitmq_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : module.kms_instance_crn_parser[0].account_id
+ kms_service = var.existing_rabbitmq_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : module.kms_instance_crn_parser[0].service_name
+ kms_instance_guid = var.existing_rabbitmq_instance_crn != null || 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.existing_rabbitmq_instance_crn != null || 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.existing_rabbitmq_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].resource : module.kms[0].keys[format("%s.%s", local.rabbitmq_key_ring_name, local.rabbitmq_key_name)].key_id
+ kms_region = var.existing_rabbitmq_instance_crn != null || var.use_ibm_owned_encryption_key ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].region : module.kms_instance_crn_parser[0].region
# If creating KMS cross account policy for backups, parse backup key details from passed in key CRN
backup_kms_account_id = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].account_id : local.kms_account_id
backup_kms_service = local.create_cross_account_backup_kms_auth_policy ? module.kms_backup_key_crn_parser[0].service_name : local.kms_service
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
+
+ backup_kms_key_crn = var.existing_rabbitmq_instance_crn != null || 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
}
@@ -233,19 +234,65 @@ locals {
# if - replace first char with J
# elseif _ replace first char with K
# else use asis
- admin_pass = var.admin_pass == null ? (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) : var.admin_pass
+ 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
#######################################################################################################################
+# Look up existing instance details if user passes one
+module "rabbitmq_instance_crn_parser" {
+ count = var.existing_rabbitmq_instance_crn != null ? 1 : 0
+ source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+ version = "1.1.0"
+ crn = var.existing_rabbitmq_instance_crn
+}
+
+# Existing instance local vars
+locals {
+ existing_rabbitmq_guid = var.existing_rabbitmq_instance_crn != null ? module.rabbitmq_instance_crn_parser[0].service_instance : null
+ existing_rabbitmq_region = var.existing_rabbitmq_instance_crn != null ? module.rabbitmq_instance_crn_parser[0].region : null
+
+ # Validate the region input matches region detected in existing instance CRN (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400)
+ # tflint-ignore: terraform_unused_declarations
+ validate_existing_instance_region = var.existing_rabbitmq_instance_crn != null && var.region != local.existing_rabbitmq_region ? tobool("The region detected in the 'existing_rabbitmq_instance_crn' value must match the value of the 'region' input variable when passing an existing instance.") : true
+}
+
+# Do a data lookup on the resource GUID to get more info that is needed for the 'ibm_database' data lookup below
+data "ibm_resource_instance" "existing_instance_resource" {
+ count = var.existing_rabbitmq_instance_crn != null ? 1 : 0
+ identifier = local.existing_rabbitmq_guid
+}
+
+# Lookup details of existing instance
+data "ibm_database" "existing_db_instance" {
+ count = var.existing_rabbitmq_instance_crn != null ? 1 : 0
+ name = data.ibm_resource_instance.existing_instance_resource[0].name
+ resource_group_id = data.ibm_resource_instance.existing_instance_resource[0].resource_group_id
+ location = var.region
+ service = "messages-for-rabbitmq"
+}
+
+# Lookup existing instance connection details
+data "ibm_database_connection" "existing_connection" {
+ count = var.existing_rabbitmq_instance_crn != null ? 1 : 0
+ endpoint_type = "private"
+ deployment_id = data.ibm_database.existing_db_instance[0].id
+ user_id = data.ibm_database.existing_db_instance[0].adminuser
+ user_type = "database"
+}
+
# Create new instance
module "rabbitmq" {
+ count = var.existing_rabbitmq_instance_crn != null ? 0 : 1
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
+ 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
@@ -266,19 +313,49 @@ module "rabbitmq" {
auto_scaling = var.auto_scaling
service_credential_names = var.service_credential_names
backup_crn = var.backup_crn
+ cbr_rules = var.cbr_rules
}
locals {
+ rabbitmq_guid = var.existing_rabbitmq_instance_crn != null ? data.ibm_database.existing_db_instance[0].guid : module.rabbitmq[0].guid
+ rabbitmq_id = var.existing_rabbitmq_instance_crn != null ? data.ibm_database.existing_db_instance[0].id : module.rabbitmq[0].id
+ rabbitmq_version = var.existing_rabbitmq_instance_crn != null ? data.ibm_database.existing_db_instance[0].version : module.rabbitmq[0].version
+ rabbitmq_crn = var.existing_rabbitmq_instance_crn != null ? var.existing_rabbitmq_instance_crn : module.rabbitmq[0].crn
+ rabbitmq_hostname = var.existing_rabbitmq_instance_crn != null ? data.ibm_database_connection.existing_connection[0].https[0].hosts[0].hostname : module.rabbitmq[0].hostname
+ rabbitmq_port = var.existing_rabbitmq_instance_crn != null ? data.ibm_database_connection.existing_connection[0].https[0].hosts[0].port : module.rabbitmq[0].port
+}
+
+#######################################################################################################################
+# Secrets management
+#######################################################################################################################
+
+locals {
+ ## Variable validation (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400)
+ # 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
+ # tflint-ignore: terraform_unused_declarations
+ validate_sm_sg = var.existing_secrets_manager_instance_crn != null && var.admin_pass_secrets_manager_secret_group == null ? tobool("`admin_pass_secrets_manager_secret_group` is required when `existing_secrets_manager_instance_crn` is set.") : false
+ # tflint-ignore: terraform_unused_declarations
+ validate_sm_sn = var.existing_secrets_manager_instance_crn != null && var.admin_pass_secrets_manager_secret_name == null ? tobool("`admin_pass_secrets_manager_secret_name` is required when `existing_secrets_manager_instance_crn` is set.") : false
+
create_sm_auth_policy = var.skip_rabbitmq_sm_auth_policy || var.existing_secrets_manager_instance_crn == null ? 0 : 1
}
+# Parse the Secrets Manager CRN
+module "sm_instance_crn_parser" {
+ count = var.existing_secrets_manager_instance_crn != null ? 1 : 0
+ source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+ version = "1.1.0"
+ crn = var.existing_secrets_manager_instance_crn
+}
+
# create a service authorization between Secrets Manager and the target service (Databases for 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
+ target_resource_instance_id = local.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"
}
@@ -306,19 +383,30 @@ locals {
service_credentials_ttl = secret.service_credentials_ttl
service_credential_secret_description = secret.service_credential_secret_description
service_credentials_source_service_role_crn = secret.service_credentials_source_service_role_crn
- service_credentials_source_service_crn = module.rabbitmq.crn
+ service_credentials_source_service_crn = module.rabbitmq[0].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
+ # Build the structure of the arbitrary credential type secret for admin password
+ admin_pass_secret = [{
+ secret_group_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secrets_manager_secret_group != null ? "${var.prefix}-${var.admin_pass_secrets_manager_secret_group}" : var.admin_pass_secrets_manager_secret_group
+ existing_secret_group = var.use_existing_admin_pass_secrets_manager_secret_group
+ secrets = [{
+ secret_name = (var.prefix != null && var.prefix != "") && var.admin_pass_secrets_manager_secret_name != null ? "${var.prefix}-${var.admin_pass_secrets_manager_secret_name}" : var.admin_pass_secrets_manager_secret_name
+ secret_type = "arbitrary"
+ secret_payload_password = local.admin_pass
+ }
+ ]
+ }]
- # 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
+ # Concatinate into 1 secrets object
+ secrets = concat(local.service_credential_secrets, local.admin_pass_secret)
+ # Parse Secrets Manager details from the CRN
+ existing_secrets_manager_instance_guid = var.existing_secrets_manager_instance_crn != null ? module.sm_instance_crn_parser[0].service_instance : null
+ existing_secrets_manager_instance_region = var.existing_secrets_manager_instance_crn != null ? module.sm_instance_crn_parser[0].region : null
}
module "secrets_manager_service_credentials" {
@@ -329,5 +417,5 @@ module "secrets_manager_service_credentials" {
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
+ secrets = local.secrets
}
diff --git a/solutions/standard/moved.tf b/solutions/standard/moved.tf
new file mode 100644
index 00000000..2c783c3c
--- /dev/null
+++ b/solutions/standard/moved.tf
@@ -0,0 +1,4 @@
+moved {
+ from = module.rabbitmq
+ to = module.rabbitmq[0]
+}
diff --git a/solutions/standard/outputs.tf b/solutions/standard/outputs.tf
index 8c8f2ca3..0e70171f 100644
--- a/solutions/standard/outputs.tf
+++ b/solutions/standard/outputs.tf
@@ -4,63 +4,53 @@
output "id" {
description = "RabbitMQ instance id"
- value = module.rabbitmq.id
+ value = local.rabbitmq_id
}
output "version" {
description = "RabbitMQ instance version"
- value = module.rabbitmq.version
+ value = local.rabbitmq_version
}
output "guid" {
description = "RabbitMQ instance guid"
- value = module.rabbitmq.guid
+ value = local.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
+ value = local.rabbitmq_crn
}
output "service_credentials_json" {
description = "Service credentials json map"
- value = module.rabbitmq.service_credentials_json
+ value = var.existing_rabbitmq_instance_crn != null ? null : module.rabbitmq[0].service_credentials_json
sensitive = true
}
output "service_credentials_object" {
description = "Service credentials object"
- value = module.rabbitmq.service_credentials_object
+ value = var.existing_rabbitmq_instance_crn != null ? null : module.rabbitmq[0].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
+ value = local.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
+ value = local.rabbitmq_port
}
output "secrets_manager_secrets" {
description = "Service credential secrets"
value = length(local.service_credential_secrets) > 0 ? module.secrets_manager_service_credentials[0].secrets : null
}
+
+output "admin_pass" {
+ description = "RabbitMQ administrator password"
+ value = local.admin_pass
+ sensitive = true
+}
diff --git a/solutions/standard/variables.tf b/solutions/standard/variables.tf
index 3c56472d..777fbb8b 100644
--- a/solutions/standard/variables.tf
+++ b/solutions/standard/variables.tf
@@ -42,6 +42,12 @@ variable "rabbitmq_version" {
default = null
}
+variable "existing_rabbitmq_instance_crn" {
+ type = string
+ default = null
+ description = "The CRN of an existing Messages for RabbitMQ instance. If no value is specified, a new instance is created."
+}
+
##############################################################################
# ICD hosting model properties
##############################################################################
@@ -294,3 +300,49 @@ variable "skip_rabbitmq_sm_auth_policy" {
description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Databases for RabbitMQ. If set to false, the Secrets Manager instance passed by the user is granted the Key Manager access to the RabbitMQ instance created by the Deployable Architecture. Set to `true` to use an existing policy. The value of this is ignored if any value for 'existing_secrets_manager_instance_crn' is not passed."
default = false
}
+
+variable "admin_pass_secrets_manager_secret_group" {
+ type = string
+ description = "The name of a new or existing secrets manager secret group for admin password. To use existing secret group, `use_existing_admin_pass_secrets_manager_secret_group` must be set to `true`. If a prefix input variable is specified, the prefix is added to the name in the `