From 36ccc0998af2e77fdb70d5257842b02664d26765 Mon Sep 17 00:00:00 2001 From: mukul-palit Date: Mon, 1 Dec 2025 13:41:50 +0530 Subject: [PATCH 1/4] feat: Monolith example for base-ocp-vpc DA --- README.md | 16 +- common-dev-assets | 2 +- examples/monolith/README.md | 21 + examples/monolith/main.tf | 213 +++ examples/monolith/outputs.tf | 289 +++ examples/monolith/provider.tf | 28 + examples/monolith/variables.tf | 614 ++++++ examples/monolith/version.tf | 21 + modules/monolith/README.md | 265 +++ modules/monolith/main.tf | 708 +++++++ modules/monolith/outputs.tf | 307 +++ modules/monolith/variables.tf | 1684 +++++++++++++++++ modules/monolith/version.tf | 13 + tests/existing-resources-monolith/README.md | 1 + tests/existing-resources-monolith/main.tf | 24 + tests/existing-resources-monolith/outputs.tf | 18 + tests/existing-resources-monolith/provider.tf | 4 + .../existing-resources-monolith/variables.tf | 32 + tests/existing-resources-monolith/version.tf | 9 + tests/other_test.go | 103 + 20 files changed, 4364 insertions(+), 8 deletions(-) create mode 100644 examples/monolith/README.md create mode 100644 examples/monolith/main.tf create mode 100644 examples/monolith/outputs.tf create mode 100644 examples/monolith/provider.tf create mode 100644 examples/monolith/variables.tf create mode 100644 examples/monolith/version.tf create mode 100644 modules/monolith/README.md create mode 100644 modules/monolith/main.tf create mode 100644 modules/monolith/outputs.tf create mode 100644 modules/monolith/variables.tf create mode 100644 modules/monolith/version.tf create mode 100644 tests/existing-resources-monolith/README.md create mode 100644 tests/existing-resources-monolith/main.tf create mode 100644 tests/existing-resources-monolith/outputs.tf create mode 100644 tests/existing-resources-monolith/provider.tf create mode 100644 tests/existing-resources-monolith/variables.tf create mode 100644 tests/existing-resources-monolith/version.tf diff --git a/README.md b/README.md index 66b0d7675..c7ecdf294 100644 --- a/README.md +++ b/README.md @@ -28,15 +28,17 @@ Optionally, the module supports advanced security group management for the worke * [Submodules](./modules) * [fscloud](./modules/fscloud) * [kube-audit](./modules/kube-audit) + * [monolith](./modules/monolith) * [worker-pool](./modules/worker-pool) * [Examples](./examples) - * [2 MZR clusters in same VPC example](./examples/multiple_mzr_clusters) - * [Advanced example (mzr, auto-scale, kms, taints)](./examples/advanced) - * [Attaching custom security groups](./examples/custom_sg) - * [Basic single zone cluster with allowed outbound traffic](./examples/basic) - * [Cluster security group rules example](./examples/add_rules_to_sg) - * [Cross account KMS encryption example](./examples/cross_kms_support) - * [Financial Services compliant example](./examples/fscloud) + *
Cluster security group rules example
Deploy to IBM Cloud button
+ *
Advanced example (mzr, auto-scale, kms, taints)
Deploy to IBM Cloud button
+ *
Basic single zone cluster with allowed outbound traffic
Deploy to IBM Cloud button
+ *
Cross account KMS encryption example
Deploy to IBM Cloud button
+ *
Attaching custom security groups
Deploy to IBM Cloud button
+ *
Financial Services compliant example
Deploy to IBM Cloud button
+ *
IBM Cloud OpenShift DA - Monolith Add-ons Module
Deploy to IBM Cloud button
+ *
2 MZR clusters in same VPC example
Deploy to IBM Cloud button
* [Contributing](#contributing) diff --git a/common-dev-assets b/common-dev-assets index 3cfd2b622..238892ddd 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 3cfd2b622d864175e7979de6885a65b4fb4ab6db +Subproject commit 238892dddce116998ab6b6ebdb998708401174d1 diff --git a/examples/monolith/README.md b/examples/monolith/README.md new file mode 100644 index 000000000..dac08c088 --- /dev/null +++ b/examples/monolith/README.md @@ -0,0 +1,21 @@ +# IBM Cloud OpenShift DA - Monolith Add-ons Module + +A simple example that shows how to provision a multi zone OCP VPC cluster as well as all foundational infrastructure and supporting services required for a secure and compliant OpenShift (OCP) cluster deployment on IBM Cloud VPC. + +The following resources are provisioned by this example: +- A new resource group, if an existing one is not passed in. +- A Key Protect instance with 2 root keys, one for cluster encryption, and one for worker boot volume encryption. +- A VPC with subnets across 3 zones. +- A public gateway for all the three zones +- A multi-zone (3 zone) KMS encrypted OCP VPC cluster, with worker pools in each zone. +- An additional worker pool named workerpool is created and attached to the cluster using the worker-pool submodule. +- Auto scaling enabled for the default worker pool. +- Taints against the workers in zone-2 and zone-3. +- Enable Kubernetes API server audit logs. +- A Cloud logs instance +- A Cloud monitoring instance +- An activity tracker event routing instance +- A secrets manager instance +- A COS instance along with 3 buckets for VPC flow logs, metrics/data bucket and activity tracker bucket. +- A SCC-WP instance +- A VPC instance diff --git a/examples/monolith/main.tf b/examples/monolith/main.tf new file mode 100644 index 000000000..cf7748270 --- /dev/null +++ b/examples/monolith/main.tf @@ -0,0 +1,213 @@ +######################################################################################################################## +# Resource group +######################################################################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.4.0" + existing_resource_group_name = var.existing_resource_group_name +} + +######################################################################################################################## +# Add-ons +######################################################################################################################## + +module "monolith_add_ons" { + source = "../../modules/monolith" + prefix = var.prefix + region = var.region + resource_group_id = module.resource_group.resource_group_id + kms_encryption_enabled_cluster = var.kms_encryption_enabled_cluster + existing_kms_instance_crn = var.existing_kms_instance_crn + existing_cluster_kms_key_crn = var.existing_cluster_kms_key_crn + kms_endpoint_type = var.kms_endpoint_type + key_protect_allowed_network = var.key_protect_allowed_network + kms_encryption_enabled_boot_volume = var.kms_encryption_enabled_boot_volume + existing_boot_volume_kms_key_crn = var.existing_boot_volume_kms_key_crn + kms_plan = var.kms_plan + existing_secrets_manager_crn = var.existing_secrets_manager_crn + secrets_manager_service_plan = var.secrets_manager_service_plan + secrets_manager_endpoint_type = var.secrets_manager_endpoint_type + secrets_manager_allowed_network = var.secrets_manager_allowed_network + existing_event_notifications_instance_crn = var.existing_event_notifications_instance_crn + existing_cos_instance_crn = var.existing_cos_instance_crn + cos_instance_plan = var.cos_instance_plan + existing_cloud_monitoring_crn = var.existing_cloud_monitoring_crn + cloud_monitoring_plan = var.cloud_monitoring_plan + existing_cloud_logs_crn = var.existing_cloud_logs_crn + scc_workload_protection_service_plan = var.scc_workload_protection_service_plan + enable_vpc_flow_logs = var.enable_vpc_flow_logs +} + +######################################################################################################################## +# OCP VPC cluster +######################################################################################################################## + +locals { + vpc_subnets = { + # The default behavior is to deploy the worker pool across all subnets within the VPC. + "default" = [ + for subnet in module.monolith_add_ons.subnet_zone_list : + { + id = subnet.id + zone = subnet.zone + cidr_block = subnet.cidr + } + ] + } + + worker_pools = concat([ + { + subnet_prefix = "default" + pool_name = "default" + machine_type = var.default_worker_pool_machine_type + workers_per_zone = var.default_worker_pool_workers_per_zone + resource_group_id = module.resource_group.resource_group_id + operating_system = var.default_worker_pool_operating_system + labels = var.default_worker_pool_labels + minSize = var.default_pool_minimum_number_of_nodes + maxSize = var.default_pool_maximum_number_of_nodes + enableAutoscaling = var.enable_autoscaling_for_default_pool + boot_volume_encryption_kms_config = { + crk = module.monolith_add_ons.boot_volume_kms_key_id + kms_instance_id = module.monolith_add_ons.boot_volume_existing_kms_guid + kms_account_id = module.monolith_add_ons.boot_volume_kms_account_id + } + additional_security_group_ids = var.additional_security_group_ids + } + ], [for pool in var.additional_worker_pools : merge(pool, { resource_group_id = module.resource_group.resource_group_id + boot_volume_encryption_kms_config = { + crk = module.monolith_add_ons.boot_volume_kms_key_id + kms_instance_id = module.monolith_add_ons.boot_volume_existing_kms_guid + kms_account_id = module.monolith_add_ons.boot_volume_kms_account_id + } }) if length(pool.vpc_subnets) > 0], + [for pool in var.additional_worker_pools : { + pool_name = pool.pool_name + machine_type = pool.machine_type + workers_per_zone = pool.workers_per_zone + resource_group_id = module.resource_group.resource_group_id + operating_system = pool.operating_system + labels = pool.labels + minSize = pool.minSize + secondary_storage = pool.secondary_storage + maxSize = pool.maxSize + enableAutoscaling = pool.enableAutoscaling + boot_volume_encryption_kms_config = { + crk = module.monolith_add_ons.boot_volume_kms_key_id + kms_instance_id = module.monolith_add_ons.boot_volume_existing_kms_guid + kms_account_id = module.monolith_add_ons.boot_volume_kms_account_id + } + additional_security_group_ids = pool.additional_security_group_ids + subnet_prefix = "default" + } if length(pool.vpc_subnets) == 0]) + + # Managing the ODF version accordingly, as it changes with each OCP version. + addons = lookup(var.addons, "openshift-data-foundation", null) != null ? lookup(var.addons["openshift-data-foundation"], "version", null) == null ? { for key, value in var.addons : + key => value != null ? { + version = lookup(value, "version", null) == null && key == "openshift-data-foundation" ? "${var.openshift_version}.0" : lookup(value, "version", null) + parameters_json = lookup(value, "parameters_json", null) + } : null } : var.addons : var.addons +} + +module "ocp_base" { + depends_on = [module.monolith_add_ons] + source = "../.." + resource_group_id = module.resource_group.resource_group_id + region = var.region + tags = var.cluster_resource_tags + cluster_name = "${var.prefix}-${var.cluster_name}" + force_delete_storage = true + use_existing_cos = true + existing_cos_id = module.monolith_add_ons.cos_instance_id + vpc_id = module.monolith_add_ons.vpc_id + vpc_subnets = local.vpc_subnets + ocp_version = var.openshift_version + worker_pools = local.worker_pools + access_tags = var.access_tags + ocp_entitlement = var.ocp_entitlement + additional_lb_security_group_ids = var.additional_lb_security_group_ids + additional_vpe_security_group_ids = var.additional_vpe_security_group_ids + addons = local.addons + allow_default_worker_pool_replacement = var.allow_default_worker_pool_replacement + attach_ibm_managed_security_group = var.attach_ibm_managed_security_group + cluster_config_endpoint_type = var.cluster_config_endpoint_type + cbr_rules = var.ocp_cbr_rules + cluster_ready_when = var.cluster_ready_when + custom_security_group_ids = var.custom_security_group_ids + disable_outbound_traffic_protection = var.allow_outbound_traffic + disable_public_endpoint = !var.allow_public_access_to_cluster_management + enable_ocp_console = var.enable_ocp_console + ignore_worker_pool_size_changes = var.ignore_worker_pool_size_changes + kms_config = module.monolith_add_ons.kms_config + manage_all_addons = var.manage_all_addons + number_of_lbs = var.number_of_lbs + pod_subnet_cidr = var.pod_subnet_cidr + service_subnet_cidr = var.service_subnet_cidr + verify_worker_network_readiness = var.verify_worker_network_readiness + worker_pools_taints = var.worker_pools_taints + enable_secrets_manager_integration = var.enable_secrets_manager_integration + existing_secrets_manager_instance_crn = module.monolith_add_ons.secrets_manager_crn + secrets_manager_secret_group_id = var.secrets_manager_secret_group_id != null ? var.secrets_manager_secret_group_id : (var.enable_secrets_manager_integration ? module.secret_group[0].secret_group_id : null) + skip_ocp_secrets_manager_iam_auth_policy = var.skip_ocp_secrets_manager_iam_auth_policy +} + +resource "terraform_data" "delete_secrets" { + depends_on = [module.monolith_add_ons] + count = var.enable_secrets_manager_integration && var.secrets_manager_secret_group_id == null ? 1 : 0 + input = { + secret_id = module.secret_group[0].secret_group_id + provider_visibility = var.provider_visibility + secrets_manager_instance_id = module.monolith_add_ons.secrets_manager_guid + secrets_manager_region = module.monolith_add_ons.secrets_manager_region + secrets_manager_endpoint = var.secrets_manager_endpoint_type + } + # api key in triggers_replace to avoid it to be printed out in clear text in terraform_data output + triggers_replace = { + api_key = var.ibmcloud_api_key + } + provisioner "local-exec" { + when = destroy + command = "${path.module}/../../solutions/fully-configurable/scripts/delete_secrets.sh ${self.input.secret_id} ${self.input.provider_visibility} ${self.input.secrets_manager_instance_id} ${self.input.secrets_manager_region} ${self.input.secrets_manager_endpoint}" + interpreter = ["/bin/bash", "-c"] + + environment = { + API_KEY = self.triggers_replace.api_key + } + } +} + +module "secret_group" { + count = var.enable_secrets_manager_integration && var.secrets_manager_secret_group_id == null ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.3.15" + region = module.monolith_add_ons.secrets_manager_region + secrets_manager_guid = module.monolith_add_ons.secrets_manager_guid + secret_group_name = module.ocp_base.cluster_id + secret_group_description = "Secret group for storing ingress certificates for cluster ${var.cluster_name} with id: ${module.ocp_base.cluster_id}" + endpoint_type = var.secrets_manager_endpoint_type +} + +data "ibm_container_cluster_config" "cluster_config" { + count = var.enable_kube_audit ? 1 : 0 + cluster_name_id = module.ocp_base.cluster_id + config_dir = "${path.module}/../../kubeconfig" + admin = true + resource_group_id = module.ocp_base.resource_group_id + endpoint_type = var.cluster_config_endpoint_type != "default" ? var.cluster_config_endpoint_type : null +} + +module "kube_audit" { + count = var.enable_kube_audit ? 1 : 0 + ibmcloud_api_key = var.ibmcloud_api_key + source = "../../modules/kube-audit" + cluster_id = module.ocp_base.cluster_id + cluster_resource_group_id = module.ocp_base.resource_group_id + region = module.ocp_base.region + use_private_endpoint = var.use_private_endpoint + cluster_config_endpoint_type = var.cluster_config_endpoint_type + audit_log_policy = var.audit_log_policy + audit_namespace = var.audit_namespace + audit_deployment_name = var.audit_deployment_name + audit_webhook_listener_image = var.audit_webhook_listener_image + audit_webhook_listener_image_tag_digest = var.audit_webhook_listener_image_tag_digest +} diff --git a/examples/monolith/outputs.tf b/examples/monolith/outputs.tf new file mode 100644 index 000000000..ab94ac26d --- /dev/null +++ b/examples/monolith/outputs.tf @@ -0,0 +1,289 @@ +######################################################################################################################## +# Outputs +######################################################################################################################## + + +############################################################################## +# VPC +############################################################################## + +output "vpc_name" { + description = "Name of the VPC created." + value = module.monolith_add_ons.vpc_name +} + +output "vpc_id" { + description = "ID of the VPC created." + value = module.monolith_add_ons.vpc_id +} + +output "vpc_crn" { + description = "CRN of the VPC created." + value = module.monolith_add_ons.vpc_crn +} + +############################################################################## +# Public Gateways +############################################################################## + +output "public_gateways" { + description = "Map of the public gateways by zone." + value = module.monolith_add_ons.public_gateways +} + +############################################################################## +# VPC flow logs +############################################################################## + +output "vpc_flow_logs" { + description = "Details of the VPC flow logs collector." + value = module.monolith_add_ons.vpc_flow_logs +} + +############################################################################## +# Network ACLs +############################################################################## + +output "network_acls" { + description = "List of shortnames and IDs of network ACLs." + value = module.monolith_add_ons.network_acls +} + +############################################################################## +# Subnet Outputs +############################################################################## + +output "subnet_ids" { + description = "The IDs of the subnets." + value = module.monolith_add_ons.subnet_ids +} + +output "private_path_subnet_id" { + description = "The IDs of the subnets." + value = length(module.monolith_add_ons.subnet_ids) > 0 ? module.monolith_add_ons.subnet_ids[0] : null +} + +output "subnet_detail_list" { + description = "A list of subnets containing names, CIDR blocks, and zones." + value = module.monolith_add_ons.subnet_detail_list +} + +output "subnet_zone_list" { + description = "A list of subnet IDs and subnet zones." + value = module.monolith_add_ons.subnet_zone_list +} + +output "subnet_detail_map" { + description = "A map of subnets containing IDs, CIDR blocks, and zones." + value = module.monolith_add_ons.subnet_detail_map +} + +############################################################################## +# VPN Gateways Outputs +############################################################################## + +output "vpn_gateways_name" { + description = "List of names of VPN gateways." + value = module.monolith_add_ons.vpn_gateways_name +} + +output "vpn_gateways_data" { + description = "Details of VPN gateways data." + value = module.monolith_add_ons.vpn_gateways_data +} + +############################################################################## +# VPE Outputs +############################################################################## + +output "vpe_ips" { + description = "The reserved IPs for endpoint gateways." + value = module.monolith_add_ons.vpe_ips +} + +output "vpe_crn" { + description = "The CRN of the endpoint gateway." + value = module.monolith_add_ons.vpe_crn +} + +############################################################################## +# KMS Outputs +############################################################################## + +output "kms_guid" { + description = "Key Protect instance GUID or the KMS instance GUID if existing_kms_instance_crn was set" + value = module.monolith_add_ons.kms_guid +} + +output "kms_account_id" { + description = "The account ID of the KMS instance." + value = module.monolith_add_ons.kms_account_id +} + +output "key_protect_id" { + description = "Key Protect instance ID when an instance is created, otherwise null" + value = module.monolith_add_ons.key_protect_id +} + +output "kms_instance_crn" { + value = module.monolith_add_ons.kms_instance_crn + description = "The CRN of the Hyper Protect Crypto Service instance or Key Protect instance" +} + +############################################################################## +# SM Outputs +############################################################################## + +output "secrets_manager_guid" { + description = "GUID of Secrets Manager instance" + value = module.monolith_add_ons.secrets_manager_guid +} + +output "secrets_manager_crn" { + value = module.monolith_add_ons.secrets_manager_crn + description = "CRN of the Secrets Manager instance" +} + +output "secrets_manager_region" { + value = module.monolith_add_ons.secrets_manager_region + description = "Region of the Secrets Manager instance" +} + +############################################################################## +# COS Outputs +############################################################################## + +output "cos_instance_crn" { + description = "COS instance crn" + value = module.monolith_add_ons.cos_instance_crn +} + +output "cos_instance_guid" { + description = "COS instance guid" + value = module.monolith_add_ons.cos_instance_guid +} + +############################################################################## +# Cloud Monitoring Outputs +############################################################################## + +output "cloud_monitoring_crn" { + value = module.monolith_add_ons.cloud_monitoring_crn + description = "The id of the provisioned IBM Cloud Monitoring instance." +} +output "cloud_monitoring_name" { + value = module.monolith_add_ons.cloud_monitoring_name + description = "The name of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_guid" { + value = module.monolith_add_ons.cloud_monitoring_guid + description = "The guid of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_access_key_name" { + value = module.monolith_add_ons.cloud_monitoring_access_key_name + description = "The name of the IBM Cloud Monitoring access key for agents to use" +} + +output "cloud_monitoring_access_key" { + value = module.monolith_add_ons.cloud_monitoring_access_key + description = "The IBM Cloud Monitoring access key for agents to use" + sensitive = true +} + +############################################################################## +# Cloud Logs Outputs +############################################################################## + +output "cloud_logs_crn" { + value = module.monolith_add_ons.cloud_logs_crn + description = "The id of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_guid" { + value = module.monolith_add_ons.cloud_logs_guid + description = "The guid of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_name" { + value = module.monolith_add_ons.cloud_logs_name + description = "The name of the provisioned IBM Cloud Logs instance." +} + +output "logs_bucket_crn" { + description = "Logs Cloud Object Storage bucket CRN" + value = module.monolith_add_ons.logs_bucket_crn +} + +output "metrics_bucket_crn" { + description = "Metrics Cloud Object Storage bucket CRN" + value = module.monolith_add_ons.metrics_bucket_crn +} + +############################################################################## +# Activity Tracker Event Routing Outputs +############################################################################## + +output "activity_tracker_cos_target_bucket_name" { + value = module.monolith_add_ons.activity_tracker_cos_target_bucket_name + description = "he name of the object storage bucket which is set as activity tracker event routing target to collect audit events." +} + +output "activity_tracker_targets" { + value = module.monolith_add_ons.activity_tracker_targets + description = "The map of created Activity Tracker Event Routing targets" +} + +output "activity_tracker_routes" { + value = module.monolith_add_ons.activity_tracker_routes + description = "The map of created Activity Tracker Event Routing routes" +} + +############################################################################## +# SCC-WP Outputs +############################################################################## + +output "scc_workload_protection_id" { + description = "SCC Workload Protection instance ID" + value = module.monolith_add_ons.scc_workload_protection_id +} + +output "scc_workload_protection_crn" { + description = "SCC Workload Protection instance CRN" + value = module.monolith_add_ons.scc_workload_protection_crn +} + +output "scc_workload_protection_name" { + description = "SCC Workload Protection instance name" + value = module.monolith_add_ons.scc_workload_protection_name +} + +############################################################################## +# Cluster Outputs +############################################################################## + +output "cluster_name" { + value = module.ocp_base.cluster_name + description = "The name of the provisioned OpenShift cluster." +} + +output "cluster_id" { + value = module.ocp_base.cluster_id + description = "The unique identifier assigned to the provisioned OpenShift cluster." +} + +output "cluster_crn" { + description = "The Cloud Resource Name (CRN) of the provisioned OpenShift cluster." + value = module.ocp_base.cluster_crn +} + +output "workerpools" { + description = "A list of worker pools associated with the provisioned cluster" + value = module.ocp_base.workerpools +} + +output "ocp_version" { + description = "The version of OpenShift running on the provisioned cluster." + value = module.ocp_base.ocp_version +} diff --git a/examples/monolith/provider.tf b/examples/monolith/provider.tf new file mode 100644 index 000000000..df39925fa --- /dev/null +++ b/examples/monolith/provider.tf @@ -0,0 +1,28 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} + +data "ibm_iam_auth_token" "auth_token" {} + +provider "restapi" { + uri = "https://resource-controller.cloud.ibm.com" + headers = { + Authorization = data.ibm_iam_auth_token.auth_token.iam_access_token + } + write_returns_object = true +} + +provider "helm" { + kubernetes = { + host = data.ibm_container_cluster_config.cluster_config[0].host + token = data.ibm_container_cluster_config.cluster_config[0].token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config[0].ca_certificate + } +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config[0].host + token = data.ibm_container_cluster_config.cluster_config[0].token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config[0].ca_certificate +} diff --git a/examples/monolith/variables.tf b/examples/monolith/variables.tf new file mode 100644 index 000000000..bc9b9416e --- /dev/null +++ b/examples/monolith/variables.tf @@ -0,0 +1,614 @@ +######################################################################################################################## +# Input variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud api token" + sensitive = true +} + +variable "prefix" { + type = string + description = "Prefix for name of all resource created by this example" + default = "mon-eg" + validation { + error_message = "Prefix must begin and end with a letter and contain only letters, numbers, and - characters." + condition = can(regex("^([A-z]|[a-z][-a-z0-9]*[a-z0-9])$", var.prefix)) + } +} + +variable "region" { + type = string + description = "Region where resources are created" + default = "us-south" +} + +variable "provider_visibility" { + description = "Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`." + type = string + default = "private" + validation { + condition = contains(["public", "private", "public-and-private"], var.provider_visibility) + error_message = "Invalid visibility option. Allowed values are `public`, `private`, or `public-and-private`." + } +} + +variable "existing_resource_group_name" { + type = string + description = "The name of an existing resource group to provision the resources." + default = "Default" +} + +variable "existing_event_notifications_instance_crn" { + type = string + description = "The CRN of the Event Notifications service used to enable lifecycle notifications for your Secrets Manager instance." + default = null +} + +variable "kms_encryption_enabled_cluster" { + description = "Set to true to enable KMS encryption for the cluster's Object Storage bucket. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn`." + type = bool + default = true + nullable = false + + validation { + condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled_cluster : true + error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled_cluster' to true." + } + + validation { + condition = var.existing_cluster_kms_key_crn != null ? var.kms_encryption_enabled_cluster : true + error_message = "If passing a value for 'existing_cluster_kms_key_crn', you should set 'kms_encryption_enabled_cluster' to true." + } +} + +variable "existing_kms_instance_crn" { + type = string + default = null + description = "The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect)." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.existing_kms_instance_crn)), + var.existing_kms_instance_crn == null, + ]) + error_message = "The provided KMS instance CRN in the input 'existing_kms_instance_crn' in not valid." + } +} + +variable "existing_cluster_kms_key_crn" { + type = string + default = null + description = "The CRN of an existing KMS key to use for encrypting the Object Storage of the Cluster. If no value is set for this variable, specify a value for `existing_kms_instance_crn` variable to create a key ring and key." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}:key:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.existing_cluster_kms_key_crn)), + var.existing_cluster_kms_key_crn == null, + ]) + error_message = "The provided KMS key CRN in the input 'existing_cluster_kms_key_crn' in not valid." + } + + validation { + condition = var.existing_cluster_kms_key_crn != null ? var.existing_kms_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing key value using the 'existing_cluster_kms_key_crn' input." + } +} + +variable "kms_endpoint_type" { + type = string + description = "The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_cluster` is true" + default = "private" + nullable = false + validation { + condition = can(regex("^(public|private)$", var.kms_endpoint_type)) + error_message = "The kms_endpoint_type value must be 'public' or 'private'." + } +} + +variable "key_protect_allowed_network" { + type = string + description = "Allowed network types for the Key Protect instance. Possible values are 'private-only', or 'public-and-private'. Only used if 'create_key_protect_instance' is set to `true`." + default = "private-only" + validation { + condition = can(regex("private-only|public-and-private", var.key_protect_allowed_network)) + error_message = "The `key_protect_allowed_network` value must be 'private-only' or 'public-and-private'." + } +} + +variable "kms_encryption_enabled_boot_volume" { + type = bool + description = "Set this to true to control the encryption keys used to encrypt the data that for the block storage volumes for VPC. If set to false, the data is encrypted by using randomly generated keys. For more info on encrypting block storage volumes, see https://cloud.ibm.com/docs/vpc?topic=vpc-creating-instances-byok" + default = true + nullable = false + + validation { + condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled_boot_volume || var.kms_encryption_enabled_cluster : true + error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled_boot_volume' to true." + } + + validation { + condition = var.existing_boot_volume_kms_key_crn != null ? var.kms_encryption_enabled_boot_volume : true + error_message = "If passing a value for 'existing_boot_volume_kms_key_crn', you should set 'kms_encryption_enabled_boot_volume' to true." + } +} + +variable "existing_boot_volume_kms_key_crn" { + type = string + default = null + description = "The CRN of an existing KMS key to use to encrypt the the block storage volumes for VPC. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}:key:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.existing_boot_volume_kms_key_crn)), + var.existing_boot_volume_kms_key_crn == null, + ]) + error_message = "The provided KMS key CRN in the input 'existing_boot_volume_kms_key_crn' in not valid." + } +} + +variable "kms_plan" { + type = string + description = "Plan for the Key Protect instance. Supported values are 'tiered-pricing' and 'cross-region-resiliency'. Only used if 'create_key_protect_instance' is set to `true`." + default = "tiered-pricing" + # validation performed in terraform-ibm-key-protect module +} + +variable "existing_secrets_manager_crn" { + type = string + description = "The CRN of an existing Secrets Manager instance. If not supplied, a new instance is created." + default = null +} + +variable "secrets_manager_service_plan" { + type = string + description = "The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. You can create only one Trial instance of Secrets Manager per account. Before you can create a new Trial instance, you must delete the existing Trial instance and its reclamation." + default = "standard" + validation { + condition = var.existing_secrets_manager_crn == null ? contains(["standard", "trial"], var.secrets_manager_service_plan) : true + error_message = "Only 'standard' and 'trial' are allowed values for 'secrets_manager_service_plan'. Applies only if not providing a value for the 'existing_secrets_manager_crn' input." + } +} + +variable "secrets_manager_allowed_network" { + type = string + description = "The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`." + default = "private-only" + validation { + condition = contains(["private-only", "public-and-private"], var.secrets_manager_allowed_network) + error_message = "The specified allowed_network is not a valid selection!" + } +} + +variable "secrets_manager_endpoint_type" { + type = string + description = "The type of endpoint (public or private) to connect to the Secrets Manager API. The Terraform provider uses this endpoint type to interact with the Secrets Manager API and configure Event Notifications." + default = "private" + validation { + condition = contains(["public", "private"], var.secrets_manager_endpoint_type) + error_message = "The specified service endpoint is not a valid selection!" + } +} + +variable "existing_cos_instance_crn" { + type = string + description = "The CRN of an existing Object Storage instance." + default = null +} + +variable "cos_instance_plan" { + description = "The plan to use when Object Storage instances are created." + type = string + default = "standard" + validation { + condition = contains(["standard", "cos-one-rate-plan"], var.cos_instance_plan) + error_message = "The specified plan is not a valid selection!" + } +} + +variable "existing_cloud_monitoring_crn" { + type = string + default = null + description = "The CRN of an existing Cloud Monitoring instance. If not supplied, a new instance will be created." +} + +variable "cloud_monitoring_plan" { + type = string + description = "The IBM Cloud Monitoring plan to provision. Available values are `lite` and `graduated-tier` and graduated-tier-sysdig-secure-plus-monitor (available in region eu-fr2 only)." + default = "graduated-tier" + + validation { + condition = can(regex("^lite$|^graduated-tier$|^graduated-tier-sysdig-secure-plus-monitor$", var.cloud_monitoring_plan)) + error_message = "The plan value must be one of the following: lite, graduated-tier and graduated-tier-sysdig-secure-plus-monitor (available in region eu-fr2 only)." + } + + validation { + condition = (var.cloud_monitoring_plan != "graduated-tier-sysdig-secure-plus-monitor") || var.region == "eu-fr2" + error_message = "When cloud_monitoring_plan is graduated-tier-sysdig-secure-plus-monitor region should be set to eu-fr2." + } +} + +variable "existing_cloud_logs_crn" { + type = string + default = null + description = "The CRN of an existing Cloud Logs instance. If not supplied, a new instance will be created." +} + +variable "scc_workload_protection_service_plan" { + description = "The pricing plan for the Workload Protection instance service. Possible values: `free-trial`, `graduated-tier`." + type = string + default = "graduated-tier" + validation { + error_message = "Plan for Workload Protection instances can only be `free-trial` or `graduated-tier`." + condition = contains( + ["free-trial", "graduated-tier"], + var.scc_workload_protection_service_plan + ) + } +} + +variable "enable_vpc_flow_logs" { + description = "To enable VPC Flow logs, set this to true." + type = bool + nullable = false + default = true +} + +######################################################################################################################## +# OCP VPC cluster +######################################################################################################################## + +variable "cluster_name" { + type = string + description = "The name of the new IBM Cloud OpenShift Cluster. If a `prefix` input variable is specified, it is added to this name in the `-value` format." + default = "openshift" +} + +variable "default_worker_pool_machine_type" { + type = string + description = "The machine type for worker nodes." + default = "bx2.4x16" + validation { + condition = length(regexall("^[a-z0-9]+(?:\\.[a-z0-9]+)*\\.\\d+x\\d+(?:\\.[a-z0-9]+)?$", var.default_worker_pool_machine_type)) > 0 + error_message = "Invalid value provided for the machine type." + } +} + +variable "default_worker_pool_workers_per_zone" { + type = number + description = "Number of worker nodes in each zone of the cluster." + default = 1 +} + +variable "default_worker_pool_operating_system" { + type = string + description = "The operating system installed on the worker nodes." + default = "RHCOS" +} + +variable "default_worker_pool_labels" { + type = map(string) + description = "A set of key-value labels assigned to the worker pool for identification." + default = {} +} + +variable "default_pool_minimum_number_of_nodes" { + type = number + description = "The minimum number of worker nodes allowed in the pool, ensuring at least one worker is always running." + default = 1 +} + +variable "default_pool_maximum_number_of_nodes" { + type = number + description = "The maximum number of worker nodes allowed in the pool, preventing the pool from exceeding three workers." + default = 3 +} + +variable "additional_security_group_ids" { + type = list(string) + description = "A list of security group IDs that are attached to the worker nodes for additional network security controls." + default = [] +} + +variable "additional_worker_pools" { + type = list(object({ + vpc_subnets = optional(list(object({ + id = string + zone = string + cidr_block = string + })), []) + pool_name = string + machine_type = string + workers_per_zone = number + operating_system = string + labels = optional(map(string)) + minSize = optional(number) + secondary_storage = optional(string) + maxSize = optional(number) + enableAutoscaling = optional(bool) + additional_security_group_ids = optional(list(string)) + })) + description = "List of additional worker pools." + default = [] +} + +variable "enable_autoscaling_for_default_pool" { + type = bool + description = "Set `true` to enable automatic scaling of worker based on workload demand." + default = false +} + +variable "addons" { + type = object({ + debug-tool = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + image-key-synchronizer = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + openshift-data-foundation = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + vpc-file-csi-driver = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + static-route = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + cluster-autoscaler = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + vpc-block-csi-driver = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + ibm-storage-operator = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + openshift-ai = optional(object({ + version = optional(string) + parameters_json = optional(string) + })) + }) + description = "Map of OCP cluster add-on versions to install (NOTE: The 'vpc-block-csi-driver' add-on is installed by default for VPC clusters and 'ibm-storage-operator' is installed by default in OCP 4.15 and later, however you can explicitly specify it here if you wish to choose a later version than the default one). [Check supported addons and versions here](https://cloud.ibm.com/docs/containers?topic=containers-supported-cluster-addon-versions)." + nullable = false + default = {} +} + +variable "openshift_version" { + type = string + description = "Version of the OpenShift cluster to provision." + default = "4.19" +} + +variable "cluster_resource_tags" { + type = list(string) + description = "Metadata labels describing this cluster deployment, i.e. test." + default = [] +} + +variable "access_tags" { + type = list(string) + description = "A list of access tags to apply to the resources created by the module." + default = [] +} + +variable "ocp_entitlement" { + type = string + description = "Value that is applied to the entitlements for OCP cluster provisioning." + default = null +} + +variable "additional_lb_security_group_ids" { + description = "List of additional security group IDs to add to the load balancers associated with the cluster. Ensure that the `number_of_lbs` variable is set to the number of Load Balancers associated with the cluster. This comes in addition to the IBM maintained security group." + type = list(string) + default = [] + nullable = false +} + +variable "number_of_lbs" { + description = "The total number of Load Balancers in the cluster that should be associated with the security groups defined in `additional_lb_security_group_ids` variable." + type = number + default = 1 + nullable = false +} + +variable "additional_vpe_security_group_ids" { + description = "Additional security groups to add to all existing load balancers. This comes in addition to the IBM maintained security group." + type = object({ + master = optional(list(string), []) + registry = optional(list(string), []) + api = optional(list(string), []) + }) + default = {} +} + +variable "allow_default_worker_pool_replacement" { + type = bool + description = "Set to true to allow the module to recreate a default worker pool. Only use in the case where you are getting an error indicating that the default worker pool cannot be replaced on apply. Once the default worker pool is handled separately, if you wish to make any change to the default worker pool which requires the re-creation of the default pool set this variable to true." + default = false + nullable = false +} + +variable "attach_ibm_managed_security_group" { + description = "Specify whether to attach the IBM-defined default security group (whose name is kube-) to all worker nodes. Only applicable if `custom_security_group_ids` is set." + type = bool + default = true +} + +variable "cluster_config_endpoint_type" { + description = "Specify which type of endpoint to use for cluster config access: 'default', 'private', 'vpe', 'link'. A 'default' value uses the default endpoint of the cluster." + type = string + default = "default" + nullable = false +} + +variable "verify_worker_network_readiness" { + type = bool + description = "By setting this to true, a script runs kubectl commands to verify that all worker nodes can communicate successfully with the master. If the runtime does not have access to the kube cluster to run kubectl commands, set this value to false." + default = true +} + +variable "cluster_ready_when" { + type = string + description = "The cluster is ready based on one of the following:: MasterNodeReady (not recommended), OneWorkerNodeReady, Normal, IngressReady." + default = "IngressReady" +} + +variable "custom_security_group_ids" { + description = "Security groups to add to all worker nodes. This comes in addition to the IBM maintained security group if `attach_ibm_managed_security_group` is set to true. If this variable is set, the default VPC security group is NOT assigned to the worker nodes." + type = list(string) + default = null +} + +variable "allow_outbound_traffic" { + type = bool + description = "Set to true to allow public outbound access from the cluster workers." + default = true +} + +variable "allow_public_access_to_cluster_management" { + type = bool + description = "Set to true to access the cluster through a public cloud service endpoint." + default = true +} + +variable "enable_ocp_console" { + description = "Flag to specify whether to enable or disable the OpenShift console. If set to `null` the module does not modify the current setting on the cluster. Keep in mind that when this input is set to `true` or `false` on a cluster with private only endpoint enabled, the runtime must be able to access the private endpoint." + type = bool + default = null + nullable = true +} + +variable "ignore_worker_pool_size_changes" { + type = bool + description = "Enable if using worker autoscaling. Stops Terraform managing worker count." + default = false +} + +variable "manage_all_addons" { + type = bool + default = false + nullable = false + description = "Instructs deployable architecture to manage all cluster addons, even if addons were installed outside of the module. If set to 'true' this deployable architecture destroys any addons that were installed by other sources." +} + +variable "pod_subnet_cidr" { + type = string + description = "Specify a custom subnet CIDR to provide private IP addresses for pods. The subnet must have a CIDR of at least `/23` or larger. Default value is `172.30.0.0/16` when the variable is set to `null`." + default = null +} + +variable "service_subnet_cidr" { + type = string + description = "Specify a custom subnet CIDR to provide private IP addresses for services. The subnet must be at least `/24` or larger. Default value is `172.21.0.0/16` when the variable is set to `null`." + default = null +} + +variable "worker_pools_taints" { + type = map(list(object({ key = string, value = string, effect = string }))) + description = "Optional, Map of lists containing node taints by node-pool name." + default = null +} + +variable "enable_secrets_manager_integration" { + type = bool + description = "Integrate with IBM Cloud Secrets Manager so you can centrally manage Ingress subdomain certificates and other secrets." + default = true + nullable = false +} + +variable "secrets_manager_secret_group_id" { + type = string + description = "Secret group ID where Ingress secrets are stored in the Secrets Manager instance. If 'enable_secrets_manager_integration' is set to true and 'secrets_manager_secret_group_id' is not provided, a new group will be created with the same name as cluster_id." + default = null +} + +variable "skip_ocp_secrets_manager_iam_auth_policy" { + type = bool + description = "To skip creating auth policy that allows OCP cluster 'Manager' role access in the existing Secrets Manager instance for managing ingress certificates." + default = false +} + +############################################################## +# Kube Audit +############################################################## + +variable "enable_kube_audit" { + type = bool + description = "Kubernetes audit logging provides a chronological record of operations performed on the cluster, including by users, administrators, and system components. It is useful for compliance, and security monitoring. Set true to enable kube audit by default." + default = true +} + +variable "audit_log_policy" { + type = string + description = "Specify the amount of information that is logged to the API server audit logs by choosing the audit log policy profile to use. Supported values are `default` and `WriteRequestBodies`." + default = "default" + + validation { + error_message = "Invalid Audit log policy Type! Valid values are 'default' or 'WriteRequestBodies'" + condition = contains(["default", "WriteRequestBodies"], var.audit_log_policy) + } +} + +variable "audit_namespace" { + type = string + description = "The name of the namespace where log collection service and a deployment will be created." + default = "ibm-kube-audit" +} + +variable "audit_deployment_name" { + type = string + description = "The name of log collection deployment and service." + default = "ibmcloud-kube-audit" +} + +variable "audit_webhook_listener_image" { + type = string + description = "The audit webhook listener image reference in the format of `[registry-url]/[namespace]/[image]`. This solution uses the `icr.io/ibm/ibmcloud-kube-audit-to-ibm-cloud-logs` image to forward logs to IBM Cloud Logs. This image is for demonstration purposes only. For a production solution, configure and maintain your own log forwarding image." + default = "icr.io/ibm/ibmcloud-kube-audit-to-ibm-cloud-logs" +} + +variable "audit_webhook_listener_image_tag_digest" { + type = string + description = "The tag or digest for the audit webhook listener image to deploy. If changing the value, ensure it is compatible with `audit_webhook_listener_image`." + default = "deaabcb8225e800385413ba420cf3f819d3b0671@sha256:acf123f4dba63534cbc104c6886abedff9d25a22a34ab7b549ede988ed6e7144" +} + +variable "use_private_endpoint" { + type = bool + description = "Set this to true to force all API calls to use the IBM Cloud private endpoints." + default = false +} + +variable "ocp_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + tags = optional(list(object({ + name = string + value = string + })), []) + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The list of context-based restriction rules to create." + default = [] +} diff --git a/examples/monolith/version.tf b/examples/monolith/version.tf new file mode 100644 index 000000000..8c94c3ba8 --- /dev/null +++ b/examples/monolith/version.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">=1.9.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.84.3" + } + restapi = { + source = "Mastercard/restapi" + version = "2.0.1" + } + helm = { + source = "hashicorp/helm" + version = "3.0.2" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.38.0" + } + } +} diff --git a/modules/monolith/README.md b/modules/monolith/README.md new file mode 100644 index 000000000..83016376c --- /dev/null +++ b/modules/monolith/README.md @@ -0,0 +1,265 @@ +# Monolith module + +The module acts as a monolithic wrapper around a collection of smaller, official IBM Terraform modules, simplifying the deployment of a compliant, secure, and fully operational environment with a single configuration. This module integrates essential foundational services for security, monitoring, and logging for creating a fully configurable OCP cluster on an IBM Cloud Virtual Private Cloud. + +### Components + +The primary goal of this module is to provision an OpenShift cluster on VPC and automatically configure the necessary supporting services, including: +* `VPC Infrastructure`: The base VPC, subnets, and network access controls (ACLs) for the OpenShift cluster. +* `Key Management (KMS)`: Optional provision and configuration of an IBM Key Protect or Hyper Protect Crypto Services (HPCS) instance for encrypting cluster and boot volumes. +* `Secrets Management`: Optional provision and configuration of an IBM Secrets Manager instance to securely store service credentials and other secrets. +* `Cloud Object Storage (COS)`: Optional provision and configuration of COS instances and buckets for flow logs, activity tracker, and other data storage needs. +* `Monitoring & Logging`: Optional provision and configuration of IBM Cloud Monitoring and IBM Cloud Logs instances for centralized observability. +* `Activity Tracker and Event Routing`: Configure event routing for platform audit logs to a COS bucket or IBM Cloud Logs. +* `Security & Compliance`: Optional integration with IBM Cloud Security and Compliance Center (SCC) Workload Protection. +* `VPE Gateways`: Optional configuration of Virtual Private Endpoint (VPE) gateways for secure private connectivity to cloud services. + +## Usage + +```hcl +module "monolith_ocp_add_ons" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm//modules/monolith" + version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release + prefix = "" + region = "us-south" + resource_group_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" + existing_event_notifications_instance_crn = var.existing_event_notifications_instance_crn +} +``` + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >=1.9.0 | +| [ibm](#requirement\_ibm) | >= 1.78.2, < 2.0.0 | +| [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [activity\_tracker](#module\_activity\_tracker) | terraform-ibm-modules/activity-tracker/ibm | 1.5.0 | +| [at\_cos\_bucket](#module\_at\_cos\_bucket) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [cloud\_logs](#module\_cloud\_logs) | terraform-ibm-modules/cloud-logs/ibm | 1.10.0 | +| [cloud\_logs\_buckets](#module\_cloud\_logs\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.7 | +| [cloud\_monitoring](#module\_cloud\_monitoring) | terraform-ibm-modules/cloud-monitoring/ibm | 1.11.0 | +| [cos](#module\_cos) | terraform-ibm-modules/cos/ibm//modules/fscloud | 10.5.9 | +| [existing\_boot\_volume\_kms\_key\_crn\_parser](#module\_existing\_boot\_volume\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | +| [existing\_cloud\_monitoring\_crn\_parser](#module\_existing\_cloud\_monitoring\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | +| [existing\_cluster\_kms\_key\_crn\_parser](#module\_existing\_cluster\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | +| [existing\_cos\_instance\_crn\_parser](#module\_existing\_cos\_instance\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | +| [existing\_kms\_crn\_parser](#module\_existing\_kms\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | +| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 5.4.5 | +| [metrics\_routing](#module\_metrics\_routing) | terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing | 1.11.0 | +| [scc\_wp](#module\_scc\_wp) | terraform-ibm-modules/scc-workload-protection/ibm | 1.16.4 | +| [secrets\_manager](#module\_secrets\_manager) | terraform-ibm-modules/secrets-manager/ibm | 2.11.9 | +| [secrets\_manager\_crn\_parser](#module\_secrets\_manager\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | +| [secrets\_manager\_service\_credentials](#module\_secrets\_manager\_service\_credentials) | terraform-ibm-modules/secrets-manager/ibm//modules/secrets | 2.11.9 | +| [vpc](#module\_vpc) | terraform-ibm-modules/landing-zone-vpc/ibm | 8.9.1 | +| [vpc\_cos\_buckets](#module\_vpc\_cos\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [vpe\_gateway](#module\_vpe\_gateway) | terraform-ibm-modules/vpe-gateway/ibm | 4.6.6 | + +### Resources + +| Name | Type | +|------|------| +| [ibm_en_subscription_email.email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_subscription_email) | resource | +| [ibm_en_topic.en_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_topic) | resource | +| [ibm_iam_authorization_policy.secrets_manager_key_manager](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [time_sleep.wait_for_cos_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_secrets_manager](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [ibm_en_destinations.en_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/en_destinations) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [activity\_tracker\_cloud\_logs\_route\_name](#input\_activity\_tracker\_cloud\_logs\_route\_name) | Name of the cloud logs route for activity tracker event routing. | `string` | `null` | no | +| [activity\_tracker\_cos\_bucket\_access\_tags](#input\_activity\_tracker\_cos\_bucket\_access\_tags) | A list of optional access tags to add to the IBM Cloud Activity Tracker Event Routing Cloud Object Storage bucket. | `list(string)` | `[]` | no | +| [activity\_tracker\_cos\_bucket\_retention\_policy](#input\_activity\_tracker\_cos\_bucket\_retention\_policy) | The retention policy of the IBM Cloud Activity Tracker Event Routing COS target bucket. |
object({
default = optional(number, 90)
maximum = optional(number, 350)
minimum = optional(number, 90)
permanent = optional(bool, false)
})
| `null` | no | +| [activity\_tracker\_cos\_route\_name](#input\_activity\_tracker\_cos\_route\_name) | Name of the cos route for activity tracker event routing. | `string` | `null` | no | +| [activity\_tracker\_cos\_target\_bucket\_class](#input\_activity\_tracker\_cos\_target\_bucket\_class) | The storage class of the newly provisioned Cloud Object Storage bucket. Specify one of the following values for the storage class: `standard`, `vault`, `cold`, `smart` (default), or `onerate_active`. | `string` | `"smart"` | no | +| [activity\_tracker\_cos\_target\_bucket\_name](#input\_activity\_tracker\_cos\_target\_bucket\_name) | The name of the Cloud Object Storage bucket to create for the Cloud Object Storage target to store AT events. Cloud Object Storage bucket names are globally unique. If the `add_bucket_name_suffix` variable is set to `true`, 4 random characters are added to this name to ensure that the name of the bucket is globally unique. If the prefix input variable is passed, the name of the instance is prefixed to the value in the `-value` format. | `string` | `"at-events-cos-bucket"` | no | +| [address\_prefixes](#input\_address\_prefixes) | The IP range that will be defined for the VPC for a certain location. Use only with manual address prefixes. |
object({
zone-1 = optional(list(string))
zone-2 = optional(list(string))
zone-3 = optional(list(string))
})
|
{
"zone-1": null,
"zone-2": null,
"zone-3": null
}
| no | +| [app\_config\_crn](#input\_app\_config\_crn) | The CRN of an existing App Config instance to use with the SCC Workload Protection instance. Required if `cspm_enabled` is true. NOTE: Ensure the App Config instance has configuration aggregator enabled. | `string` | `null` | no | +| [append\_random\_bucket\_name\_suffix](#input\_append\_random\_bucket\_name\_suffix) | Append random generated suffix (4 characters long) to the newly provisioned IBM Cloud Logs Object Storage bucket names. | `bool` | `true` | no | +| [boot\_volume\_kms\_key\_name](#input\_boot\_volume\_kms\_key\_name) | The name for the key created for the block storage volumes. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"boot-volume-key"` | no | +| [boot\_volume\_kms\_key\_ring\_name](#input\_boot\_volume\_kms\_key\_ring\_name) | The name for the key ring created for the block storage volumes key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"boot-volume-key-ring"` | no | +| [clean\_default\_security\_group\_acl](#input\_clean\_default\_security\_group\_acl) | Remove all rules from the default VPC security group and VPC ACL (less permissive). | `bool` | `true` | no | +| [cloud\_logs\_access\_tags](#input\_cloud\_logs\_access\_tags) | A list of access tags to apply to the IBM Cloud Logs instance created by the DA. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial. | `list(string)` | `[]` | no | +| [cloud\_logs\_cbr\_rules](#input\_cloud\_logs\_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
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [cloud\_logs\_cos\_buckets\_class](#input\_cloud\_logs\_cos\_buckets\_class) | The storage class of the newly provisioned IBM Cloud Logs Object Storage buckets. Possible values: `standard` or `smart`. Applies only if `existing_cloud_logs_crn` is not provided. | `string` | `"smart"` | no | +| [cloud\_logs\_data\_cos\_bucket\_name](#input\_cloud\_logs\_data\_cos\_bucket\_name) | The name of an to be given to a new bucket inside the existing Object Storage instance to use for IBM Cloud Logs. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cloud-logs-logs-bucket"` | no | +| [cloud\_logs\_instance\_name](#input\_cloud\_logs\_instance\_name) | The name of the IBM Cloud Logs instance to create. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cloud-logs"` | no | +| [cloud\_logs\_metrics\_cos\_bucket\_name](#input\_cloud\_logs\_metrics\_cos\_bucket\_name) | The name of an to be given to a new bucket inside the existing Object Storage instance to use for IBM Cloud Logs. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cloud-logs-metrics-bucket"` | no | +| [cloud\_logs\_resource\_tags](#input\_cloud\_logs\_resource\_tags) | Tags associated with the IBM Cloud Logs instance (Optional, array of strings). | `list(string)` | `[]` | no | +| [cloud\_logs\_retention\_period](#input\_cloud\_logs\_retention\_period) | The number of days IBM Cloud Logs will retain the logs data in Priority insights. Allowed values: 7, 14, 30, 60, 90. | `number` | `7` | no | +| [cloud\_logs\_target\_name](#input\_cloud\_logs\_target\_name) | Name of the cloud logs target for activity tracker event routing. | `string` | `null` | no | +| [cloud\_monitoring\_access\_tags](#input\_cloud\_monitoring\_access\_tags) | A list of access tags to apply to the IBM Cloud Monitoring instance created by the DA. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial. | `list(string)` | `[]` | no | +| [cloud\_monitoring\_cbr\_rules](#input\_cloud\_monitoring\_cbr\_rules) | The list of context-based restriction rules to create for the instance. |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [cloud\_monitoring\_instance\_name](#input\_cloud\_monitoring\_instance\_name) | The name of the IBM Cloud Monitoring instance to create. If the prefix variable is passed, the name of the instance is prefixed to the value in the `-value` format. | `string` | `"cloud-monitoring"` | no | +| [cloud\_monitoring\_plan](#input\_cloud\_monitoring\_plan) | The IBM Cloud Monitoring plan to provision. Available values are `lite` and `graduated-tier` and graduated-tier-sysdig-secure-plus-monitor (available in region eu-fr2 only). | `string` | `"graduated-tier"` | no | +| [cloud\_monitoring\_resource\_keys](#input\_cloud\_monitoring\_resource\_keys) | A list of maps representing resource keys to create for the IBM Cloud Monitoring instance. Each entry defines a single resource key. Use this list to manage custom keys and handle key rotation. |
list(object({
name = string
generate_hmac_credentials = optional(bool, false) # pragma: allowlist secret
role = optional(string, "Manager")
service_id_crn = optional(string, null)
}))
| `[]` | no | +| [cloud\_monitoring\_resource\_tags](#input\_cloud\_monitoring\_resource\_tags) | Tags associated with the IBM Cloud Monitoring instance (Optional, array of strings). | `list(string)` | `[]` | no | +| [cluster\_kms\_key\_name](#input\_cluster\_kms\_key\_name) | The name of the key to be created for the cluster's Object Storage bucket encryption. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cluster-key"` | no | +| [cluster\_kms\_key\_ring\_name](#input\_cluster\_kms\_key\_ring\_name) | The name of the key ring to be created for the cluster's Object Storage bucket encryption key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cluster-key-ring"` | no | +| [cos\_instance\_access\_tags](#input\_cos\_instance\_access\_tags) | A list of access tags to apply to the Object Storage instance created by the module. | `list(string)` | `[]` | no | +| [cos\_instance\_cbr\_rules](#input\_cos\_instance\_cbr\_rules) | The list of context-based restriction rules to create for the instance. |
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 | +| [cos\_instance\_name](#input\_cos\_instance\_name) | The name for the IBM Cloud Object Storage instance provisioned by this solution. If a value is passed for `prefix`, the instance will be named with the prefix value in the format of `-value`. | `string` | `"cos-instance"` | no | +| [cos\_instance\_plan](#input\_cos\_instance\_plan) | The plan to use when Object Storage instances are created. | `string` | `"standard"` | no | +| [cos\_instance\_resource\_tags](#input\_cos\_instance\_resource\_tags) | A list of resource tags to apply to the Object Storage instance. | `list(string)` | `[]` | no | +| [cos\_target\_name](#input\_cos\_target\_name) | Name of the cos target for activity tracker event routing. | `string` | `null` | no | +| [cspm\_enabled](#input\_cspm\_enabled) | Enable Cloud Security Posture Management (CSPM) for the Workload Protection instance. This will create a trusted profile associated with the SCC Workload Protection instance that has viewer / reader access to the App Config service and viewer access to the Enterprise service. | `bool` | `false` | no | +| [default\_network\_acl\_name](#input\_default\_network\_acl\_name) | Name of the Default ACL. If null, a name will be automatically generated. | `string` | `null` | no | +| [default\_routing\_table\_name](#input\_default\_routing\_table\_name) | Name of the Default Routing Table. If null, a name will be automatically generated. | `string` | `null` | no | +| [default\_security\_group\_name](#input\_default\_security\_group\_name) | Name of the Default Security Group. If null, a name will be automatically generated. | `string` | `null` | no | +| [disable\_access\_key\_creation](#input\_disable\_access\_key\_creation) | When set to true, disables the creation of a default manager access key which is required by agents to ingest metrics. | `bool` | `false` | no | +| [dual\_auth\_delete\_enabled](#input\_dual\_auth\_delete\_enabled) | If set to `true`, a dual authorization policy is enabled on the Key Protect instance. After the dual authorization policy is set on the instance, it cannot be reverted. An instance with dual authorization policy enabled cannot be destroyed by using Terraform. Only used if 'create\_key\_protect\_instance' is set to `true`. | `bool` | `false` | no | +| [enable\_activity\_tracker\_event\_routing\_to\_cloud\_logs](#input\_enable\_activity\_tracker\_event\_routing\_to\_cloud\_logs) | When set to `true`, you must provide a value for `existing_cloud_logs_crn` to enable event routing from Activity Tracker to a Cloud Logs instance. | `bool` | `true` | no | +| [enable\_activity\_tracker\_event\_routing\_to\_cos\_bucket](#input\_enable\_activity\_tracker\_event\_routing\_to\_cos\_bucket) | When set to `true`, you must provide a value for `existing_cos_instance_crn` to enable event routing from Activity Tracker to a Object Storage bucket. | `bool` | `true` | no | +| [enable\_metrics](#input\_enable\_metrics) | Set to `true` to enable metrics on the Key Protect instance. Only used if 'create\_key\_protect\_instance' is set to `true`. In order to view metrics, you need an IBM Cloud Monitoring (Sysdig) instance that is located in the same region as the Key Protect instance. After you provision a Monitoring instance, enable platform metrics to monitor your Key Protect instance. | `bool` | `true` | no | +| [enable\_metrics\_routing\_to\_cloud\_monitoring](#input\_enable\_metrics\_routing\_to\_cloud\_monitoring) | Whether to enable metrics routing from IBM Cloud Metric Routing to Cloud Monitoring. | `bool` | `true` | no | +| [enable\_platform\_metrics](#input\_enable\_platform\_metrics) | When set to `true`, the IBM Cloud Monitoring instance collects the platform metrics. | `bool` | `false` | no | +| [enable\_primary\_metadata\_region](#input\_enable\_primary\_metadata\_region) | When set to `true`, sets `primary_metadata_region` to `region`, storing Metrics Router metadata in that region. When `false`, no region is set and the default global region is used. For new accounts, creating targets and routes will fail until primary\_metadata\_region is set, so it is recommended to default enable\_primary\_metadata\_region to true. | `bool` | `true` | no | +| [enable\_vpc\_flow\_logs](#input\_enable\_vpc\_flow\_logs) | To enable VPC Flow logs, set this to true. | `bool` | `false` | no | +| [event\_notifications\_email\_list](#input\_event\_notifications\_email\_list) | The list of email address to target out when Secrets Manager triggers an event | `list(string)` | `[]` | no | +| [event\_notifications\_from\_email](#input\_event\_notifications\_from\_email) | The email address used to send any Secrets Manager event coming via Event Notifications | `string` | `"compliancealert@ibm.com"` | no | +| [event\_notifications\_reply\_to\_email](#input\_event\_notifications\_reply\_to\_email) | The email address specified in the 'reply\_to' section for any Secret Manager event coming via Event Notifications | `string` | `"no-reply@ibm.com"` | no | +| [existing\_activity\_tracker\_cos\_target\_bucket\_endpoint](#input\_existing\_activity\_tracker\_cos\_target\_bucket\_endpoint) | The name of an existing Cloud Object Storage bucket endpoint to use for setting up IBM Cloud Activity Tracker Event Routing. If an existing endpoint is not specified, the endpoint of the new Cloud Object Storage bucket is used. | `string` | `null` | no | +| [existing\_activity\_tracker\_cos\_target\_bucket\_name](#input\_existing\_activity\_tracker\_cos\_target\_bucket\_name) | The name of an existing bucket within the Cloud Object Storage instance in which to store IBM Cloud Activity Tracker Event Routing. If an existing Cloud Object Storage bucket is not specified, a bucket is created. | `string` | `null` | no | +| [existing\_boot\_volume\_kms\_key\_crn](#input\_existing\_boot\_volume\_kms\_key\_crn) | The CRN of an existing KMS key to use to encrypt the the block storage volumes for VPC. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key. | `string` | `null` | no | +| [existing\_cloud\_logs\_crn](#input\_existing\_cloud\_logs\_crn) | The CRN of an existing Cloud Logs instance. If not supplied, a new instance will be created. | `string` | `null` | no | +| [existing\_cloud\_monitoring\_crn](#input\_existing\_cloud\_monitoring\_crn) | The CRN of an existing Cloud Monitoring instance. If not supplied, a new instance will be created. | `string` | `null` | no | +| [existing\_cluster\_kms\_key\_crn](#input\_existing\_cluster\_kms\_key\_crn) | The CRN of an existing KMS key to use for encrypting the Object Storage of the Cluster. If no value is set for this variable, specify a value for `existing_kms_instance_crn` variable to create a key ring and key. | `string` | `null` | no | +| [existing\_cos\_instance\_crn](#input\_existing\_cos\_instance\_crn) | The CRN of an existing Object Storage instance. | `string` | `null` | no | +| [existing\_event\_notifications\_instance\_crn](#input\_existing\_event\_notifications\_instance\_crn) | The CRN of the Event Notifications service used to enable lifecycle notifications for your Secrets Manager instance. | `string` | `null` | no | +| [existing\_event\_notifications\_instances](#input\_existing\_event\_notifications\_instances) | List of Event Notifications instance details for routing critical events that occur in your IBM Cloud Logs. |
list(object({
crn = string
integration_name = optional(string)
skip_iam_auth_policy = optional(bool, false)
}))
| `[]` | no | +| [existing\_kms\_instance\_crn](#input\_existing\_kms\_instance\_crn) | The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). | `string` | `null` | no | +| [existing\_secrets\_manager\_crn](#input\_existing\_secrets\_manager\_crn) | The CRN of an existing Secrets Manager instance. If not supplied, a new instance is created. | `string` | `null` | no | +| [flow\_logs\_cos\_bucket\_archive\_days](#input\_flow\_logs\_cos\_bucket\_archive\_days) | The number of days before the `archive_type` rule action takes effect for the flow logs cloud object storage bucket. | `number` | `90` | no | +| [flow\_logs\_cos\_bucket\_archive\_type](#input\_flow\_logs\_cos\_bucket\_archive\_type) | The storage class or archive type you want the object to transition to in the flow logs cloud object storage bucket. | `string` | `"Glacier"` | no | +| [flow\_logs\_cos\_bucket\_default\_retention\_days](#input\_flow\_logs\_cos\_bucket\_default\_retention\_days) | The number of days that an object can remain unmodified in the flow logs cloud object storage bucket. | `number` | `90` | no | +| [flow\_logs\_cos\_bucket\_enable\_object\_versioning](#input\_flow\_logs\_cos\_bucket\_enable\_object\_versioning) | Set it to true if object versioning is enabled so that multiple versions of an object are retained in the flow logs cloud object storage bucket. Cannot be used if `flow_logs_cos_bucket_enable_retention` is true. | `bool` | `false` | no | +| [flow\_logs\_cos\_bucket\_enable\_permanent\_retention](#input\_flow\_logs\_cos\_bucket\_enable\_permanent\_retention) | Whether permanent retention status is enabled for the flow logs cloud object storage bucket. | `bool` | `false` | no | +| [flow\_logs\_cos\_bucket\_enable\_retention](#input\_flow\_logs\_cos\_bucket\_enable\_retention) | Set to true to enable retention for the flow logs cloud object storage bucket. | `bool` | `false` | no | +| [flow\_logs\_cos\_bucket\_expire\_days](#input\_flow\_logs\_cos\_bucket\_expire\_days) | The number of days before the expire rule action takes effect for the flow logs cloud object storage bucket. | `number` | `366` | no | +| [flow\_logs\_cos\_bucket\_maximum\_retention\_days](#input\_flow\_logs\_cos\_bucket\_maximum\_retention\_days) | The maximum number of days that an object can be kept unmodified in the flow logs cloud object storage. | `number` | `350` | no | +| [flow\_logs\_cos\_bucket\_minimum\_retention\_days](#input\_flow\_logs\_cos\_bucket\_minimum\_retention\_days) | The minimum number of days that an object must be kept unmodified in the flow logs cloud object storage. | `number` | `90` | no | +| [flow\_logs\_cos\_bucket\_name](#input\_flow\_logs\_cos\_bucket\_name) | Name of the Cloud Object Storage bucket to be created to collect VPC flow logs. | `string` | `"flow-logs-bucket"` | no | +| [key\_create\_import\_access\_enabled](#input\_key\_create\_import\_access\_enabled) | If set to `true`, a key create and import access policy is enabled on the instance of Key Protect. Only used if 'create\_key\_protect\_instance' is set to `true`. | `bool` | `true` | no | +| [key\_protect\_allowed\_network](#input\_key\_protect\_allowed\_network) | Allowed network types for the Key Protect instance. Possible values are 'private-only', or 'public-and-private'. Only used if 'create\_key\_protect\_instance' is set to `true`. | `string` | `"private-only"` | no | +| [kms\_access\_tags](#input\_kms\_access\_tags) | A list of access tags to apply to the Key Protect instance. Only used if 'create\_key\_protect\_instance' is set to `true`. | `list(string)` | `[]` | no | +| [kms\_cbr\_rules](#input\_kms\_cbr\_rules) | The context-based restrictions rule to create. Only one rule is allowed. |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [kms\_encryption\_enabled\_boot\_volume](#input\_kms\_encryption\_enabled\_boot\_volume) | Set this to true to control the encryption keys used to encrypt the data that for the block storage volumes for VPC. If set to false, the data is encrypted by using randomly generated keys. For more info on encrypting block storage volumes, see https://cloud.ibm.com/docs/vpc?topic=vpc-creating-instances-byok | `bool` | `false` | no | +| [kms\_encryption\_enabled\_buckets](#input\_kms\_encryption\_enabled\_buckets) | Set to true to enable KMS encryption on the Object Storage buckets created for the IBM Cloud Logs instance. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_cloud_logs_crn`. | `bool` | `false` | no | +| [kms\_encryption\_enabled\_cluster](#input\_kms\_encryption\_enabled\_cluster) | Set to true to enable KMS encryption for the cluster's Object Storage bucket. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn`. | `bool` | `false` | no | +| [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_cluster` is true | `string` | `"private"` | no | +| [kms\_instance\_name](#input\_kms\_instance\_name) | The name to give the Key Protect instance that that is created by this module. Only used if 'create\_key\_protect\_instance' is set to `true`. | `string` | `"key-protect"` | no | +| [kms\_plan](#input\_kms\_plan) | Plan for the Key Protect instance. Supported values are 'tiered-pricing' and 'cross-region-resiliency'. Only used if 'create\_key\_protect\_instance' is set to `true`. | `string` | `"tiered-pricing"` | no | +| [kms\_resource\_tags](#input\_kms\_resource\_tags) | Optional list of tags to add to the Key Protect instance. Only used if 'create\_key\_protect\_instance' is set to `true`. | `list(string)` | `[]` | no | +| [logs\_policies](#input\_logs\_policies) | Configuration of Cloud Logs policies. |
list(object({
logs_policy_name = string
logs_policy_description = optional(string, null)
logs_policy_priority = string
application_rule = optional(list(object({
name = string
rule_type_id = string
})))
subsystem_rule = optional(list(object({
name = string
rule_type_id = string
})))
log_rules = optional(list(object({
severities = list(string)
})))
archive_retention = optional(list(object({
id = string
})))
}))
| `[]` | no | +| [logs\_routing\_tenant\_regions](#input\_logs\_routing\_tenant\_regions) | Pass a list of regions to create a tenant for that is targeted to the Cloud Logs instance created by this module. To manage platform logs that are generated by IBM Cloud® services in a region of IBM Cloud, you must create a tenant in each region that you operate. Leave the list empty if you don't want to create any tenants. NOTE: You can only have 1 tenant per region in an account. | `list(any)` | `[]` | no | +| [management\_endpoint\_type\_for\_buckets](#input\_management\_endpoint\_type\_for\_buckets) | The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`, `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. | `string` | `"direct"` | no | +| [metrics\_router\_routes](#input\_metrics\_router\_routes) | Routes for IBM Cloud Metrics Routing. |
list(object({
name = string
rules = list(object({
action = string
targets = list(object({
id = string
}))
inclusion_filters = list(object({
operand = string
operator = string
values = list(string)
}))
}))
}))
| `[]` | no | +| [metrics\_routing\_route\_name](#input\_metrics\_routing\_route\_name) | The name of the IBM Cloud Metrics Routing route for the default route that indicate what metrics are routed in a region and where to store them. If the prefix variable is passed, the name of the target is prefixed to the value in the `-value` format. | `string` | `"metrics-routing-route"` | no | +| [metrics\_routing\_target\_name](#input\_metrics\_routing\_target\_name) | The name of the IBM Cloud Metrics Routing target where metrics are collected. If the prefix variable is passed, the name of the target is prefixed to the value in the `-value` format. | `string` | `"cloud-monitoring-target"` | no | +| [network\_acls](#input\_network\_acls) | The list of ACLs to create. Provide at least one rule for each ACL. |
list(
object({
name = string
add_ibm_cloud_internal_rules = optional(bool)
add_vpc_connectivity_rules = optional(bool)
prepend_ibm_rules = optional(bool)
rules = list(
object({
name = string
action = string
destination = string
direction = string
source = string
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
source_port_max = optional(number)
source_port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
source_port_max = optional(number)
source_port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
})
)
|
[
{
"add_ibm_cloud_internal_rules": true,
"add_vpc_connectivity_rules": true,
"name": "vpc-acl",
"prepend_ibm_rules": true,
"rules": [
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-443-inbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 443,
"port_min": 443,
"source_port_max": 443,
"source_port_min": 443
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-80-inbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 80,
"port_min": 80,
"source_port_max": 80,
"source_port_min": 80
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-22-inbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 22,
"port_min": 22,
"source_port_max": 22,
"source_port_min": 22
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-443-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 443,
"port_min": 443,
"source_port_max": 443,
"source_port_min": 443
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-80-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 80,
"port_min": 80,
"source_port_max": 80,
"source_port_min": 80
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-22-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 22,
"port_min": 22,
"source_port_max": 22,
"source_port_min": 22
}
}
]
}
]
| no | +| [prefix](#input\_prefix) | The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To skip using a prefix, set this value to null or an empty string. | `string` | n/a | yes | +| [region](#input\_region) | The region to provision all resources in. | `string` | `"us-south"` | no | +| [resource\_group\_id](#input\_resource\_group\_id) | The ID of an existing IBM Cloud resource group where the cluster is grouped. | `string` | n/a | yes | +| [rotation\_enabled](#input\_rotation\_enabled) | If set to `true`, a rotation policy is enabled on the Key Protect instance. Only used if 'create\_key\_protect\_instance' is set to `true`. | `bool` | `true` | no | +| [rotation\_interval\_month](#input\_rotation\_interval\_month) | Specifies how often keys are rotated in months. Value must be between `1` and `12` inclusive. Only used if 'create\_key\_protect\_instance' is set to `true`. | `number` | `1` | no | +| [routes](#input\_routes) | Allows you to specify the next hop for packets based on their destination address. |
list(
object({
name = string
route_direct_link_ingress = optional(bool)
route_transit_gateway_ingress = optional(bool)
route_vpc_zone_ingress = optional(bool)
routes = optional(
list(
object({
action = optional(string)
zone = number
destination = string
next_hop = string
})
))
})
)
| `[]` | no | +| [scc\_workload\_protection\_access\_tags](#input\_scc\_workload\_protection\_access\_tags) | A list of access tags to apply to the Workload Protection instance. Maximum length: 128 characters. Possible characters are A-Z, 0-9, spaces, underscores, hyphens, periods, and colons. | `list(string)` | `[]` | no | +| [scc\_workload\_protection\_instance\_name](#input\_scc\_workload\_protection\_instance\_name) | The name for the Workload Protection instance that is created by this solution. Must begin with a letter. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"scc-workload-protection"` | no | +| [scc\_workload\_protection\_instance\_tags](#input\_scc\_workload\_protection\_instance\_tags) | The list of tags to add to the Workload Protection instance. | `list(string)` | `[]` | no | +| [scc\_workload\_protection\_resource\_key\_tags](#input\_scc\_workload\_protection\_resource\_key\_tags) | The tags associated with the Workload Protection resource key. | `list(string)` | `[]` | no | +| [scc\_workload\_protection\_service\_plan](#input\_scc\_workload\_protection\_service\_plan) | The pricing plan for the Workload Protection instance service. Possible values: `free-trial`, `graduated-tier`. | `string` | `"graduated-tier"` | no | +| [scc\_workload\_protection\_trusted\_profile\_name](#input\_scc\_workload\_protection\_trusted\_profile\_name) | The name to give the trusted profile that is created by this module if `cspm_enabled` is `true. Must begin with a letter. If a prefix input variable is specified, the prefix is added to the name in the `-` format.` | `string` | `"workload-protection-trusted-profile"` | no | +| [scc\_wp\_cbr\_rules](#input\_scc\_wp\_cbr\_rules) | The list of context-based restriction rules to create for the instance. |
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 | +| [secret\_groups](#input\_secret\_groups) | Secret Manager secret group and access group configurations. If a prefix input variable is specified, it is added to the `access_group_name` value in the `-value` format. If you do not wish to create any groups, set the value to `[]`. |
list(object({
secret_group_name = string
secret_group_description = optional(string)
create_access_group = optional(bool, true)
access_group_name = optional(string)
access_group_roles = optional(list(string), ["SecretsReader"])
access_group_tags = optional(list(string))
}))
|
[
{
"access_group_name": "general-secrets-group-access-group",
"access_group_roles": [
"SecretsReader"
],
"create_access_group": true,
"secret_group_description": "A general purpose secrets group with an associated access group which has a secrets reader role",
"secret_group_name": "General"
}
]
| no | +| [secrets\_manager\_allowed\_network](#input\_secrets\_manager\_allowed\_network) | The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`. | `string` | `"private-only"` | no | +| [secrets\_manager\_cbr\_rules](#input\_secrets\_manager\_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
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [secrets\_manager\_endpoint\_type](#input\_secrets\_manager\_endpoint\_type) | The type of endpoint (public or private) to connect to the Secrets Manager API. The Terraform provider uses this endpoint type to interact with the Secrets Manager API and configure Event Notifications. | `string` | `"private"` | no | +| [secrets\_manager\_instance\_name](#input\_secrets\_manager\_instance\_name) | The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format. Applies only if `existing_secrets_manager_crn` is not provided. | `string` | `"secrets-manager"` | no | +| [secrets\_manager\_resource\_tags](#input\_secrets\_manager\_resource\_tags) | The list of resource tags you want to associate with your Secrets Manager instance. Applies only if `existing_secrets_manager_crn` is not provided. | `list(string)` | `[]` | no | +| [secrets\_manager\_service\_plan](#input\_secrets\_manager\_service\_plan) | The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. You can create only one Trial instance of Secrets Manager per account. Before you can create a new Trial instance, you must delete the existing Trial instance and its reclamation. | `string` | `"standard"` | no | +| [security\_group\_rules](#input\_security\_group\_rules) | A list of security group rules to be added to the default vpc security group (default empty). |
list(
object({
name = string
direction = string
remote = optional(string)
local = optional(string)
ip_version = optional(string)
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
| `[]` | no | +| [service\_cred](#input\_service\_cred) | Service configuration for COS. |
list(object({
secret_group_name = string # pragma: allowlist secret
secret_group_description = optional(string) # pragma: allowlist secret
existing_secret_group = optional(bool) # pragma: allowlist secret
service_credentials = list(object({ # pragma: allowlist secret
secret_name = string # pragma: allowlist secret
service_credentials_source_service_role_crn = string # pragma: allowlist secret
secret_labels = optional(list(string)) # pragma: allowlist secret
secret_auto_rotation = optional(bool) # pragma: allowlist secret
secret_auto_rotation_unit = optional(string) # pragma: allowlist secret
secret_auto_rotation_interval = optional(number) # pragma: allowlist secret
service_credentials_ttl = optional(string) # pragma: allowlist secret
service_credential_secret_description = optional(string) # pragma: allowlist secret

}))
}))
| `[]` | no | +| [skip\_activity\_tracker\_cos\_auth\_policy](#input\_skip\_activity\_tracker\_cos\_auth\_policy) | To skip creating an IAM authorization policy that allows the Activity Tracker to write to the Cloud Object Storage instance, set this variable to `true`. | `bool` | `false` | no | +| [skip\_cloud\_logs\_cos\_auth\_policy](#input\_skip\_cloud\_logs\_cos\_auth\_policy) | To skip creating an IAM authorization policy that allows the IBM Cloud logs to write to the Cloud Object Storage bucket, set this variable to `true`. | `bool` | `false` | no | +| [skip\_logs\_routing\_auth\_policy](#input\_skip\_logs\_routing\_auth\_policy) | Whether to create an IAM authorization policy that permits the Logs Routing server 'Sender' access to the IBM Cloud Logs instance created by this Deployable Architecture. | `bool` | `false` | no | +| [skip\_secrets\_manager\_cos\_iam\_auth\_policy](#input\_skip\_secrets\_manager\_cos\_iam\_auth\_policy) | Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Cloud Object Storage. Set to `true` to use an existing policy. | `bool` | `false` | no | +| [skip\_secrets\_manager\_event\_notifications\_iam\_auth\_policy](#input\_skip\_secrets\_manager\_event\_notifications\_iam\_auth\_policy) | If set to true, this skips the creation of a service to service authorization from Secrets Manager to Event Notifications. If false, the service to service authorization is created. | `bool` | `false` | no | +| [skip\_secrets\_manager\_iam\_auth\_policy](#input\_skip\_secrets\_manager\_iam\_auth\_policy) | Whether to skip the creation of the IAM authorization policies required to enable the IAM credentials engine (if you are using an existing Secrets Manager instance, attempting to re-create can cause conflicts if the policies already exist). If set to false, policies will be created that grants the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manage' access to the IAM groups service. | `bool` | `false` | no | +| [skip\_secrets\_manager\_kms\_iam\_auth\_policy](#input\_skip\_secrets\_manager\_kms\_iam\_auth\_policy) | Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. | `bool` | `false` | no | +| [skip\_vpc\_cos\_iam\_auth\_policy](#input\_skip\_vpc\_cos\_iam\_auth\_policy) | To skip creating an IAM authorization policy that allows the VPC to access the Cloud Object Storage, set this variable to `true`. Required only if `enable_vpc_flow_logs` is set to true. | `bool` | `false` | no | +| [subnets](#input\_subnets) | List of subnets for the vpc. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total ipv4 addresses. Public gateways will be enabled only in zones where a gateway has been createds. |
object({
zone-1 = list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
}))
zone-2 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
})))
zone-3 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
})))
})
|
{
"zone-1": [
{
"acl_name": "vpc-acl",
"cidr": "10.10.10.0/24",
"name": "subnet-a",
"no_addr_prefix": false,
"public_gateway": true
}
],
"zone-2": [
{
"acl_name": "vpc-acl",
"cidr": "10.20.10.0/24",
"name": "subnet-b",
"no_addr_prefix": false,
"public_gateway": true
}
],
"zone-3": [
{
"acl_name": "vpc-acl",
"cidr": "10.30.10.0/24",
"name": "subnet-c",
"no_addr_prefix": false,
"public_gateway": true
}
]
}
| no | +| [vpc\_access\_tags](#input\_vpc\_access\_tags) | The list of access tags to add to the VPC instance. | `list(string)` | `[]` | no | +| [vpc\_flow\_logs\_access\_tags](#input\_vpc\_flow\_logs\_access\_tags) | The list of access tags to add to the VPC instance. | `list(string)` | `[]` | no | +| [vpc\_name](#input\_vpc\_name) | Name of the VPC. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"vpc"` | no | +| [vpc\_resource\_tags](#input\_vpc\_resource\_tags) | The list of tags to add to the VPC instance. | `list(string)` | `[]` | no | +| [vpe\_gateway\_cloud\_service\_by\_crn](#input\_vpe\_gateway\_cloud\_service\_by\_crn) | The list of cloud service CRNs used to create endpoint gateways. Use this list to identify services that are not supported by service name in the `cloud_services` variable. For a list of supported services, see [VPE-enabled services](https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-supported-services). If `service_name` is not specified, the CRN is used to find the name. If `vpe_name` is not specified in the list, VPE names are created in the format `--`. |
set(
object({
crn = string
vpe_name = optional(string) # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name.
service_name = optional(string) # Name of the service used to compute the name of the VPE. If not specified, the service name will be obtained from the crn.
allow_dns_resolution_binding = optional(bool, true)
})
)
| `[]` | no | +| [vpe\_gateway\_cloud\_services](#input\_vpe\_gateway\_cloud\_services) | The list of cloud services used to create endpoint gateways. If `vpe_name` is not specified in the list, VPE names are created in the format `--`. |
set(object({
service_name = string
vpe_name = optional(string), # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name.
allow_dns_resolution_binding = optional(bool, false)
}))
| `[]` | no | +| [vpe\_gateway\_reserved\_ips](#input\_vpe\_gateway\_reserved\_ips) | Map of existing reserved IP names and values. Leave this value as default if you want to create new reserved ips, this value is used when a user passes their existing reserved ips created here and not attempt to recreate those. |
object({
name = optional(string) # reserved ip name
})
| `{}` | no | +| [vpe\_gateway\_security\_group\_ids](#input\_vpe\_gateway\_security\_group\_ids) | List of security group ids to attach to each endpoint gateway. | `list(string)` | `null` | no | +| [vpe\_gateway\_service\_endpoints](#input\_vpe\_gateway\_service\_endpoints) | Service endpoints to use to create endpoint gateways. Can be `public`, or `private`. | `string` | `"private"` | no | +| [vpn\_gateways](#input\_vpn\_gateways) | List of VPN Gateways to create. |
list(
object({
name = string
subnet_name = string # Do not include prefix, use same name as in `var.subnets`
mode = optional(string)
resource_group = optional(string)
access_tags = optional(list(string), [])
})
)
| `[]` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [activity\_tracker\_cos\_target\_bucket\_name](#output\_activity\_tracker\_cos\_target\_bucket\_name) | he name of the object storage bucket which is set as activity tracker event routing target to collect audit events. | +| [activity\_tracker\_routes](#output\_activity\_tracker\_routes) | The map of created Activity Tracker Event Routing routes | +| [activity\_tracker\_targets](#output\_activity\_tracker\_targets) | The map of created Activity Tracker Event Routing targets | +| [boot\_volume\_existing\_kms\_guid](#output\_boot\_volume\_existing\_kms\_guid) | The GUID for the boot volume encryption | +| [boot\_volume\_kms\_account\_id](#output\_boot\_volume\_kms\_account\_id) | The Account ID for the boot volume encryption | +| [boot\_volume\_kms\_key\_id](#output\_boot\_volume\_kms\_key\_id) | The Key ID for the boot volume encryption | +| [cloud\_logs\_crn](#output\_cloud\_logs\_crn) | The id of the provisioned IBM Cloud Logs instance. | +| [cloud\_logs\_guid](#output\_cloud\_logs\_guid) | The guid of the provisioned IBM Cloud Logs instance. | +| [cloud\_logs\_ingress\_endpoint](#output\_cloud\_logs\_ingress\_endpoint) | The public ingress endpoint of the provisioned IBM Cloud Logs instance. | +| [cloud\_logs\_ingress\_private\_endpoint](#output\_cloud\_logs\_ingress\_private\_endpoint) | The private ingress endpoint of the provisioned IBM Cloud Logs instance. | +| [cloud\_logs\_logs\_policies\_details](#output\_cloud\_logs\_logs\_policies\_details) | The details of the IBM Cloud logs policies created. | +| [cloud\_logs\_name](#output\_cloud\_logs\_name) | The name of the provisioned IBM Cloud Logs instance. | +| [cloud\_monitoring\_access\_key](#output\_cloud\_monitoring\_access\_key) | The IBM Cloud Monitoring access key for agents to use | +| [cloud\_monitoring\_access\_key\_name](#output\_cloud\_monitoring\_access\_key\_name) | The name of the IBM Cloud Monitoring access key for agents to use | +| [cloud\_monitoring\_crn](#output\_cloud\_monitoring\_crn) | The id of the provisioned IBM Cloud Monitoring instance. | +| [cloud\_monitoring\_guid](#output\_cloud\_monitoring\_guid) | The guid of the provisioned IBM Cloud Monitoring instance. | +| [cloud\_monitoring\_name](#output\_cloud\_monitoring\_name) | The name of the provisioned IBM Cloud Monitoring instance. | +| [cos\_instance\_crn](#output\_cos\_instance\_crn) | COS instance crn | +| [cos\_instance\_guid](#output\_cos\_instance\_guid) | COS instance guid | +| [cos\_instance\_id](#output\_cos\_instance\_id) | COS instance ID | +| [key\_protect\_id](#output\_key\_protect\_id) | Key Protect instance ID when an instance is created, otherwise null | +| [kms\_account\_id](#output\_kms\_account\_id) | The account ID of the KMS instance. | +| [kms\_config](#output\_kms\_config) | The KMS config needed for OCP cluster | +| [kms\_guid](#output\_kms\_guid) | Key Protect instance GUID or the KMS instance GUID if existing\_kms\_instance\_crn was set | +| [kms\_instance\_crn](#output\_kms\_instance\_crn) | The CRN of the Hyper Protect Crypto Service instance or Key Protect instance | +| [logs\_bucket\_crn](#output\_logs\_bucket\_crn) | Logs Cloud Object Storage bucket CRN | +| [metrics\_bucket\_crn](#output\_metrics\_bucket\_crn) | Metrics Cloud Object Storage bucket CRN | +| [network\_acls](#output\_network\_acls) | List of shortnames and IDs of network ACLs. | +| [private\_path\_subnet\_id](#output\_private\_path\_subnet\_id) | The IDs of the subnets. | +| [public\_gateways](#output\_public\_gateways) | Map of the public gateways by zone. | +| [scc\_workload\_protection\_api\_endpoint](#output\_scc\_workload\_protection\_api\_endpoint) | SCC Workload Protection API endpoint | +| [scc\_workload\_protection\_crn](#output\_scc\_workload\_protection\_crn) | SCC Workload Protection instance CRN | +| [scc\_workload\_protection\_id](#output\_scc\_workload\_protection\_id) | SCC Workload Protection instance ID | +| [scc\_workload\_protection\_ingestion\_endpoint](#output\_scc\_workload\_protection\_ingestion\_endpoint) | SCC Workload Protection instance ingestion endpoint | +| [scc\_workload\_protection\_name](#output\_scc\_workload\_protection\_name) | SCC Workload Protection instance name | +| [secrets\_manager\_crn](#output\_secrets\_manager\_crn) | CRN of the Secrets Manager instance | +| [secrets\_manager\_guid](#output\_secrets\_manager\_guid) | GUID of Secrets Manager instance | +| [secrets\_manager\_region](#output\_secrets\_manager\_region) | Region of the Secrets Manager instance | +| [subnet\_detail\_list](#output\_subnet\_detail\_list) | A list of subnets containing names, CIDR blocks, and zones. | +| [subnet\_detail\_map](#output\_subnet\_detail\_map) | A map of subnets containing IDs, CIDR blocks, and zones. | +| [subnet\_ids](#output\_subnet\_ids) | The IDs of the subnets. | +| [subnet\_zone\_list](#output\_subnet\_zone\_list) | A list of subnet IDs and subnet zones. | +| [vpc\_crn](#output\_vpc\_crn) | CRN of the VPC created. | +| [vpc\_flow\_logs](#output\_vpc\_flow\_logs) | Details of the VPC flow logs collector. | +| [vpc\_id](#output\_vpc\_id) | ID of the VPC created. | +| [vpc\_name](#output\_vpc\_name) | Name of the VPC created. | +| [vpe\_crn](#output\_vpe\_crn) | The CRN of the endpoint gateway. | +| [vpe\_ips](#output\_vpe\_ips) | The reserved IPs for endpoint gateways. | +| [vpn\_gateways\_data](#output\_vpn\_gateways\_data) | Details of VPN gateways data. | +| [vpn\_gateways\_name](#output\_vpn\_gateways\_name) | List of names of VPN gateways. | + diff --git a/modules/monolith/main.tf b/modules/monolith/main.tf new file mode 100644 index 000000000..e5a4551b3 --- /dev/null +++ b/modules/monolith/main.tf @@ -0,0 +1,708 @@ +################################################################################# +# KMS +################################################################################# + +module "existing_kms_crn_parser" { + count = var.existing_kms_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.2.0" + crn = var.existing_kms_instance_crn +} + +module "existing_cluster_kms_key_crn_parser" { + count = var.existing_cluster_kms_key_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.2.0" + crn = var.existing_cluster_kms_key_crn +} + +module "existing_boot_volume_kms_key_crn_parser" { + count = var.existing_boot_volume_kms_key_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.2.0" + crn = var.existing_boot_volume_kms_key_crn +} + +locals { + prefix = var.prefix != null ? trimspace(var.prefix) != "" ? "${var.prefix}-" : "" : "" + cluster_existing_kms_guid = var.existing_kms_instance_crn != null && var.kms_encryption_enabled_cluster ? module.existing_kms_crn_parser[0].service_instance : var.existing_cluster_kms_key_crn != null ? module.existing_cluster_kms_key_crn_parser[0].service_instance : var.kms_encryption_enabled_cluster ? module.kms[0].kms_guid : null + cluster_kms_account_id = var.existing_kms_instance_crn != null && var.kms_encryption_enabled_cluster ? module.existing_kms_crn_parser[0].account_id : var.existing_cluster_kms_key_crn != null ? module.existing_cluster_kms_key_crn_parser[0].account_id : var.kms_encryption_enabled_cluster ? module.kms[0].kms_account_id : null + cluster_kms_key_id = var.existing_kms_instance_crn != null && var.kms_encryption_enabled_cluster ? module.kms[0].keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].key_id : var.existing_cluster_kms_key_crn != null ? module.existing_cluster_kms_key_crn_parser[0].resource : var.kms_encryption_enabled_cluster ? module.kms[0].keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].key_id : null + cluster_kms_key_crn = var.kms_encryption_enabled_cluster ? module.kms[0].keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn : var.existing_cluster_kms_key_crn != null ? var.existing_boot_volume_kms_key_crn : var.kms_encryption_enabled_cluster ? module.kms[0].key_protect_crn : null + cluster_key_ring_name = "${local.prefix}${var.cluster_kms_key_ring_name}" + cluster_key_name = "${local.prefix}${var.cluster_kms_key_name}" + + boot_volume_key_ring_name = "${local.prefix}${var.boot_volume_kms_key_ring_name}" + boot_volume_key_name = "${local.prefix}${var.boot_volume_kms_key_name}" + boot_volume_existing_kms_guid = var.existing_kms_instance_crn != null && var.kms_encryption_enabled_boot_volume ? module.existing_kms_crn_parser[0].service_instance : var.existing_boot_volume_kms_key_crn != null ? module.existing_boot_volume_kms_key_crn_parser[0].service_instance : var.kms_encryption_enabled_cluster ? module.kms[0].kms_guid : null + boot_volume_kms_account_id = var.existing_kms_instance_crn != null && var.kms_encryption_enabled_boot_volume ? module.existing_kms_crn_parser[0].account_id : var.existing_boot_volume_kms_key_crn != null ? module.existing_boot_volume_kms_key_crn_parser[0].account_id : var.kms_encryption_enabled_cluster ? module.kms[0].kms_account_id : null + boot_volume_kms_key_id = var.existing_kms_instance_crn != null && var.kms_encryption_enabled_boot_volume ? module.kms[0].keys[format("%s.%s", local.boot_volume_key_ring_name, local.boot_volume_key_name)].key_id : var.existing_boot_volume_kms_key_crn != null ? module.existing_boot_volume_kms_key_crn_parser[0].resource : var.kms_encryption_enabled_boot_volume ? module.kms[0].keys[format("%s.%s", local.boot_volume_key_ring_name, local.boot_volume_key_name)].key_id : null + parsed_service_name = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_name : (var.existing_cluster_kms_key_crn != null ? module.existing_cluster_kms_key_crn_parser[0].service_name : null) + is_hpcs_key = local.parsed_service_name == "hs-crypto" ? true : false + + kms_config = var.kms_encryption_enabled_cluster ? { + crk_id = local.cluster_kms_key_id + instance_id = local.cluster_existing_kms_guid + private_endpoint = var.kms_endpoint_type == "private" ? true : false + account_id = local.cluster_kms_account_id + } : null + + keys = [ + var.kms_encryption_enabled_cluster ? { + key_ring_name = local.cluster_key_ring_name + existing_key_ring = false + keys = [ + { + key_name = local.cluster_key_name + standard_key = false + rotation_interval_month = 3 + dual_auth_delete_enabled = false + force_delete = true + } + ] + } : null, + var.kms_encryption_enabled_boot_volume ? { + key_ring_name = local.boot_volume_key_ring_name + existing_key_ring = false + keys = [ + { + key_name = local.boot_volume_key_name + standard_key = false + rotation_interval_month = 3 + dual_auth_delete_enabled = false + force_delete = true + } + ] + } : null + ] +} + +module "kms" { + count = (var.kms_encryption_enabled_boot_volume && var.existing_boot_volume_kms_key_crn == null) || (var.kms_encryption_enabled_cluster && var.existing_cluster_kms_key_crn == null) ? 1 : 0 + source = "terraform-ibm-modules/kms-all-inclusive/ibm" + version = "5.4.5" + resource_group_id = var.resource_group_id + region = var.region + create_key_protect_instance = var.existing_kms_instance_crn != null || var.existing_cluster_kms_key_crn != null || var.existing_boot_volume_kms_key_crn != null ? false : true + existing_kms_instance_crn = var.existing_kms_instance_crn + key_protect_instance_name = "${local.prefix}${var.kms_instance_name}" + key_protect_plan = var.kms_plan + rotation_enabled = var.rotation_enabled + rotation_interval_month = var.rotation_interval_month + dual_auth_delete_enabled = var.dual_auth_delete_enabled + enable_metrics = var.enable_metrics + key_create_import_access_enabled = var.key_create_import_access_enabled + key_protect_allowed_network = var.key_protect_allowed_network + key_ring_endpoint_type = var.kms_endpoint_type + key_endpoint_type = var.kms_endpoint_type + resource_tags = var.kms_resource_tags + access_tags = var.kms_access_tags + keys = [for key in local.keys : key if key != null] + cbr_rules = var.kms_cbr_rules +} + +################################################################################# +# Secrets Manager +################################################################################# + +locals { + enable_secrets_manager_cluster = var.existing_secrets_manager_crn == null ? true : false + parsed_existing_secrets_manager_crn = var.existing_secrets_manager_crn != null ? split(":", var.existing_secrets_manager_crn) : [] + secrets_manager_guid = var.existing_secrets_manager_crn != null ? (length(local.parsed_existing_secrets_manager_crn) > 0 ? local.parsed_existing_secrets_manager_crn[7] : null) : module.secrets_manager[0].secrets_manager_guid + secrets_manager_crn = var.existing_secrets_manager_crn != null ? var.existing_secrets_manager_crn : module.secrets_manager[0].secrets_manager_crn + secrets_manager_region = var.existing_secrets_manager_crn != null ? (length(local.parsed_existing_secrets_manager_crn) > 0 ? local.parsed_existing_secrets_manager_crn[5] : null) : module.secrets_manager[0].secrets_manager_region + enable_event_notifications = var.existing_event_notifications_instance_crn == null || var.existing_event_notifications_instance_crn == "" ? false : true + secret_groups_with_prefix = [ + for group in var.secret_groups : merge(group, { + access_group_name = group.access_group_name != null ? "${local.prefix}${group.access_group_name}" : null + }) + ] +} + +module "secrets_manager_crn_parser" { + count = var.existing_secrets_manager_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.3.0" + crn = var.existing_secrets_manager_crn +} + +module "secrets_manager" { + count = local.enable_secrets_manager_cluster ? 1 : 0 + source = "terraform-ibm-modules/secrets-manager/ibm" + version = "2.11.9" + existing_sm_instance_crn = var.existing_secrets_manager_crn + resource_group_id = var.resource_group_id + region = var.region + secrets_manager_name = "${local.prefix}${var.secrets_manager_instance_name}" + sm_service_plan = var.secrets_manager_service_plan + sm_tags = var.secrets_manager_resource_tags + skip_iam_authorization_policy = var.skip_secrets_manager_iam_auth_policy + # kms dependency + is_hpcs_key = local.is_hpcs_key + kms_encryption_enabled = var.kms_encryption_enabled_cluster + kms_key_crn = local.cluster_kms_key_crn + skip_kms_iam_authorization_policy = var.skip_secrets_manager_kms_iam_auth_policy #|| local.create_cross_account_auth_policy + # event notifications dependency + enable_event_notification = local.enable_event_notifications + existing_en_instance_crn = local.enable_event_notifications ? var.existing_event_notifications_instance_crn : null + skip_en_iam_authorization_policy = var.skip_secrets_manager_event_notifications_iam_auth_policy + cbr_rules = var.secrets_manager_cbr_rules + endpoint_type = var.secrets_manager_endpoint_type + allowed_network = var.secrets_manager_allowed_network + secrets = local.secret_groups_with_prefix +} + +################################################################################# +# Secrets Manager Event Notifications Configuration +################################################################################# + +locals { + parsed_existing_en_instance_crn = var.existing_event_notifications_instance_crn == null || var.existing_event_notifications_instance_crn == "" ? [] : split(":", var.existing_event_notifications_instance_crn) + existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null +} + +data "ibm_en_destinations" "en_destinations" { + # if existing SM instance CRN is passed (!= null), then never do data lookup for EN destinations + count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && local.enable_secrets_manager_cluster ? 1 : 0 + instance_guid = local.existing_en_guid +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5533 +resource "time_sleep" "wait_for_secrets_manager" { + # if existing SM instance CRN is passed (!= null), then never work with EN + count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && local.enable_secrets_manager_cluster ? 1 : 0 + depends_on = [module.secrets_manager] + + create_duration = "30s" +} + +resource "ibm_en_topic" "en_topic" { + # if existing SM instance CRN is passed (!= null), then never create EN topic + count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && local.enable_secrets_manager_cluster ? 1 : 0 + depends_on = [time_sleep.wait_for_secrets_manager] + instance_guid = local.existing_en_guid + name = "Topic for Secrets Manager instance ${module.secrets_manager[0].secrets_manager_guid}" + description = "Topic for Secrets Manager events routing" + sources { + id = local.secrets_manager_crn + rules { + enabled = true + event_type_filter = "$.*" + } + } +} + +resource "ibm_en_subscription_email" "email_subscription" { + # if existing SM instance CRN is passed (!= null), then never create EN email subscription + count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && length(var.event_notifications_email_list) > 0 && local.enable_secrets_manager_cluster ? 1 : 0 + instance_guid = local.existing_en_guid + name = "Email for Secrets Manager Subscription" + description = "Subscription for Secret Manager Events" + destination_id = [for s in toset(data.ibm_en_destinations.en_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_topic[count.index].topic_id + attributes { + add_notification_payload = true + reply_to_mail = var.event_notifications_reply_to_email + reply_to_name = "Secret Manager Event Notifications Bot" + from_name = var.event_notifications_from_email + invited = var.event_notifications_email_list + } +} + +################################################################################# +# COS +################################################################################# + +locals { + create_cos_instance = var.existing_cos_instance_crn == null ? true : false + existing_secrets_manager_instance_guid = var.existing_secrets_manager_crn != null ? module.secrets_manager_crn_parser[0].service_instance : local.enable_secrets_manager_cluster ? module.secrets_manager[0].secrets_manager_guid : "" + existing_secrets_manager_instance_region = var.existing_secrets_manager_crn != null ? module.secrets_manager_crn_parser[0].region : local.enable_secrets_manager_cluster ? module.secrets_manager[0].secrets_manager_region : "" + + service_credential_secrets = [ + for service_credentials in var.service_cred : { + 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_crn = secret.service_credentials_source_service_role_crn + service_credentials_source_service_crn = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].service_instance : module.cos[0].cos_instance_id + secret_type = "service_credentials" #checkov:skip=CKV_SECRET_6 + } + ] + } + ] +} + +module "existing_cos_instance_crn_parser" { + count = var.existing_cos_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.3.0" + crn = var.existing_cos_instance_crn +} + +module "cos" { + count = local.create_cos_instance != false ? 1 : 0 + source = "terraform-ibm-modules/cos/ibm//modules/fscloud" + version = "10.5.9" + resource_group_id = var.resource_group_id + create_cos_instance = local.create_cos_instance + cos_instance_name = "${local.prefix}${var.cos_instance_name}" + resource_keys = [] + cos_plan = var.cos_instance_plan + cos_tags = var.cos_instance_resource_tags + access_tags = var.cos_instance_access_tags + instance_cbr_rules = var.cos_instance_cbr_rules +} + +################################################################################# +# Secrets Manager service credentials for COS +################################################################################# + +# create s2s auth policy with Secrets Manager +resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { + count = !var.skip_secrets_manager_cos_iam_auth_policy && (var.existing_secrets_manager_crn != null || local.enable_secrets_manager_cluster) ? 1 : 0 + source_service_name = "secrets-manager" + source_resource_instance_id = local.existing_secrets_manager_instance_guid + target_service_name = "cloud-object-storage" + target_resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].service_instance : module.cos[0].cos_instance_guid + roles = ["Key Manager"] + description = "Allow Secrets Manager with instance id ${local.existing_secrets_manager_instance_guid} to manage key for the COS instance" +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_cos_authorization_policy" { + count = length(local.service_credential_secrets) > 0 ? 1 : 0 + depends_on = [ibm_iam_authorization_policy.secrets_manager_key_manager] + create_duration = "30s" +} + +module "secrets_manager_service_credentials" { + count = length(local.service_credential_secrets) > 0 ? 1 : 0 + depends_on = [time_sleep.wait_for_cos_authorization_policy] + source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets" + version = "2.11.9" + existing_sm_instance_guid = local.existing_secrets_manager_instance_guid + existing_sm_instance_region = local.existing_secrets_manager_instance_region + endpoint_type = var.secrets_manager_endpoint_type + secrets = local.service_credential_secrets +} + +################################################################################# +# Cloud Monitoring +################################################################################# + +module "existing_cloud_monitoring_crn_parser" { + count = var.existing_cloud_monitoring_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.3.0" + crn = var.existing_cloud_monitoring_crn +} + +locals { + create_cloud_monitoring = var.existing_cloud_monitoring_crn == null + cloud_monitoring_crn = local.create_cloud_monitoring ? module.cloud_monitoring[0].crn : var.existing_cloud_monitoring_crn + cloud_monitoring_instance_name = "${local.prefix}${var.cloud_monitoring_instance_name}" + metrics_router_target_name = "${local.prefix}${var.metrics_routing_target_name}" + metrics_router_route_name = "${local.prefix}${var.metrics_routing_route_name}" + + default_metrics_router_route = var.enable_metrics_routing_to_cloud_monitoring ? [{ + name = local.metrics_router_route_name + rules = [{ + action = "send" + targets = [{ + id = module.metrics_routing[0].metrics_router_targets[local.metrics_router_target_name].id + }] + inclusion_filters = [] + }] + }] : [] +} + +module "cloud_monitoring" { + count = local.create_cloud_monitoring ? 1 : 0 + source = "terraform-ibm-modules/cloud-monitoring/ibm" + version = "1.11.0" + resource_group_id = var.resource_group_id + region = var.region + instance_name = local.cloud_monitoring_instance_name + plan = var.cloud_monitoring_plan + resource_tags = var.cloud_monitoring_resource_tags + access_tags = var.cloud_monitoring_access_tags + resource_keys = var.cloud_monitoring_resource_keys + disable_access_key_creation = var.disable_access_key_creation + service_endpoints = "public-and-private" + enable_platform_metrics = var.enable_platform_metrics + cbr_rules = var.cloud_monitoring_cbr_rules +} + +module "metrics_routing" { + count = var.enable_metrics_routing_to_cloud_monitoring ? 1 : 0 + source = "terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing" + version = "1.11.0" + metrics_router_targets = [ + { + destination_crn = local.cloud_monitoring_crn + target_name = local.metrics_router_target_name + target_region = var.region + skip_metrics_router_auth_policy = false + } + ] + + metrics_router_routes = length(var.metrics_router_routes) != 0 ? var.metrics_router_routes : local.default_metrics_router_route + metrics_router_settings = var.enable_primary_metadata_region ? { primary_metadata_region = var.region } : null +} + +################################################################################# +# Cloud Logs +################################################################################# + +locals { + cloud_logs_instance_name = "${local.prefix}${var.cloud_logs_instance_name}" + create_cloud_logs = var.existing_cloud_logs_crn == null + cloud_logs_crn = local.create_cloud_logs ? module.cloud_logs[0].crn : var.existing_cloud_logs_crn + + data_bucket_name = "${local.prefix}${var.cloud_logs_data_cos_bucket_name}" + metrics_bucket_name = "${local.prefix}${var.cloud_logs_metrics_cos_bucket_name}" + cos_instance_guid = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].service_instance : module.cos[0].cos_instance_guid +} + +module "cloud_logs" { + depends_on = [time_sleep.wait_for_cos_authorization_policy[0]] + count = local.create_cloud_logs ? 1 : 0 + source = "terraform-ibm-modules/cloud-logs/ibm" + version = "1.10.0" + resource_group_id = var.resource_group_id + region = var.region + instance_name = local.cloud_logs_instance_name + plan = "standard" # not a variable because there is only one option + resource_tags = var.cloud_logs_resource_tags + access_tags = var.cloud_logs_access_tags + retention_period = var.cloud_logs_retention_period + service_endpoints = "public-and-private" # not a variable because there is only one option + existing_event_notifications_instances = var.existing_event_notifications_instances + cbr_rules = var.cloud_logs_cbr_rules + data_storage = { + logs_data = { + enabled = true + bucket_crn = module.cloud_logs_buckets.buckets[local.data_bucket_name].bucket_crn + bucket_endpoint = module.cloud_logs_buckets.buckets[local.data_bucket_name].s3_endpoint_direct + skip_cos_auth_policy = var.skip_cloud_logs_cos_auth_policy + }, + metrics_data = { + enabled = true + bucket_crn = module.cloud_logs_buckets.buckets[local.metrics_bucket_name].bucket_crn + bucket_endpoint = module.cloud_logs_buckets.buckets[local.metrics_bucket_name].s3_endpoint_direct + skip_cos_auth_policy = var.skip_cloud_logs_cos_auth_policy + } + } + logs_routing_tenant_regions = var.logs_routing_tenant_regions + skip_logs_routing_auth_policy = var.skip_logs_routing_auth_policy + policies = var.logs_policies +} + +module "cloud_logs_buckets" { + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.7" + bucket_configs = [ + { + bucket_name = local.data_bucket_name + kms_key_crn = var.kms_encryption_enabled_buckets ? local.cluster_kms_key_crn : null + kms_guid = var.kms_encryption_enabled_buckets ? local.cluster_existing_kms_guid : null + kms_encryption_enabled = var.kms_encryption_enabled_buckets + region_location = var.region + resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id + add_bucket_name_suffix = var.append_random_bucket_name_suffix + management_endpoint_type = var.management_endpoint_type_for_buckets + storage_class = var.cloud_logs_cos_buckets_class + force_delete = true # If this is set to false, and the bucket contains data, the destroy will fail. Setting it to false on destroy has no impact, it has to be set on apply, so hence hard coding to true." + activity_tracking = { + read_data_events = true + write_data_events = true + management_events = true + } + metrics_monitoring = { + usage_metrics_enabled = true + request_metrics_enabled = true + metrics_monitoring_crn = var.existing_cloud_monitoring_crn != null ? var.existing_cloud_monitoring_crn : module.cloud_monitoring[0].crn + } + }, + { + bucket_name = local.metrics_bucket_name + kms_key_crn = var.kms_encryption_enabled_buckets ? local.cluster_kms_key_crn : null + kms_guid = var.kms_encryption_enabled_buckets ? local.cluster_existing_kms_guid : null + kms_encryption_enabled = var.kms_encryption_enabled_buckets + region_location = var.region + resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id + add_bucket_name_suffix = var.append_random_bucket_name_suffix + management_endpoint_type = var.management_endpoint_type_for_buckets + storage_class = var.cloud_logs_cos_buckets_class + skip_iam_authorization_policy = true + force_delete = true # If this is set to false, and the bucket contains data, the destroy will fail. Setting it to false on destroy has no impact, it has to be set on apply, so hence hard coding to true." + activity_tracking = { + read_data_events = true + write_data_events = true + management_events = true + } + metrics_monitoring = { + usage_metrics_enabled = true + request_metrics_enabled = true + metrics_monitoring_crn = var.existing_cloud_monitoring_crn != null ? var.existing_cloud_monitoring_crn : module.cloud_monitoring[0].crn + } + } + ] +} + +################################################################################# +# Activity Tracker +################################################################################# +locals { + activity_tracker_cos_target_bucket_name = try("${local.prefix}${var.activity_tracker_cos_target_bucket_name}", var.activity_tracker_cos_target_bucket_name) + cos_target_bucket_name = var.existing_activity_tracker_cos_target_bucket_name != null ? var.existing_activity_tracker_cos_target_bucket_name : var.enable_activity_tracker_event_routing_to_cos_bucket ? module.at_cos_bucket[0].buckets[local.activity_tracker_cos_target_bucket_name].bucket_name : null + cos_target_bucket_endpoint = var.existing_activity_tracker_cos_target_bucket_endpoint != null ? var.existing_activity_tracker_cos_target_bucket_endpoint : var.enable_activity_tracker_event_routing_to_cos_bucket ? module.at_cos_bucket[0].buckets[local.activity_tracker_cos_target_bucket_name].s3_endpoint_private : null + cos_target_name = var.cos_target_name != null ? var.cos_target_name : local.create_cos_instance ? module.cos[0].cos_instance_name : try("${local.prefix}-cos-target", "cos-target") + cloud_logs_target_name = var.cloud_logs_target_name != null ? var.cloud_logs_target_name : local.create_cos_instance ? module.cos[0].cos_instance_name : try("${local.prefix}-cloud-logs-target", "cloud-logs-target") + activity_tracker_cos_route_name = var.activity_tracker_cos_route_name != null ? var.activity_tracker_cos_route_name : try("${local.prefix}at-cos-route", "at-cos-route") + activity_tracker_cloud_logs_route_name = var.activity_tracker_cloud_logs_route_name != null ? var.activity_tracker_cloud_logs_route_name : try("${local.prefix}at-cloud-logs-route", "at-cloud-logs-route") + activity_tracker_bucket_config = var.existing_activity_tracker_cos_target_bucket_name == null && var.enable_activity_tracker_event_routing_to_cos_bucket ? { + class = var.activity_tracker_cos_target_bucket_class + name = local.activity_tracker_cos_target_bucket_name + tag = var.activity_tracker_cos_bucket_access_tags + } : null + + + bucket_retention_configs = local.activity_tracker_bucket_config != null ? { (local.activity_tracker_cos_target_bucket_name) = var.activity_tracker_cos_bucket_retention_policy } : null + + at_buckets_config = local.activity_tracker_bucket_config != null ? [local.activity_tracker_bucket_config] : [] + + archive_rule = length(local.at_buckets_config) != 0 ? { + enable = true + days = 90 + type = "Glacier" + } : null + + expire_rule = length(local.at_buckets_config) != 0 ? { + enable = true + days = 366 + } : null + + activity_tracker_cos_route = var.enable_activity_tracker_event_routing_to_cos_bucket ? [{ + route_name = local.activity_tracker_cos_route_name + locations = ["*"] + target_ids = [module.activity_tracker.activity_tracker_targets[local.cos_target_name].id] + }] : [] + + activity_tracker_cloud_logs_route = var.enable_activity_tracker_event_routing_to_cloud_logs ? [{ + route_name = local.activity_tracker_cloud_logs_route_name + locations = ["*"] + target_ids = [module.activity_tracker.activity_tracker_targets[local.cloud_logs_target_name].id] + }] : [] + activity_tracker_routes = concat(local.activity_tracker_cos_route, local.activity_tracker_cloud_logs_route) + +} + +module "activity_tracker" { + source = "terraform-ibm-modules/activity-tracker/ibm" + version = "1.5.0" + cos_targets = var.enable_activity_tracker_event_routing_to_cos_bucket ? [ + { + bucket_name = local.cos_target_bucket_name + endpoint = local.cos_target_bucket_endpoint + instance_id = var.existing_cos_instance_crn != null ? var.existing_cos_instance_crn : module.cos[0].cos_instance_crn + target_region = var.region + target_name = local.cos_target_name + skip_atracker_cos_iam_auth_policy = var.skip_activity_tracker_cos_auth_policy + service_to_service_enabled = true + } + ] : [] + + cloud_logs_targets = var.enable_activity_tracker_event_routing_to_cloud_logs ? [ + { + instance_id = var.existing_cloud_logs_crn != null ? var.existing_cloud_logs_crn : module.cloud_logs[0].crn + target_region = var.region + target_name = local.cloud_logs_target_name + } + ] : [] + + # Routes + activity_tracker_routes = local.activity_tracker_routes +} + +module "at_cos_bucket" { + count = length(coalesce(local.at_buckets_config, [])) != 0 ? 1 : 0 # no need to call COS module if consumer is using existing COS bucket + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.8" + bucket_configs = [ + for value in local.at_buckets_config : + { + access_tags = value.tag + bucket_name = value.name + add_bucket_name_suffix = var.append_random_bucket_name_suffix + kms_guid = local.cluster_existing_kms_guid + kms_encryption_enabled = var.kms_encryption_enabled_buckets + kms_key_crn = local.cluster_kms_key_crn + skip_iam_authorization_policy = false + management_endpoint_type = var.management_endpoint_type_for_buckets + storage_class = value.class + resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id + region_location = var.region + force_delete = true + archive_rule = local.archive_rule + expire_rule = local.expire_rule + retention_rule = lookup(local.bucket_retention_configs, value.name, null) + metrics_monitoring = { + usage_metrics_enabled = true + request_metrics_enabled = true + # If `existing_monitoring_crn` is not passed, metrics are sent to the instance associated to the container's location unless otherwise specified in the Metrics Router service configuration. + metrics_monitoring_crn = var.existing_cloud_monitoring_crn != null ? var.existing_cloud_monitoring_crn : module.cloud_monitoring[0].crn + } + activity_tracking = { + read_data_events = true + write_data_events = true + management_events = true + } + } + ] +} + +################################################################################# +# SCC Workload Protection +################################################################################# + +locals { + scc_workload_protection_instance_name = "${local.prefix}${var.scc_workload_protection_instance_name}" + scc_workload_protection_resource_key_name = "${local.prefix}${var.scc_workload_protection_instance_name}-key" +} + +module "scc_wp" { + source = "terraform-ibm-modules/scc-workload-protection/ibm" + version = "1.16.4" + name = local.scc_workload_protection_instance_name + region = var.region + resource_group_id = var.resource_group_id + resource_tags = var.scc_workload_protection_instance_tags + resource_key_name = local.scc_workload_protection_resource_key_name + resource_key_tags = var.scc_workload_protection_resource_key_tags + cloud_monitoring_instance_crn = var.existing_cloud_monitoring_crn != null ? var.existing_cloud_monitoring_crn : module.cloud_monitoring[0].crn + access_tags = var.scc_workload_protection_access_tags + scc_wp_service_plan = var.scc_workload_protection_service_plan + app_config_crn = var.app_config_crn + scc_workload_protection_trusted_profile_name = "${local.prefix}${var.scc_workload_protection_trusted_profile_name}" + cbr_rules = var.scc_wp_cbr_rules + cspm_enabled = var.cspm_enabled +} + + + +############################################################################# +# COS Bucket for VPC flow logs +############################################################################# + + +locals { + vpc_flow_logs_bucket_name = "${local.prefix}${var.flow_logs_cos_bucket_name}" + # configuration for the flow logs bucket + flow_logs_bucket_config = [{ + access_tags = var.vpc_flow_logs_access_tags + bucket_name = local.vpc_flow_logs_bucket_name + add_bucket_name_suffix = var.append_random_bucket_name_suffix + kms_encryption_enabled = var.kms_encryption_enabled_buckets + kms_guid = local.cluster_existing_kms_guid + kms_key_crn = local.cluster_kms_key_crn + skip_iam_authorization_policy = true + management_endpoint_type = var.management_endpoint_type_for_buckets + storage_class = var.cloud_logs_cos_buckets_class + resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id + region_location = var.region + force_delete = true + archive_rule = var.flow_logs_cos_bucket_archive_days != null ? { + enable = true + days = var.flow_logs_cos_bucket_archive_days + type = var.flow_logs_cos_bucket_archive_type + } : null + expire_rule = var.flow_logs_cos_bucket_expire_days != null ? { + enable = true + days = var.flow_logs_cos_bucket_expire_days + } : null + retention_rule = var.flow_logs_cos_bucket_enable_retention ? { + default = var.flow_logs_cos_bucket_default_retention_days + maximum = var.flow_logs_cos_bucket_maximum_retention_days + minimum = var.flow_logs_cos_bucket_minimum_retention_days + permanent = var.flow_logs_cos_bucket_enable_permanent_retention + } : null + object_versioning_enabled = var.flow_logs_cos_bucket_enable_object_versioning + }] +} + +# Create COS bucket using the defined bucket configuration +module "vpc_cos_buckets" { + count = var.enable_vpc_flow_logs ? 1 : 0 + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.8" + bucket_configs = local.flow_logs_bucket_config +} + +############################################################################# +# VPC +############################################################################# + +locals { + # create 'use_public_gateways' object + public_gateway_object = { + for key, value in var.subnets : key => value != null ? length([for sub in value : sub.public_gateway if sub.public_gateway]) > 0 ? [for sub in value : sub.public_gateway if sub.public_gateway][0] : false : false + } +} + +# Create VPC +module "vpc" { + source = "terraform-ibm-modules/landing-zone-vpc/ibm" + version = "8.9.1" + resource_group_id = var.resource_group_id + region = var.region + create_vpc = true + name = var.vpc_name + prefix = local.prefix != "" ? trimspace(var.prefix) : null + tags = var.vpc_resource_tags + access_tags = var.vpc_access_tags + subnets = var.subnets + default_network_acl_name = var.default_network_acl_name + default_security_group_name = var.default_security_group_name + default_routing_table_name = var.default_routing_table_name + network_acls = var.network_acls + security_group_rules = var.security_group_rules + clean_default_sg_acl = var.clean_default_security_group_acl + use_public_gateways = local.public_gateway_object + address_prefixes = var.address_prefixes + routes = var.routes + enable_vpc_flow_logs = var.enable_vpc_flow_logs + create_authorization_policy_vpc_to_cos = !var.skip_vpc_cos_iam_auth_policy + existing_cos_instance_guid = var.enable_vpc_flow_logs ? local.cos_instance_guid : null + existing_storage_bucket_name = var.enable_vpc_flow_logs ? module.vpc_cos_buckets[0].buckets[local.vpc_flow_logs_bucket_name].bucket_name : null + vpn_gateways = var.vpn_gateways +} + +############################################################################# +# VPE Gateway +############################################################################# + +module "vpe_gateway" { + source = "terraform-ibm-modules/vpe-gateway/ibm" + version = "4.6.6" + resource_group_id = var.resource_group_id + region = var.region + prefix = local.prefix + security_group_ids = var.vpe_gateway_security_group_ids + vpc_name = module.vpc.vpc_name + vpc_id = module.vpc.vpc_id + subnet_zone_list = module.vpc.subnet_zone_list + cloud_services = var.vpe_gateway_cloud_services + cloud_service_by_crn = var.vpe_gateway_cloud_service_by_crn + service_endpoints = var.vpe_gateway_service_endpoints + reserved_ips = var.vpe_gateway_reserved_ips +} diff --git a/modules/monolith/outputs.tf b/modules/monolith/outputs.tf new file mode 100644 index 000000000..d43df4a98 --- /dev/null +++ b/modules/monolith/outputs.tf @@ -0,0 +1,307 @@ +############################################################################## +# VPC +############################################################################## + +output "vpc_name" { + description = "Name of the VPC created." + value = module.vpc.vpc_name +} + +output "vpc_id" { + description = "ID of the VPC created." + value = module.vpc.vpc_id +} + +output "vpc_crn" { + description = "CRN of the VPC created." + value = module.vpc.vpc_crn +} + +############################################################################## +# Public Gateways +############################################################################## + +output "public_gateways" { + description = "Map of the public gateways by zone." + value = module.vpc.public_gateways +} + +############################################################################## +# VPC flow logs +############################################################################## + +output "vpc_flow_logs" { + description = "Details of the VPC flow logs collector." + value = module.vpc.vpc_flow_logs +} + +############################################################################## +# Network ACLs +############################################################################## + +output "network_acls" { + description = "List of shortnames and IDs of network ACLs." + value = module.vpc.network_acls +} + +############################################################################## +# Subnet Outputs +############################################################################## + +output "subnet_ids" { + description = "The IDs of the subnets." + value = module.vpc.subnet_ids +} + +output "private_path_subnet_id" { + description = "The IDs of the subnets." + value = length(module.vpc.subnet_ids) > 0 ? module.vpc.subnet_ids[0] : null +} + +output "subnet_detail_list" { + description = "A list of subnets containing names, CIDR blocks, and zones." + value = module.vpc.subnet_detail_list +} + +output "subnet_zone_list" { + description = "A list of subnet IDs and subnet zones." + value = module.vpc.subnet_zone_list +} + +output "subnet_detail_map" { + description = "A map of subnets containing IDs, CIDR blocks, and zones." + value = module.vpc.subnet_detail_map +} + +############################################################################## +# VPN Gateways Outputs +############################################################################## + +output "vpn_gateways_name" { + description = "List of names of VPN gateways." + value = module.vpc.vpn_gateways_name +} + +output "vpn_gateways_data" { + description = "Details of VPN gateways data." + value = module.vpc.vpn_gateways_data +} + +############################################################################## +# VPE Outputs +############################################################################## + +output "vpe_ips" { + description = "The reserved IPs for endpoint gateways." + value = module.vpe_gateway.vpe_ips +} + +output "vpe_crn" { + description = "The CRN of the endpoint gateway." + value = module.vpe_gateway.crn +} + +############################################################################## +# KMS Outputs +############################################################################## + +output "kms_guid" { + description = "Key Protect instance GUID or the KMS instance GUID if existing_kms_instance_crn was set" + value = local.cluster_existing_kms_guid +} + +output "kms_account_id" { + description = "The account ID of the KMS instance." + value = local.cluster_kms_account_id +} + +output "key_protect_id" { + description = "Key Protect instance ID when an instance is created, otherwise null" + value = local.cluster_kms_key_id +} + +output "kms_instance_crn" { + value = var.existing_kms_instance_crn == null ? var.kms_encryption_enabled_cluster ? module.kms[0].key_protect_crn : null : var.existing_kms_instance_crn + description = "The CRN of the Hyper Protect Crypto Service instance or Key Protect instance" +} + +output "kms_config" { + description = "The KMS config needed for OCP cluster" + value = local.kms_config +} + +output "boot_volume_kms_key_id" { + description = "The Key ID for the boot volume encryption" + value = local.boot_volume_kms_key_id +} + +output "boot_volume_existing_kms_guid" { + description = "The GUID for the boot volume encryption" + value = local.boot_volume_existing_kms_guid +} + +output "boot_volume_kms_account_id" { + description = "The Account ID for the boot volume encryption" + value = local.boot_volume_kms_account_id +} + +############################################################################## +# SM Outputs +############################################################################## + +output "secrets_manager_guid" { + description = "GUID of Secrets Manager instance" + value = local.secrets_manager_guid +} + +output "secrets_manager_crn" { + value = local.secrets_manager_crn + description = "CRN of the Secrets Manager instance" +} + +output "secrets_manager_region" { + value = local.secrets_manager_region + description = "Region of the Secrets Manager instance" +} + +############################################################################## +# COS Outputs +############################################################################## + +output "cos_instance_crn" { + description = "COS instance crn" + value = var.existing_cos_instance_crn != null ? var.existing_cos_instance_crn : module.cos[0].cos_instance_crn +} + +output "cos_instance_guid" { + description = "COS instance guid" + value = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].service_instance : module.cos[0].cos_instance_guid +} + +output "cos_instance_id" { + description = "COS instance ID" + value = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_crn +} + + +############################################################################## +# Cloud Monitoring Outputs +############################################################################## + +output "cloud_monitoring_crn" { + value = local.cloud_monitoring_crn + description = "The id of the provisioned IBM Cloud Monitoring instance." +} +output "cloud_monitoring_name" { + value = local.create_cloud_monitoring ? module.cloud_monitoring[0].name : null + description = "The name of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_guid" { + value = local.create_cloud_monitoring ? module.cloud_monitoring[0].guid : module.existing_cloud_monitoring_crn_parser[0].service_instance + description = "The guid of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_access_key_name" { + value = local.create_cloud_monitoring ? module.cloud_monitoring[0].access_key_name : null + description = "The name of the IBM Cloud Monitoring access key for agents to use" +} + +output "cloud_monitoring_access_key" { + value = local.create_cloud_monitoring ? module.cloud_monitoring[0].access_key : null + description = "The IBM Cloud Monitoring access key for agents to use" + sensitive = true +} + +############################################################################## +# Cloud Logs Outputs +############################################################################## + +output "cloud_logs_crn" { + value = local.cloud_logs_crn + description = "The id of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_guid" { + value = local.create_cloud_logs ? module.cloud_logs[0].guid : null + description = "The guid of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_name" { + value = local.create_cloud_logs ? module.cloud_logs[0].name : null + description = "The name of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_ingress_endpoint" { + value = local.create_cloud_logs ? module.cloud_logs[0].ingress_endpoint : null + description = "The public ingress endpoint of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_ingress_private_endpoint" { + value = local.create_cloud_logs ? module.cloud_logs[0].ingress_private_endpoint : null + description = "The private ingress endpoint of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_logs_policies_details" { + value = local.create_cloud_logs ? module.cloud_logs[0].logs_policies_details : null + description = "The details of the IBM Cloud logs policies created." +} + +output "logs_bucket_crn" { + description = "Logs Cloud Object Storage bucket CRN" + value = module.cloud_logs_buckets.buckets[local.data_bucket_name].bucket_crn +} + +output "metrics_bucket_crn" { + description = "Metrics Cloud Object Storage bucket CRN" + value = module.cloud_logs_buckets.buckets[local.metrics_bucket_name].bucket_crn +} + +############################################################################## +# Activity Tracker Event Routing Outputs +############################################################################## + +output "activity_tracker_cos_target_bucket_name" { + value = var.existing_activity_tracker_cos_target_bucket_name == null ? var.enable_activity_tracker_event_routing_to_cos_bucket ? module.at_cos_bucket[0].buckets[local.activity_tracker_cos_target_bucket_name].bucket_name : null : var.existing_activity_tracker_cos_target_bucket_name + description = "he name of the object storage bucket which is set as activity tracker event routing target to collect audit events." +} + +output "activity_tracker_targets" { + value = module.activity_tracker.activity_tracker_targets + description = "The map of created Activity Tracker Event Routing targets" +} + +output "activity_tracker_routes" { + value = module.activity_tracker.activity_tracker_routes + description = "The map of created Activity Tracker Event Routing routes" +} + +############################################################################## +# SCC-WP Outputs +############################################################################## + +output "scc_workload_protection_id" { + description = "SCC Workload Protection instance ID" + value = module.scc_wp.id +} + +output "scc_workload_protection_crn" { + description = "SCC Workload Protection instance CRN" + value = module.scc_wp.crn +} + +output "scc_workload_protection_name" { + description = "SCC Workload Protection instance name" + value = module.scc_wp.name +} + +output "scc_workload_protection_ingestion_endpoint" { + description = "SCC Workload Protection instance ingestion endpoint" + value = module.scc_wp.name +} + +output "scc_workload_protection_api_endpoint" { + description = "SCC Workload Protection API endpoint" + value = module.scc_wp.api_endpoint + sensitive = true +} diff --git a/modules/monolith/variables.tf b/modules/monolith/variables.tf new file mode 100644 index 000000000..73ca707b8 --- /dev/null +++ b/modules/monolith/variables.tf @@ -0,0 +1,1684 @@ +variable "prefix" { + type = string + nullable = true + description = "The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To skip using a prefix, set this value to null or an empty string." + + validation { + # - null and empty string is allowed + # - Must not contain consecutive hyphens (--): length(regexall("--", var.prefix)) == 0 + # - Starts with a lowercase letter: [a-z] + # - Contains only lowercase letters (a–z), digits (0–9), and hyphens (-) + # - Must not end with a hyphen (-): [a-z0-9] + condition = (var.prefix == null || var.prefix == "" ? true : + alltrue([ + can(regex("^[a-z][-a-z0-9]*[a-z0-9]$", var.prefix)), + length(regexall("--", var.prefix)) == 0 + ]) + ) + error_message = "Prefix must begin with a lowercase letter and may contain only lowercase letters, digits, and hyphens '-'. It must not end with a hyphen('-'), and cannot contain consecutive hyphens ('--')." + } + + validation { + # must not exceed 16 characters in length + condition = var.prefix == null || var.prefix == "" ? true : length(var.prefix) <= 16 + error_message = "Prefix must not exceed 16 characters." + } +} + +variable "region" { + type = string + description = "The region to provision all resources in." + default = "us-south" + nullable = false +} + +variable "resource_group_id" { + type = string + description = "The ID of an existing IBM Cloud resource group where the cluster is grouped." +} + +############################################################## +# KMS Related +############################################################## +variable "kms_encryption_enabled_cluster" { + description = "Set to true to enable KMS encryption for the cluster's Object Storage bucket. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn`." + type = bool + default = false + nullable = false + + validation { + condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled_cluster : true + error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled_cluster' to true." + } + + validation { + condition = var.existing_cluster_kms_key_crn != null ? var.kms_encryption_enabled_cluster : true + error_message = "If passing a value for 'existing_cluster_kms_key_crn', you should set 'kms_encryption_enabled_cluster' to true." + } +} + +variable "existing_kms_instance_crn" { + type = string + default = null + description = "The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect)." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.existing_kms_instance_crn)), + var.existing_kms_instance_crn == null, + ]) + error_message = "The provided KMS instance CRN in the input 'existing_kms_instance_crn' in not valid." + } +} + +variable "existing_cluster_kms_key_crn" { + type = string + default = null + description = "The CRN of an existing KMS key to use for encrypting the Object Storage of the Cluster. If no value is set for this variable, specify a value for `existing_kms_instance_crn` variable to create a key ring and key." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}:key:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.existing_cluster_kms_key_crn)), + var.existing_cluster_kms_key_crn == null, + ]) + error_message = "The provided KMS key CRN in the input 'existing_cluster_kms_key_crn' in not valid." + } + + validation { + condition = var.existing_cluster_kms_key_crn != null ? var.existing_kms_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing key value using the 'existing_cluster_kms_key_crn' input." + } + +} + +variable "kms_endpoint_type" { + type = string + description = "The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_cluster` is true" + default = "private" + nullable = false + validation { + condition = can(regex("^(public|private)$", var.kms_endpoint_type)) + error_message = "The kms_endpoint_type value must be 'public' or 'private'." + } +} + +variable "cluster_kms_key_ring_name" { + type = string + default = "cluster-key-ring" + description = "The name of the key ring to be created for the cluster's Object Storage bucket encryption key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "cluster_kms_key_name" { + type = string + default = "cluster-key" + description = "The name of the key to be created for the cluster's Object Storage bucket encryption. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "kms_encryption_enabled_boot_volume" { + type = bool + description = "Set this to true to control the encryption keys used to encrypt the data that for the block storage volumes for VPC. If set to false, the data is encrypted by using randomly generated keys. For more info on encrypting block storage volumes, see https://cloud.ibm.com/docs/vpc?topic=vpc-creating-instances-byok" + default = false + nullable = false + + validation { + condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled_boot_volume || var.kms_encryption_enabled_cluster : true + error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled_boot_volume' to true." + } + + validation { + condition = var.existing_boot_volume_kms_key_crn != null ? var.kms_encryption_enabled_boot_volume : true + error_message = "If passing a value for 'existing_boot_volume_kms_key_crn', you should set 'kms_encryption_enabled_boot_volume' to true." + } +} + +variable "existing_boot_volume_kms_key_crn" { + type = string + default = null + description = "The CRN of an existing KMS key to use to encrypt the the block storage volumes for VPC. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}:key:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.existing_boot_volume_kms_key_crn)), + var.existing_boot_volume_kms_key_crn == null, + ]) + error_message = "The provided KMS key CRN in the input 'existing_boot_volume_kms_key_crn' in not valid." + } +} + +variable "boot_volume_kms_key_ring_name" { + type = string + default = "boot-volume-key-ring" + description = "The name for the key ring created for the block storage volumes key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "boot_volume_kms_key_name" { + type = string + default = "boot-volume-key" + description = "The name for the key created for the block storage volumes. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "kms_instance_name" { + type = string + description = "The name to give the Key Protect instance that that is created by this module. Only used if 'create_key_protect_instance' is set to `true`." + default = "key-protect" +} + +variable "kms_plan" { + type = string + description = "Plan for the Key Protect instance. Supported values are 'tiered-pricing' and 'cross-region-resiliency'. Only used if 'create_key_protect_instance' is set to `true`." + default = "tiered-pricing" + # validation performed in terraform-ibm-key-protect module +} + +variable "rotation_enabled" { + type = bool + description = "If set to `true`, a rotation policy is enabled on the Key Protect instance. Only used if 'create_key_protect_instance' is set to `true`." + default = true +} + +variable "rotation_interval_month" { + type = number + description = "Specifies how often keys are rotated in months. Value must be between `1` and `12` inclusive. Only used if 'create_key_protect_instance' is set to `true`." + default = 1 +} + +variable "dual_auth_delete_enabled" { + type = bool + description = "If set to `true`, a dual authorization policy is enabled on the Key Protect instance. After the dual authorization policy is set on the instance, it cannot be reverted. An instance with dual authorization policy enabled cannot be destroyed by using Terraform. Only used if 'create_key_protect_instance' is set to `true`." + default = false +} + +variable "enable_metrics" { + type = bool + description = "Set to `true` to enable metrics on the Key Protect instance. Only used if 'create_key_protect_instance' is set to `true`. In order to view metrics, you need an IBM Cloud Monitoring (Sysdig) instance that is located in the same region as the Key Protect instance. After you provision a Monitoring instance, enable platform metrics to monitor your Key Protect instance." + default = true +} + +variable "key_create_import_access_enabled" { + type = bool + description = "If set to `true`, a key create and import access policy is enabled on the instance of Key Protect. Only used if 'create_key_protect_instance' is set to `true`." + default = true +} + +variable "key_protect_allowed_network" { + type = string + description = "Allowed network types for the Key Protect instance. Possible values are 'private-only', or 'public-and-private'. Only used if 'create_key_protect_instance' is set to `true`." + default = "private-only" + validation { + condition = can(regex("private-only|public-and-private", var.key_protect_allowed_network)) + error_message = "The `key_protect_allowed_network` value must be 'private-only' or 'public-and-private'." + } +} + +variable "kms_resource_tags" { + type = list(string) + description = "Optional list of tags to add to the Key Protect instance. Only used if 'create_key_protect_instance' is set to `true`." + default = [] +} + +variable "kms_access_tags" { + type = list(string) + description = "A list of access tags to apply to the Key Protect instance. Only used if 'create_key_protect_instance' is set to `true`." + default = [] +} + +variable "kms_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The context-based restrictions rule to create. Only one rule is allowed." + default = [] + # Validation happens in the rule module + # NOTE: Context-based restriction rules applies to Key Protect instances only and is not supported by Hyper Protect Crypto Services (HPCS) instances + + validation { + condition = var.existing_kms_instance_crn == null ? true : length(regexall(".*hscrypto.*", var.existing_kms_instance_crn)) > 0 ? length(var.kms_cbr_rules) == 0 : true + error_message = "When passing a Hyper Protect Crypto Services (HPCS) instance as a value for `existing_kms_instance_crn` you cannot provide `kms_cbr_rules`. Context-based restrictions are not supported by HPCS instances. For more information, go to [services that integrate with context-based restrictions](https://cloud.ibm.com/docs/account?topic=account-context-restrictions-whatis#cbr-adopters)." + } + validation { + condition = length(var.kms_cbr_rules) <= 1 + error_message = "Only one CBR rule is allowed." + } +} + +############################################################## +# Secrets Manager +############################################################## + +variable "secrets_manager_instance_name" { + type = string + description = "The name to give the Secrets Manager instance provisioned by this solution. If a prefix input variable is specified, it is added to the value in the `-value` format. Applies only if `existing_secrets_manager_crn` is not provided." + default = "secrets-manager" +} + +variable "existing_secrets_manager_crn" { + type = string + description = "The CRN of an existing Secrets Manager instance. If not supplied, a new instance is created." + default = null +} + +variable "secrets_manager_service_plan" { + type = string + description = "The pricing plan to use when provisioning a Secrets Manager instance. Possible values: `standard`, `trial`. You can create only one Trial instance of Secrets Manager per account. Before you can create a new Trial instance, you must delete the existing Trial instance and its reclamation." + default = "standard" + validation { + condition = var.existing_secrets_manager_crn == null ? contains(["standard", "trial"], var.secrets_manager_service_plan) : true + error_message = "Only 'standard' and 'trial' are allowed values for 'secrets_manager_service_plan'. Applies only if not providing a value for the 'existing_secrets_manager_crn' input." + } +} + +variable "skip_secrets_manager_iam_auth_policy" { + type = bool + description = "Whether to skip the creation of the IAM authorization policies required to enable the IAM credentials engine (if you are using an existing Secrets Manager instance, attempting to re-create can cause conflicts if the policies already exist). If set to false, policies will be created that grants the Secrets Manager instance 'Operator' access to the IAM identity service, and 'Groups Service Member Manage' access to the IAM groups service." + default = false +} + +variable "secrets_manager_resource_tags" { + type = list(string) + description = "The list of resource tags you want to associate with your Secrets Manager instance. Applies only if `existing_secrets_manager_crn` is not provided." + default = [] +} + +variable "secrets_manager_endpoint_type" { + type = string + description = "The type of endpoint (public or private) to connect to the Secrets Manager API. The Terraform provider uses this endpoint type to interact with the Secrets Manager API and configure Event Notifications." + default = "private" + validation { + condition = contains(["public", "private"], var.secrets_manager_endpoint_type) + error_message = "The specified service endpoint is not a valid selection!" + } +} + +variable "secrets_manager_allowed_network" { + type = string + description = "The types of service endpoints to set on the Secrets Manager instance. Possible values are `private-only` or `public-and-private`." + default = "private-only" + validation { + condition = contains(["private-only", "public-and-private"], var.secrets_manager_allowed_network) + error_message = "The specified allowed_network is not a valid selection!" + } +} + +variable "skip_secrets_manager_kms_iam_auth_policy" { + type = bool + description = "Set to true to skip the creation of an IAM authorization policy that permits all Secrets Manager instances in the resource group to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable." + default = false +} + +variable "secret_groups" { + type = list(object({ + secret_group_name = string + secret_group_description = optional(string) + create_access_group = optional(bool, true) + access_group_name = optional(string) + access_group_roles = optional(list(string), ["SecretsReader"]) + access_group_tags = optional(list(string)) + })) + description = "Secret Manager secret group and access group configurations. If a prefix input variable is specified, it is added to the `access_group_name` value in the `-value` format. If you do not wish to create any groups, set the value to `[]`." + nullable = false + default = [ + { + secret_group_name = "General" + secret_group_description = "A general purpose secrets group with an associated access group which has a secrets reader role" + create_access_group = true + access_group_name = "general-secrets-group-access-group" + access_group_roles = ["SecretsReader"] + } + ] + validation { + error_message = "The name of the secret group cannot be null or empty string." + condition = length([ + for group in var.secret_groups : + true if(group.secret_group_name == "" || group.secret_group_name == null) + ]) == 0 + } + validation { + error_message = "When creating an access group, a list of roles must be specified." + condition = length([ + for group in var.secret_groups : + true if(group.create_access_group && group.access_group_roles == null) + ]) == 0 + } +} + +variable "secrets_manager_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "(Optional, list) List of CBR rules to create." + default = [] + # Validation happens in the rule module +} + +######################################################################################################################## +# Event Notifications +######################################################################################################################## + +variable "existing_event_notifications_instance_crn" { + type = string + description = "The CRN of the Event Notifications service used to enable lifecycle notifications for your Secrets Manager instance." + default = null +} + +variable "skip_secrets_manager_event_notifications_iam_auth_policy" { + type = bool + description = "If set to true, this skips the creation of a service to service authorization from Secrets Manager to Event Notifications. If false, the service to service authorization is created." + default = false +} + +variable "event_notifications_email_list" { + type = list(string) + description = "The list of email address to target out when Secrets Manager triggers an event" + default = [] +} + +variable "event_notifications_from_email" { + type = string + description = "The email address used to send any Secrets Manager event coming via Event Notifications" + default = "compliancealert@ibm.com" +} + +variable "event_notifications_reply_to_email" { + type = string + description = "The email address specified in the 'reply_to' section for any Secret Manager event coming via Event Notifications" + default = "no-reply@ibm.com" +} + +############################################################## +# COS +############################################################## + +variable "existing_cos_instance_crn" { + type = string + description = "The CRN of an existing Object Storage instance." + default = null +} + +variable "cos_instance_name" { + description = "The name for the IBM Cloud Object Storage instance provisioned by this solution. If a value is passed for `prefix`, the instance will be named with the prefix value in the format of `-value`." + type = string + default = "cos-instance" +} + +variable "cos_instance_plan" { + description = "The plan to use when Object Storage instances are created." + type = string + default = "standard" + validation { + condition = contains(["standard", "cos-one-rate-plan"], var.cos_instance_plan) + error_message = "The specified plan is not a valid selection!" + } +} + +variable "cos_instance_resource_tags" { + description = "A list of resource tags to apply to the Object Storage instance." + type = list(string) + default = [] +} + +variable "cos_instance_access_tags" { + type = list(string) + description = "A list of access tags to apply to the Object Storage instance created by the module." + default = [] +} + +variable "skip_secrets_manager_cos_iam_auth_policy" { + type = bool + default = false + description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Cloud Object Storage. Set to `true` to use an existing policy." +} + +variable "service_cred" { # pragma: allowlist secret + type = list(object({ + secret_group_name = string # pragma: allowlist secret + secret_group_description = optional(string) # pragma: allowlist secret + existing_secret_group = optional(bool) # pragma: allowlist secret + service_credentials = list(object({ # pragma: allowlist secret + secret_name = string # pragma: allowlist secret + service_credentials_source_service_role_crn = string # pragma: allowlist secret + secret_labels = optional(list(string)) # pragma: allowlist secret + secret_auto_rotation = optional(bool) # pragma: allowlist secret + secret_auto_rotation_unit = optional(string) # pragma: allowlist secret + secret_auto_rotation_interval = optional(number) # pragma: allowlist secret + service_credentials_ttl = optional(string) # pragma: allowlist secret + service_credential_secret_description = optional(string) # pragma: allowlist secret + + })) + })) + default = [] + description = "Service configuration for COS." + + validation { + # Service roles CRNs can be found at https://cloud.ibm.com/iam/roles, select Cloud Object Storage and select the role + condition = alltrue([ + for group in var.service_cred : alltrue([ + # crn:v?:bluemix; two non-empty segments; three possibly empty segments; :serviceRole or role: non-empty segment + for credential in group.service_credentials : can(regex("^crn:v[0-9]:bluemix(:..*){2}(:.*){3}:(serviceRole|role):..*$", credential.service_credentials_source_service_role_crn)) + ]) + ]) + error_message = "service_credentials_source_service_role_crn must be a serviceRole CRN. See https://cloud.ibm.com/iam/roles" + } + + validation { + condition = length(var.service_cred) > 0 ? var.existing_secrets_manager_crn != null : true + error_message = "When passing a value for 'service_credential', a value must be passed for 'existing_secrets_manager_crn'." + } +} + +variable "cos_instance_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + tags = optional(list(object({ + name = string + value = string + })), []) + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The list of context-based restriction rules to create for the instance." + default = [] + # Validation happens in the rule module +} + +######################################################################################################################## +# Cloud Monitoring +######################################################################################################################## + +variable "existing_cloud_monitoring_crn" { + type = string + default = null + description = "The CRN of an existing Cloud Monitoring instance. If not supplied, a new instance will be created." +} + +variable "cloud_monitoring_instance_name" { + type = string + description = "The name of the IBM Cloud Monitoring instance to create. If the prefix variable is passed, the name of the instance is prefixed to the value in the `-value` format." + default = "cloud-monitoring" +} + +variable "cloud_monitoring_resource_tags" { + type = list(string) + description = "Tags associated with the IBM Cloud Monitoring instance (Optional, array of strings)." + default = [] +} + +variable "cloud_monitoring_access_tags" { + type = list(string) + description = "A list of access tags to apply to the IBM Cloud Monitoring instance created by the DA. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial." + default = [] +} + +variable "disable_access_key_creation" { + type = bool + description = "When set to true, disables the creation of a default manager access key which is required by agents to ingest metrics." + default = false +} + +variable "cloud_monitoring_resource_keys" { + description = "A list of maps representing resource keys to create for the IBM Cloud Monitoring instance. Each entry defines a single resource key. Use this list to manage custom keys and handle key rotation." + type = list(object({ + name = string + generate_hmac_credentials = optional(bool, false) # pragma: allowlist secret + role = optional(string, "Manager") + service_id_crn = optional(string, null) + })) + default = [] +} + +variable "cloud_monitoring_plan" { + type = string + description = "The IBM Cloud Monitoring plan to provision. Available values are `lite` and `graduated-tier` and graduated-tier-sysdig-secure-plus-monitor (available in region eu-fr2 only)." + default = "graduated-tier" + + validation { + condition = can(regex("^lite$|^graduated-tier$|^graduated-tier-sysdig-secure-plus-monitor$", var.cloud_monitoring_plan)) + error_message = "The plan value must be one of the following: lite, graduated-tier and graduated-tier-sysdig-secure-plus-monitor (available in region eu-fr2 only)." + } + + validation { + condition = (var.cloud_monitoring_plan != "graduated-tier-sysdig-secure-plus-monitor") || var.region == "eu-fr2" + error_message = "When cloud_monitoring_plan is graduated-tier-sysdig-secure-plus-monitor region should be set to eu-fr2." + } +} + +variable "enable_platform_metrics" { + type = bool + description = "When set to `true`, the IBM Cloud Monitoring instance collects the platform metrics." + default = false +} + +######################################################################################################################## +# Metrics Routing +######################################################################################################################## + +variable "metrics_routing_target_name" { + type = string + description = "The name of the IBM Cloud Metrics Routing target where metrics are collected. If the prefix variable is passed, the name of the target is prefixed to the value in the `-value` format." + default = "cloud-monitoring-target" +} + +variable "metrics_routing_route_name" { + type = string + description = "The name of the IBM Cloud Metrics Routing route for the default route that indicate what metrics are routed in a region and where to store them. If the prefix variable is passed, the name of the target is prefixed to the value in the `-value` format." + default = "metrics-routing-route" +} + +variable "enable_metrics_routing_to_cloud_monitoring" { + type = bool + description = "Whether to enable metrics routing from IBM Cloud Metric Routing to Cloud Monitoring." + default = true +} + +variable "enable_primary_metadata_region" { + type = bool + description = "When set to `true`, sets `primary_metadata_region` to `region`, storing Metrics Router metadata in that region. When `false`, no region is set and the default global region is used. For new accounts, creating targets and routes will fail until primary_metadata_region is set, so it is recommended to default enable_primary_metadata_region to true." + default = true +} + +variable "metrics_router_routes" { + type = list(object({ + name = string + rules = list(object({ + action = string + targets = list(object({ + id = string + })) + inclusion_filters = list(object({ + operand = string + operator = string + values = list(string) + })) + })) + })) + default = [] + description = "Routes for IBM Cloud Metrics Routing." +} + +variable "cloud_monitoring_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The list of context-based restriction rules to create for the instance." + default = [] + # Validation happens in the rule module +} + +######################################################################################################################## +# Cloud Logs +######################################################################################################################## + +variable "existing_cloud_logs_crn" { + type = string + default = null + description = "The CRN of an existing Cloud Logs instance. If not supplied, a new instance will be created." +} + +variable "cloud_logs_instance_name" { + type = string + description = "The name of the IBM Cloud Logs instance to create. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + default = "cloud-logs" +} + +variable "cloud_logs_resource_tags" { + type = list(string) + description = "Tags associated with the IBM Cloud Logs instance (Optional, array of strings)." + default = [] +} + +variable "cloud_logs_access_tags" { + type = list(string) + description = "A list of access tags to apply to the IBM Cloud Logs instance created by the DA. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial." + default = [] +} + +variable "cloud_logs_retention_period" { + type = number + description = "The number of days IBM Cloud Logs will retain the logs data in Priority insights. Allowed values: 7, 14, 30, 60, 90." + default = 7 + + validation { + condition = contains([7, 14, 30, 60, 90], var.cloud_logs_retention_period) + error_message = "Valid values 'cloud_logs_retention_period' are: 7, 14, 30, 60, 90" + } +} + +variable "existing_event_notifications_instances" { + type = list(object({ + crn = string + integration_name = optional(string) + skip_iam_auth_policy = optional(bool, false) + })) + default = [] + description = "List of Event Notifications instance details for routing critical events that occur in your IBM Cloud Logs." +} + +variable "cloud_logs_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "(Optional, list) List of context-based restrictions rules to create." + default = [] +} + +variable "cloud_logs_data_cos_bucket_name" { + type = string + nullable = true + default = "cloud-logs-logs-bucket" + description = "The name of an to be given to a new bucket inside the existing Object Storage instance to use for IBM Cloud Logs. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "cloud_logs_metrics_cos_bucket_name" { + type = string + nullable = true + default = "cloud-logs-metrics-bucket" + description = "The name of an to be given to a new bucket inside the existing Object Storage instance to use for IBM Cloud Logs. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "skip_cloud_logs_cos_auth_policy" { + type = bool + description = "To skip creating an IAM authorization policy that allows the IBM Cloud logs to write to the Cloud Object Storage bucket, set this variable to `true`." + default = false +} + + + +variable "kms_encryption_enabled_buckets" { + description = "Set to true to enable KMS encryption on the Object Storage buckets created for the IBM Cloud Logs instance. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_cloud_logs_crn`." + type = bool + default = false + nullable = false + + validation { + condition = var.kms_encryption_enabled_buckets ? var.existing_cloud_logs_crn == null : true + error_message = "'kms_encryption_enabled_buckets' should be false if passing a value for 'existing_cloud_logs_crn' as existing Cloud Logs instance will already have a bucket attached." + } + + validation { + condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled_buckets : true + error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled_buckets' to true." + } + + validation { + condition = var.existing_cluster_kms_key_crn != null ? var.kms_encryption_enabled_buckets : true + error_message = "If passing a value for 'existing_cluster_kms_key_crn', you should set 'kms_encryption_enabled_buckets' to true." + } + + validation { + condition = var.kms_encryption_enabled_buckets ? ((var.existing_cluster_kms_key_crn != null || var.existing_kms_instance_crn != null) ? true : false) : true + error_message = "Either 'existing_cluster_kms_key_crn' or 'existing_kms_instance_crn' is required if 'kms_encryption_enabled_buckets' is set to true." + } +} + +variable "append_random_bucket_name_suffix" { + type = bool + description = "Append random generated suffix (4 characters long) to the newly provisioned IBM Cloud Logs Object Storage bucket names." + default = true +} + +variable "management_endpoint_type_for_buckets" { + description = "The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`, `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network." + type = string + default = "direct" + validation { + condition = contains(["public", "private", "direct"], var.management_endpoint_type_for_buckets) + error_message = "The specified management_endpoint_type_for_buckets is not a valid selection!" + } +} + +variable "cloud_logs_cos_buckets_class" { + type = string + default = "smart" + description = "The storage class of the newly provisioned IBM Cloud Logs Object Storage buckets. Possible values: `standard` or `smart`. Applies only if `existing_cloud_logs_crn` is not provided." + validation { + condition = contains(["standard", "smart"], var.cloud_logs_cos_buckets_class) + error_message = "Allowed values for cos_bucket_class are \"standard\" or \"smart\"." + } +} + +############################################################################## +# Logs Routing +############################################################################## + +variable "logs_routing_tenant_regions" { + type = list(any) + default = [] + description = "Pass a list of regions to create a tenant for that is targeted to the Cloud Logs instance created by this module. To manage platform logs that are generated by IBM Cloud® services in a region of IBM Cloud, you must create a tenant in each region that you operate. Leave the list empty if you don't want to create any tenants. NOTE: You can only have 1 tenant per region in an account." + nullable = false +} + +variable "skip_logs_routing_auth_policy" { + description = "Whether to create an IAM authorization policy that permits the Logs Routing server 'Sender' access to the IBM Cloud Logs instance created by this Deployable Architecture." + type = bool + default = false +} + +variable "logs_policies" { + type = list(object({ + logs_policy_name = string + logs_policy_description = optional(string, null) + logs_policy_priority = string + application_rule = optional(list(object({ + name = string + rule_type_id = string + }))) + subsystem_rule = optional(list(object({ + name = string + rule_type_id = string + }))) + log_rules = optional(list(object({ + severities = list(string) + }))) + archive_retention = optional(list(object({ + id = string + }))) + })) + description = "Configuration of Cloud Logs policies." + default = [] + + validation { + condition = alltrue([for config in var.logs_policies : (length(config.logs_policy_name) <= 4096 ? true : false)]) + error_message = "Maximum length of logs_policy_name allowed is 4096 chars." + } + + validation { + condition = alltrue([for config in var.logs_policies : contains(["type_unspecified", "type_block", "type_low", "type_medium", "type_high"], config.logs_policy_priority)]) + error_message = "The specified priority for logs policy is not a valid selection. Allowed values are: type_unspecified, type_block, type_low, type_medium, type_high." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.application_rule != null ? + (alltrue([for rule in config.application_rule : + contains(["unspecified", "is", "is_not", "start_with", "includes"], rule.rule_type_id)])) + : true) + ]) + error_message = "Identifier of application_rule 'rule_type_id' is not a valid selection. Allowed values are: unspecified, is, is_not, start_with, includes." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.application_rule != null ? + (alltrue([for rule in config.application_rule : + can(regex("^[\\p{L}\\p{N}\\p{P}\\p{Z}\\p{S}\\p{M}]+$", rule.name)) && length(rule.name) <= 4096 && length(rule.name) > 1])) + : true) + ]) + error_message = "The name of the application_rule does not meet the required criteria." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.log_rules != null && length(config.log_rules) > 0 ? true : false) + ]) + error_message = "The log_rules can not be empty and must contain at least 1 item." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.log_rules != null ? + (alltrue([for rule in config.log_rules : + alltrue([for severity in rule["severities"] : + contains(["unspecified", "debug", "verbose", "info", "warning", "error", "critical"], severity)])])) + : true + )]) + error_message = "The 'severities' of log_rules is not a valid selection. Allowed values are: unspecified, debug, verbose, info, warning, error, critical." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.subsystem_rule != null ? + (alltrue([for rule in config.subsystem_rule : + contains(["unspecified", "is", "is_not", "start_with", "includes"], rule.rule_type_id)])) + : true + )]) + error_message = "Identifier of subsystem_rule 'rule_type_id' is not a valid selection. Allowed values are: unspecified, is, is_not, start_with, includes." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.subsystem_rule != null ? + (alltrue([for rule in config.subsystem_rule : + can(regex("^[\\p{L}\\p{N}\\p{P}\\p{Z}\\p{S}\\p{M}]+$", rule.name)) && length(rule.name) <= 4096 && length(rule.name) > 1])) + : true) + ]) + error_message = "The name of the subsystem_rule does not meet the required criteria." + } + + validation { + condition = alltrue( + [for config in var.logs_policies : + (config.archive_retention != null ? + (alltrue( + [for rule in config.archive_retention : can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", rule.id))] + )) : true + )]) + error_message = "The id of the archive_retention does not meet the required criteria." + } +} + +############################################################################## +# Activity Tracker Event Routing +############################################################################## + +variable "enable_activity_tracker_event_routing_to_cos_bucket" { + type = bool + description = "When set to `true`, you must provide a value for `existing_cos_instance_crn` to enable event routing from Activity Tracker to a Object Storage bucket." + default = true + + validation { + condition = var.enable_activity_tracker_event_routing_to_cos_bucket || var.enable_activity_tracker_event_routing_to_cloud_logs + error_message = "At least one of 'enable_activity_tracker_event_routing_to_cos_bucket' or 'enable_activity_tracker_event_routing_to_cloud_logs' must be true to route audit events to COS bucket or Cloud Logs instance." + } + +} + +variable "activity_tracker_cos_target_bucket_name" { + type = string + default = "at-events-cos-bucket" + description = "The name of the Cloud Object Storage bucket to create for the Cloud Object Storage target to store AT events. Cloud Object Storage bucket names are globally unique. If the `add_bucket_name_suffix` variable is set to `true`, 4 random characters are added to this name to ensure that the name of the bucket is globally unique. If the prefix input variable is passed, the name of the instance is prefixed to the value in the `-value` format." +} + +variable "existing_activity_tracker_cos_target_bucket_name" { + type = string + nullable = true + default = null + description = "The name of an existing bucket within the Cloud Object Storage instance in which to store IBM Cloud Activity Tracker Event Routing. If an existing Cloud Object Storage bucket is not specified, a bucket is created." +} + +variable "existing_activity_tracker_cos_target_bucket_endpoint" { + type = string + nullable = true + default = null + description = "The name of an existing Cloud Object Storage bucket endpoint to use for setting up IBM Cloud Activity Tracker Event Routing. If an existing endpoint is not specified, the endpoint of the new Cloud Object Storage bucket is used." +} + +variable "cos_target_name" { + type = string + description = "Name of the cos target for activity tracker event routing." + default = null +} + +variable "cloud_logs_target_name" { + type = string + description = "Name of the cloud logs target for activity tracker event routing." + default = null +} + +variable "activity_tracker_cos_route_name" { + type = string + description = "Name of the cos route for activity tracker event routing." + default = null +} + +variable "activity_tracker_cloud_logs_route_name" { + type = string + description = "Name of the cloud logs route for activity tracker event routing." + default = null +} + +variable "activity_tracker_cos_target_bucket_class" { + type = string + default = "smart" + description = "The storage class of the newly provisioned Cloud Object Storage bucket. Specify one of the following values for the storage class: `standard`, `vault`, `cold`, `smart` (default), or `onerate_active`." + validation { + condition = contains(["standard", "vault", "cold", "smart", "onerate_active"], var.activity_tracker_cos_target_bucket_class) + error_message = "Specify one of the following values for the `cos_bucket_class`: `standard`, `vault`, `cold`, `smart`, or `onerate_active`." + } +} + +variable "activity_tracker_cos_bucket_access_tags" { + type = list(string) + default = [] + description = "A list of optional access tags to add to the IBM Cloud Activity Tracker Event Routing Cloud Object Storage bucket." +} + +variable "activity_tracker_cos_bucket_retention_policy" { + type = object({ + default = optional(number, 90) + maximum = optional(number, 350) + minimum = optional(number, 90) + permanent = optional(bool, false) + }) + description = "The retention policy of the IBM Cloud Activity Tracker Event Routing COS target bucket." + default = null +} + +variable "enable_activity_tracker_event_routing_to_cloud_logs" { + type = bool + description = "When set to `true`, you must provide a value for `existing_cloud_logs_crn` to enable event routing from Activity Tracker to a Cloud Logs instance." + default = true +} + +variable "skip_activity_tracker_cos_auth_policy" { + type = bool + description = "To skip creating an IAM authorization policy that allows the Activity Tracker to write to the Cloud Object Storage instance, set this variable to `true`." + default = false +} + +####################################################################################################################### +# SCC Workload Protection +####################################################################################################################### + +variable "scc_workload_protection_instance_name" { + description = "The name for the Workload Protection instance that is created by this solution. Must begin with a letter. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string + default = "scc-workload-protection" +} + +variable "scc_workload_protection_trusted_profile_name" { + description = "The name to give the trusted profile that is created by this module if `cspm_enabled` is `true. Must begin with a letter. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string + default = "workload-protection-trusted-profile" + validation { + condition = can(regex("^[a-zA-Z][a-zA-Z0-9\\-_\\.]+$", var.scc_workload_protection_trusted_profile_name)) + error_message = "The trusted profile name must begin with a letter and can only contain letters, numbers, hyphens, underscores, and periods." + } + validation { + condition = !(var.cspm_enabled && var.scc_workload_protection_trusted_profile_name == null) + error_message = "Cannot be `null` if `cspm_enabled` is `true`." + } +} + +variable "scc_workload_protection_instance_tags" { + type = list(string) + description = "The list of tags to add to the Workload Protection instance." + default = [] +} + +variable "scc_workload_protection_resource_key_tags" { + type = list(string) + description = "The tags associated with the Workload Protection resource key." + default = [] +} + +variable "scc_workload_protection_access_tags" { + type = list(string) + description = "A list of access tags to apply to the Workload Protection instance. Maximum length: 128 characters. Possible characters are A-Z, 0-9, spaces, underscores, hyphens, periods, and colons." + default = [] + + validation { + condition = alltrue([ + for tag in var.scc_workload_protection_access_tags : can(regex("[\\w\\-_\\.]+:[\\w\\-_\\.]+", tag)) && length(tag) <= 128 + ]) + error_message = "Tags must match the regular expression \"[\\w\\-_\\.]+:[\\w\\-_\\.]+\", see https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#limits for more details" + } +} + +variable "scc_workload_protection_service_plan" { + description = "The pricing plan for the Workload Protection instance service. Possible values: `free-trial`, `graduated-tier`." + type = string + default = "graduated-tier" + validation { + error_message = "Plan for Workload Protection instances can only be `free-trial` or `graduated-tier`." + condition = contains( + ["free-trial", "graduated-tier"], + var.scc_workload_protection_service_plan + ) + } +} + +variable "cspm_enabled" { + description = "Enable Cloud Security Posture Management (CSPM) for the Workload Protection instance. This will create a trusted profile associated with the SCC Workload Protection instance that has viewer / reader access to the App Config service and viewer access to the Enterprise service." + type = bool + default = false + nullable = false +} + +variable "app_config_crn" { + description = "The CRN of an existing App Config instance to use with the SCC Workload Protection instance. Required if `cspm_enabled` is true. NOTE: Ensure the App Config instance has configuration aggregator enabled." + type = string + default = null + validation { + condition = var.cspm_enabled ? var.app_config_crn != null : true + error_message = "Cannot be `null` if CSPM is enabled." + } + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}apprapp:(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.app_config_crn)), + var.app_config_crn == null, + ]) + error_message = "The provided CRN is not a valid App Config CRN." + } +} + +variable "scc_wp_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + tags = optional(list(object({ + name = string + value = string + })), []) + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The list of context-based restriction rules to create for the instance." + default = [] + # Validation happens in the rule module +} + +####################################################################################################################### +# VPC and VPE +####################################################################################################################### + +variable "enable_vpc_flow_logs" { + description = "To enable VPC Flow logs, set this to true." + type = bool + nullable = false + default = false +} + +variable "vpc_name" { + default = "vpc" + description = "Name of the VPC. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string +} + +variable "flow_logs_cos_bucket_name" { + description = "Name of the Cloud Object Storage bucket to be created to collect VPC flow logs." + type = string + default = "flow-logs-bucket" +} + +variable "vpc_resource_tags" { + type = list(string) + description = "The list of tags to add to the VPC instance." + default = [] +} + +variable "vpc_access_tags" { + type = list(string) + description = "The list of access tags to add to the VPC instance." + default = [] +} + +variable "vpc_flow_logs_access_tags" { + type = list(string) + description = "The list of access tags to add to the VPC instance." + default = [] +} + +variable "flow_logs_cos_bucket_archive_days" { + description = "The number of days before the `archive_type` rule action takes effect for the flow logs cloud object storage bucket." + type = number + default = 90 +} + +variable "flow_logs_cos_bucket_archive_type" { + description = "The storage class or archive type you want the object to transition to in the flow logs cloud object storage bucket." + type = string + default = "Glacier" + validation { + condition = contains(["Glacier", "Accelerated"], var.flow_logs_cos_bucket_archive_type) + error_message = "The specified flow_logs_cos_bucket_archive_type is not a valid selection!" + } +} + +variable "flow_logs_cos_bucket_expire_days" { + description = "The number of days before the expire rule action takes effect for the flow logs cloud object storage bucket." + type = number + default = 366 +} + +variable "flow_logs_cos_bucket_enable_object_versioning" { + description = "Set it to true if object versioning is enabled so that multiple versions of an object are retained in the flow logs cloud object storage bucket. Cannot be used if `flow_logs_cos_bucket_enable_retention` is true." + type = bool + nullable = false + default = false + + validation { + condition = var.flow_logs_cos_bucket_enable_object_versioning ? (var.flow_logs_cos_bucket_enable_retention ? false : true) : true + error_message = "`flow_logs_cos_bucket_enable_object_versioning` cannot set true if `flow_logs_cos_bucket_enable_retention` is true." + } +} + +variable "flow_logs_cos_bucket_enable_retention" { + description = "Set to true to enable retention for the flow logs cloud object storage bucket." + type = bool + nullable = false + default = false +} + +variable "flow_logs_cos_bucket_default_retention_days" { + description = "The number of days that an object can remain unmodified in the flow logs cloud object storage bucket." + type = number + default = 90 +} + +variable "flow_logs_cos_bucket_maximum_retention_days" { + description = "The maximum number of days that an object can be kept unmodified in the flow logs cloud object storage." + type = number + default = 350 +} + +variable "flow_logs_cos_bucket_minimum_retention_days" { + description = "The minimum number of days that an object must be kept unmodified in the flow logs cloud object storage." + type = number + default = 90 +} + +variable "flow_logs_cos_bucket_enable_permanent_retention" { + description = "Whether permanent retention status is enabled for the flow logs cloud object storage bucket." + type = bool + nullable = false + default = false +} + +variable "subnets" { + description = "List of subnets for the vpc. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total ipv4 addresses. Public gateways will be enabled only in zones where a gateway has been createds." + type = object({ + zone-1 = list(object({ + name = string + cidr = string + public_gateway = optional(bool) + acl_name = string + no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) + })) + zone-2 = optional(list(object({ + name = string + cidr = string + public_gateway = optional(bool) + acl_name = string + no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) + }))) + zone-3 = optional(list(object({ + name = string + cidr = string + public_gateway = optional(bool) + acl_name = string + no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) + }))) + }) + + default = { + zone-1 = [ + { + name = "subnet-a" + cidr = "10.10.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ], + zone-2 = [ + { + name = "subnet-b" + cidr = "10.20.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ], + zone-3 = [ + { + name = "subnet-c" + cidr = "10.30.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ] + } + + validation { + condition = alltrue([for key, value in var.subnets : value != null ? length([for subnet in value : subnet.public_gateway if subnet.public_gateway]) > 1 ? false : true : true]) + error_message = "var.subnets has more than one public gateway in a zone. Only one public gateway can be attached to a zone for the virtual private cloud." + } +} + +variable "default_network_acl_name" { + description = "Name of the Default ACL. If null, a name will be automatically generated." + type = string + default = null +} + +variable "default_security_group_name" { + description = "Name of the Default Security Group. If null, a name will be automatically generated." + type = string + default = null +} + +variable "default_routing_table_name" { + description = "Name of the Default Routing Table. If null, a name will be automatically generated." + type = string + default = null +} + +variable "network_acls" { + description = "The list of ACLs to create. Provide at least one rule for each ACL." + type = list( + object({ + name = string + add_ibm_cloud_internal_rules = optional(bool) + add_vpc_connectivity_rules = optional(bool) + prepend_ibm_rules = optional(bool) + rules = list( + object({ + name = string + action = string + destination = string + direction = string + source = string + tcp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + source_port_max = optional(number) + source_port_min = optional(number) + }) + ) + udp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + source_port_max = optional(number) + source_port_min = optional(number) + }) + ) + icmp = optional( + object({ + type = optional(number) + code = optional(number) + }) + ) + }) + ) + }) + ) + + default = [ + { + name = "vpc-acl" + add_ibm_cloud_internal_rules = true + add_vpc_connectivity_rules = true + prepend_ibm_rules = true + rules = [ + { + name = "allow-all-443-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 443 + port_max = 443 + source_port_min = 443 + source_port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-80-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 80 + port_max = 80 + source_port_min = 80 + source_port_max = 80 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-22-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 22 + port_max = 22 + source_port_min = 22 + source_port_max = 22 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-443-outbound" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 443 + port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-80-outbound" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 80 + source_port_max = 80 + port_min = 80 + port_max = 80 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-22-outbound" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 22 + source_port_max = 22 + port_min = 22 + port_max = 22 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + } + ] + } + ] + + validation { + error_message = "ACL rule actions can only be `allow` or `deny`." + condition = length(distinct( + flatten([ + # Check through rules + for rule in flatten([var.network_acls[*].rules]) : + # Return false action is not valid + false if !contains(["allow", "deny"], rule.action) + ]) + )) == 0 + } + + validation { + error_message = "ACL rule direction can only be `inbound` or `outbound`." + condition = length(distinct( + flatten([ + # Check through rules + for rule in flatten([var.network_acls[*].rules]) : + # Return false if direction is not valid + false if !contains(["inbound", "outbound"], rule.direction) + ]) + )) == 0 + } + + validation { + error_message = "ACL rule names must match the regex pattern ^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$." + condition = length(distinct( + flatten([ + # Check through rules + for rule in flatten([var.network_acls[*].rules]) : + # Return false if direction is not valid + false if !can(regex("^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", rule.name)) + ]) + )) == 0 + } + +} + +############################################################################## +# Default Security Group Rules +############################################################################## + +variable "security_group_rules" { + description = "A list of security group rules to be added to the default vpc security group (default empty)." + default = [] + type = list( + object({ + name = string + direction = string + remote = optional(string) + local = optional(string) + ip_version = optional(string) + tcp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + }) + ) + udp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + }) + ) + icmp = optional( + object({ + type = optional(number) + code = optional(number) + }) + ) + }) + ) + + validation { + error_message = "Security group rule direction can only be `inbound` or `outbound`." + condition = (var.security_group_rules == null || length(var.security_group_rules) == 0) ? true : length(distinct( + flatten([ + # Check through rules + for rule in var.security_group_rules : + # Return false if direction is not valid + false if !contains(["inbound", "outbound"], rule.direction) + ]) + )) == 0 + } + + validation { + error_message = "Security group rule names must match the regex pattern ^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$." + condition = (var.security_group_rules == null || length(var.security_group_rules) == 0) ? true : length(distinct( + flatten([ + # Check through rules + for rule in var.security_group_rules : + # Return false if direction is not valid + false if !can(regex("^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", rule.name)) + ]) + )) == 0 + } +} + +variable "clean_default_security_group_acl" { + description = "Remove all rules from the default VPC security group and VPC ACL (less permissive)." + type = bool + nullable = false + default = true +} + +############################################################################## +# Address Prefixes +############################################################################## + +variable "address_prefixes" { + description = "The IP range that will be defined for the VPC for a certain location. Use only with manual address prefixes." + type = object({ + zone-1 = optional(list(string)) + zone-2 = optional(list(string)) + zone-3 = optional(list(string)) + }) + default = { + zone-1 = null + zone-2 = null + zone-3 = null + } + validation { + error_message = "Keys for `use_public_gateways` must be in the order `zone-1`, `zone-2`, `zone-3`." + condition = var.address_prefixes == null ? true : ( + (length(var.address_prefixes) == 1 && keys(var.address_prefixes)[0] == "zone-1") || + (length(var.address_prefixes) == 2 && keys(var.address_prefixes)[0] == "zone-1" && keys(var.address_prefixes)[1] == "zone-2") || + (length(var.address_prefixes) == 3 && keys(var.address_prefixes)[0] == "zone-1" && keys(var.address_prefixes)[1] == "zone-2") && keys(var.address_prefixes)[2] == "zone-3" + ) + } +} + +############################################################################## +# Add routes to VPC +############################################################################## + +variable "routes" { + description = "Allows you to specify the next hop for packets based on their destination address." + type = list( + object({ + name = string + route_direct_link_ingress = optional(bool) + route_transit_gateway_ingress = optional(bool) + route_vpc_zone_ingress = optional(bool) + routes = optional( + list( + object({ + action = optional(string) + zone = number + destination = string + next_hop = string + }) + )) + }) + ) + default = [] +} + +variable "skip_vpc_cos_iam_auth_policy" { + description = "To skip creating an IAM authorization policy that allows the VPC to access the Cloud Object Storage, set this variable to `true`. Required only if `enable_vpc_flow_logs` is set to true." + type = bool + nullable = false + default = false +} + +variable "vpn_gateways" { + description = "List of VPN Gateways to create." + nullable = false + type = list( + object({ + name = string + subnet_name = string # Do not include prefix, use same name as in `var.subnets` + mode = optional(string) + resource_group = optional(string) + access_tags = optional(list(string), []) + }) + ) + + default = [] +} + +variable "vpe_gateway_cloud_services" { + description = "The list of cloud services used to create endpoint gateways. If `vpe_name` is not specified in the list, VPE names are created in the format `--`." + type = set(object({ + service_name = string + vpe_name = optional(string), # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name. + allow_dns_resolution_binding = optional(bool, false) + })) + default = [] +} + +variable "vpe_gateway_cloud_service_by_crn" { + description = "The list of cloud service CRNs used to create endpoint gateways. Use this list to identify services that are not supported by service name in the `cloud_services` variable. For a list of supported services, see [VPE-enabled services](https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-supported-services). If `service_name` is not specified, the CRN is used to find the name. If `vpe_name` is not specified in the list, VPE names are created in the format `--`." + type = set( + object({ + crn = string + vpe_name = optional(string) # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name. + service_name = optional(string) # Name of the service used to compute the name of the VPE. If not specified, the service name will be obtained from the crn. + allow_dns_resolution_binding = optional(bool, true) + }) + ) + default = [] +} + +variable "vpe_gateway_service_endpoints" { + description = "Service endpoints to use to create endpoint gateways. Can be `public`, or `private`." + type = string + default = "private" + + validation { + error_message = "Service endpoints can only be `public` or `private`." + condition = contains(["public", "private"], var.vpe_gateway_service_endpoints) + } +} + +variable "vpe_gateway_security_group_ids" { + + # Currently unused — the DA doesn't create any custom security groups. + # The default security group (automatically created with the VPC) is attached to the VPE gateway since no other security groups are present. + # May be useful in the future when DA supports using an existing VPC with custom security groups or if DA supports creating additional security groups we can take `vpe_gateway_security_group_names` as input. + + description = "List of security group ids to attach to each endpoint gateway." + type = list(string) + default = null # Let this default value be null instead of []. Provider issue - https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4546 +} + +variable "vpe_gateway_reserved_ips" { + description = "Map of existing reserved IP names and values. Leave this value as default if you want to create new reserved ips, this value is used when a user passes their existing reserved ips created here and not attempt to recreate those." + type = object({ + name = optional(string) # reserved ip name + }) + default = {} +} diff --git a/modules/monolith/version.tf b/modules/monolith/version.tf new file mode 100644 index 000000000..6d52d17c2 --- /dev/null +++ b/modules/monolith/version.tf @@ -0,0 +1,13 @@ +terraform { + required_version = ">=1.9.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.78.2, < 2.0.0" + } + time = { + source = "hashicorp/time" + version = ">= 0.9.1, < 1.0.0" + } + } +} diff --git a/tests/existing-resources-monolith/README.md b/tests/existing-resources-monolith/README.md new file mode 100644 index 000000000..705db15d6 --- /dev/null +++ b/tests/existing-resources-monolith/README.md @@ -0,0 +1 @@ +The terraform code in this directory is used by the existing resource test in tests/other_test.go diff --git a/tests/existing-resources-monolith/main.tf b/tests/existing-resources-monolith/main.tf new file mode 100644 index 000000000..3aa2b0abf --- /dev/null +++ b/tests/existing-resources-monolith/main.tf @@ -0,0 +1,24 @@ +############################################################################# +# Provision Resource Group +############################################################################# +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.4.0" + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +############################################################################## +# Event Notification +############################################################################## + +module "event_notifications" { + source = "terraform-ibm-modules/event-notifications/ibm" + version = "2.7.0" + resource_group_id = module.resource_group.resource_group_id + name = "${var.prefix}-en" + tags = var.resource_tags + plan = "lite" + service_endpoints = "public-and-private" + region = var.region +} diff --git a/tests/existing-resources-monolith/outputs.tf b/tests/existing-resources-monolith/outputs.tf new file mode 100644 index 000000000..4deb3162c --- /dev/null +++ b/tests/existing-resources-monolith/outputs.tf @@ -0,0 +1,18 @@ +######################################################################################################################## +# Outputs +######################################################################################################################## + +output "resource_group_id" { + description = "The id of the resource group where resources are created" + value = module.resource_group.resource_group_id +} + +output "resource_group_name" { + description = "The name of the resource group where resources are created" + value = module.resource_group.resource_group_name +} + +output "event_notifications_instance_crn" { + value = module.event_notifications.crn + description = "CRN of created event notification" +} diff --git a/tests/existing-resources-monolith/provider.tf b/tests/existing-resources-monolith/provider.tf new file mode 100644 index 000000000..df45ef50b --- /dev/null +++ b/tests/existing-resources-monolith/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/tests/existing-resources-monolith/variables.tf b/tests/existing-resources-monolith/variables.tf new file mode 100644 index 000000000..4b4575848 --- /dev/null +++ b/tests/existing-resources-monolith/variables.tf @@ -0,0 +1,32 @@ +############################################################################## +# Input variables +############################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region to provision all resources created by this example" + default = "us-south" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources created by this example" +} + +variable "resource_group" { + type = string + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + default = null +} + +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} diff --git a/tests/existing-resources-monolith/version.tf b/tests/existing-resources-monolith/version.tf new file mode 100644 index 000000000..97b20938f --- /dev/null +++ b/tests/existing-resources-monolith/version.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.3.0" + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.64.1" + } + } +} diff --git a/tests/other_test.go b/tests/other_test.go index 1e62fef2e..c81c81694 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -2,10 +2,17 @@ package test import ( + "fmt" + "os" + "strings" "testing" + "github.com/gruntwork-io/terratest/modules/files" + "github.com/gruntwork-io/terratest/modules/logger" + "github.com/gruntwork-io/terratest/modules/random" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testschematic" ) @@ -14,6 +21,7 @@ const advancedExampleDir = "examples/advanced" const basicExampleDir = "examples/basic" const fscloudExampleDir = "examples/fscloud" const crossKmsSupportExampleDir = "examples/cross_kms_support" +const monolithExampleDir = "examples/monolith" func setupOptions(t *testing.T, prefix string, terraformDir string, ocpVersion string) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ @@ -192,3 +200,98 @@ func TestFSCloudInSchematic(t *testing.T) { err := options.RunSchematicTest() assert.Nil(t, err, "This should not have errored") } + +func provisionPreReq(t *testing.T, p string) (string, *terraform.Options, error) { + // ------------------------------------------------------------------------------------ + // Provision existing resources first + // ------------------------------------------------------------------------------------ + prefix := fmt.Sprintf("%s-%s", p, strings.ToLower(random.UniqueId())) + realTerraformDir := "./existing-resources-monolith" + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, prefix) + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir, + Vars: map[string]interface{}{ + "prefix": prefix, + }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, + }) + + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + if existErr != nil { + // assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") + return "", nil, existErr + } + return prefix, existingTerraformOptions, nil +} + +func TestMonolithExample(t *testing.T) { + t.Parallel() + + prefix, existingTerraformOptions, existErr := provisionPreReq(t, "mon-ocp") + + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") + } else { + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Prefix: prefix, + TarIncludePatterns: []string{ + "*.tf", + monolithExampleDir + "/*.tf", + fullyConfigurableTerraformDir + "/scripts/*.*", + "/scripts/*.*", + "kubeconfig/*.*", + "modules/kube-audit/*.*", + "modules/worker-pool/*.*", + "modules/kube-audit/kubeconfig/*.*", + "modules/kube-audit/scripts/*.*", + "modules/kube-audit/helm-charts/kube-audit/*.*", + "modules/kube-audit/helm-charts/kube-audit/templates/*.*", + "modules/monolith/*.tf", + }, + TemplateFolder: monolithExampleDir, + Tags: []string{"monolith-base-ocp-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 240, + IgnoreAdds: testhelper.Exemptions{ + List: []string{"module.monolith_add_ons.module.scc_wp.restapi_object.cspm"}, + }, + IgnoreUpdates: testhelper.Exemptions{ + List: []string{"module.ocp_base.ibm_container_addons.addons"}, + }, + }) + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "prefix", Value: prefix, DataType: "string"}, + {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, + {Name: "kms_encryption_enabled_cluster", Value: true, DataType: "bool"}, + {Name: "existing_event_notifications_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "event_notifications_instance_crn"), DataType: "string"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (prereq resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (prereq resources)") + } +} From 14780c320b09020f32dfdb7707b98d807c9969b3 Mon Sep 17 00:00:00 2001 From: mukul-palit Date: Mon, 1 Dec 2025 18:03:51 +0530 Subject: [PATCH 2/4] merge changes --- tests/other_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/other_test.go b/tests/other_test.go index 70414fdf8..8a26d9a1a 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -6,13 +6,14 @@ import ( "os" "strings" "testing" + + "github.com/IBM/go-sdk-core/v5/core" "github.com/gruntwork-io/terratest/modules/files" "github.com/gruntwork-io/terratest/modules/logger" "github.com/gruntwork-io/terratest/modules/random" - "github.com/stretchr/testify/require" - "github.com/IBM/go-sdk-core/v5/core" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testaddons" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" @@ -293,6 +294,7 @@ func TestMonolithExample(t *testing.T) { terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) logger.Log(t, "END: Destroy (prereq resources)") } +} func TestAddonPermutations(t *testing.T) { testCases := []testaddons.AddonTestCase{ From 66cdfa6b9d3649d4eb74fc1c0d80c7a5a860f7af Mon Sep 17 00:00:00 2001 From: mukul-palit Date: Wed, 3 Dec 2025 02:59:00 +0530 Subject: [PATCH 3/4] Add EN and Apprapp --- README.md | 2 +- examples/monolith/README.md | 4 +- examples/monolith/main.tf | 5 + examples/monolith/outputs.tf | 14 ++ examples/monolith/variables.tf | 49 ++++ modules/monolith/README.md | 69 +++++- modules/monolith/main.tf | 405 +++++++++++++++++++++++++-------- modules/monolith/outputs.tf | 15 ++ modules/monolith/variables.tf | 375 ++++++++++++++++++++++++++++-- tests/other_test.go | 129 +++-------- 10 files changed, 844 insertions(+), 223 deletions(-) diff --git a/README.md b/README.md index f9f232395..ea198e6ab 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Optionally, the module supports advanced security group management for the worke *
Deploy to IBM Cloud button
*
Deploy to IBM Cloud button
*
Deploy to IBM Cloud button
- *
Deploy to IBM Cloud button
+ *
Deploy to IBM Cloud button
*
Deploy to IBM Cloud button
* [Contributing](#contributing) diff --git a/examples/monolith/README.md b/examples/monolith/README.md index dac08c088..dc3552bfa 100644 --- a/examples/monolith/README.md +++ b/examples/monolith/README.md @@ -1,4 +1,4 @@ -# IBM Cloud OpenShift DA - Monolith Add-ons Module +# IBM Cloud OpenShift DA - Monolith Add-ons Module Example A simple example that shows how to provision a multi zone OCP VPC cluster as well as all foundational infrastructure and supporting services required for a secure and compliant OpenShift (OCP) cluster deployment on IBM Cloud VPC. @@ -19,3 +19,5 @@ The following resources are provisioned by this example: - A COS instance along with 3 buckets for VPC flow logs, metrics/data bucket and activity tracker bucket. - A SCC-WP instance - A VPC instance +- An event notifications instance +- An app configuration service with aggregator enabled diff --git a/examples/monolith/main.tf b/examples/monolith/main.tf index cf7748270..d56c3c17c 100644 --- a/examples/monolith/main.tf +++ b/examples/monolith/main.tf @@ -25,6 +25,8 @@ module "monolith_add_ons" { kms_encryption_enabled_boot_volume = var.kms_encryption_enabled_boot_volume existing_boot_volume_kms_key_crn = var.existing_boot_volume_kms_key_crn kms_plan = var.kms_plan + en_service_plan = var.en_service_plan + en_service_endpoints = var.en_service_endpoints existing_secrets_manager_crn = var.existing_secrets_manager_crn secrets_manager_service_plan = var.secrets_manager_service_plan secrets_manager_endpoint_type = var.secrets_manager_endpoint_type @@ -32,11 +34,14 @@ module "monolith_add_ons" { existing_event_notifications_instance_crn = var.existing_event_notifications_instance_crn existing_cos_instance_crn = var.existing_cos_instance_crn cos_instance_plan = var.cos_instance_plan + management_endpoint_type_for_buckets = var.management_endpoint_type_for_buckets existing_cloud_monitoring_crn = var.existing_cloud_monitoring_crn cloud_monitoring_plan = var.cloud_monitoring_plan existing_cloud_logs_crn = var.existing_cloud_logs_crn scc_workload_protection_service_plan = var.scc_workload_protection_service_plan enable_vpc_flow_logs = var.enable_vpc_flow_logs + app_config_plan = var.app_config_plan + app_config_service_endpoints = var.app_config_service_endpoints } ######################################################################################################################## diff --git a/examples/monolith/outputs.tf b/examples/monolith/outputs.tf index ab94ac26d..d18185c01 100644 --- a/examples/monolith/outputs.tf +++ b/examples/monolith/outputs.tf @@ -130,6 +130,20 @@ output "kms_instance_crn" { description = "The CRN of the Hyper Protect Crypto Service instance or Key Protect instance" } +############################################################################## +# EN Outputs +############################################################################## + +output "en_crn" { + description = "Event Notification crn" + value = module.monolith_add_ons.en_crn +} + +output "en_guid" { + description = "Event Notification guid" + value = module.monolith_add_ons.en_guid +} + ############################################################################## # SM Outputs ############################################################################## diff --git a/examples/monolith/variables.tf b/examples/monolith/variables.tf index bc9b9416e..586793129 100644 --- a/examples/monolith/variables.tf +++ b/examples/monolith/variables.tf @@ -155,6 +155,26 @@ variable "kms_plan" { # validation performed in terraform-ibm-key-protect module } +variable "en_service_plan" { + type = string + description = "The pricing plan of the Event Notifications instance. Possible values: `Lite`, `Standard`." + default = "standard" + validation { + condition = contains(["lite", "standard"], var.en_service_plan) + error_message = "The specified pricing plan is not available. The following plans are supported: `Lite`, `Standard`" + } +} + +variable "en_service_endpoints" { + type = string + description = "Specify whether you want to enable public, private, or both public and private service endpoints. Possible values: `public`, `private`, `public-and-private`." + default = "public-and-private" + validation { + condition = contains(["public", "private", "public-and-private"], var.en_service_endpoints) + error_message = "The specified service endpoint is not supported. The following endpoint options are supported: `public`, `private`, `public-and-private`" + } +} + variable "existing_secrets_manager_crn" { type = string description = "The CRN of an existing Secrets Manager instance. If not supplied, a new instance is created." @@ -207,6 +227,16 @@ variable "cos_instance_plan" { } } +variable "management_endpoint_type_for_buckets" { + description = "The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`, `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network." + type = string + default = "direct" + validation { + condition = contains(["public", "private", "direct"], var.management_endpoint_type_for_buckets) + error_message = "The specified management_endpoint_type_for_buckets is not a valid selection!" + } +} + variable "existing_cloud_monitoring_crn" { type = string default = null @@ -255,6 +285,25 @@ variable "enable_vpc_flow_logs" { default = true } +variable "app_config_plan" { + type = string + description = "Plan for the App Configuration service instance." + default = "enterprise" + nullable = false +} + +variable "app_config_service_endpoints" { + type = string + description = "Service Endpoints for the App Configuration service instance, valid endpoints are public or public-and-private." + default = "public" + nullable = false + + validation { + condition = contains(["public", "public-and-private"], var.app_config_service_endpoints) + error_message = "Value for service endpoints must be one of the following: \"public\" or \"public-and-private\"." + } +} + ######################################################################################################################## # OCP VPC cluster ######################################################################################################################## diff --git a/modules/monolith/README.md b/modules/monolith/README.md index 83016376c..f36e5da80 100644 --- a/modules/monolith/README.md +++ b/modules/monolith/README.md @@ -41,22 +41,28 @@ module "monolith_ocp_add_ons" { | Name | Source | Version | |------|--------|---------| | [activity\_tracker](#module\_activity\_tracker) | terraform-ibm-modules/activity-tracker/ibm | 1.5.0 | +| [app\_config](#module\_app\_config) | terraform-ibm-modules/app-configuration/ibm | 1.14.2 | | [at\_cos\_bucket](#module\_at\_cos\_bucket) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | | [cloud\_logs](#module\_cloud\_logs) | terraform-ibm-modules/cloud-logs/ibm | 1.10.0 | -| [cloud\_logs\_buckets](#module\_cloud\_logs\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.7 | +| [cloud\_logs\_buckets](#module\_cloud\_logs\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | | [cloud\_monitoring](#module\_cloud\_monitoring) | terraform-ibm-modules/cloud-monitoring/ibm | 1.11.0 | | [cos](#module\_cos) | terraform-ibm-modules/cos/ibm//modules/fscloud | 10.5.9 | -| [existing\_boot\_volume\_kms\_key\_crn\_parser](#module\_existing\_boot\_volume\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | +| [cos\_secrets\_manager\_service\_credentials](#module\_cos\_secrets\_manager\_service\_credentials) | terraform-ibm-modules/secrets-manager/ibm//modules/secrets | 2.11.9 | +| [en\_cos\_buckets](#module\_en\_cos\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [en\_secrets\_manager\_service\_credentials](#module\_en\_secrets\_manager\_service\_credentials) | terraform-ibm-modules/secrets-manager/ibm//modules/secrets | 2.11.9 | +| [event\_notifications](#module\_event\_notifications) | terraform-ibm-modules/event-notifications/ibm | 2.7.0 | +| [existing\_boot\_volume\_kms\_key\_crn\_parser](#module\_existing\_boot\_volume\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | | [existing\_cloud\_monitoring\_crn\_parser](#module\_existing\_cloud\_monitoring\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | -| [existing\_cluster\_kms\_key\_crn\_parser](#module\_existing\_cluster\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | +| [existing\_cluster\_kms\_key\_crn\_parser](#module\_existing\_cluster\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | | [existing\_cos\_instance\_crn\_parser](#module\_existing\_cos\_instance\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | -| [existing\_kms\_crn\_parser](#module\_existing\_kms\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | +| [existing\_en\_crn\_parser](#module\_existing\_en\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | +| [existing\_kms\_crn\_parser](#module\_existing\_kms\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | +| [existing\_sm\_crn\_parser](#module\_existing\_sm\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | | [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 5.4.5 | | [metrics\_routing](#module\_metrics\_routing) | terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing | 1.11.0 | | [scc\_wp](#module\_scc\_wp) | terraform-ibm-modules/scc-workload-protection/ibm | 1.16.4 | | [secrets\_manager](#module\_secrets\_manager) | terraform-ibm-modules/secrets-manager/ibm | 2.11.9 | | [secrets\_manager\_crn\_parser](#module\_secrets\_manager\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.3.0 | -| [secrets\_manager\_service\_credentials](#module\_secrets\_manager\_service\_credentials) | terraform-ibm-modules/secrets-manager/ibm//modules/secrets | 2.11.9 | | [vpc](#module\_vpc) | terraform-ibm-modules/landing-zone-vpc/ibm | 8.9.1 | | [vpc\_cos\_buckets](#module\_vpc\_cos\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | | [vpe\_gateway](#module\_vpe\_gateway) | terraform-ibm-modules/vpe-gateway/ibm | 4.6.6 | @@ -65,12 +71,17 @@ module "monolith_ocp_add_ons" { | Name | Type | |------|------| -| [ibm_en_subscription_email.email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_subscription_email) | resource | -| [ibm_en_topic.en_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_topic) | resource | -| [ibm_iam_authorization_policy.secrets_manager_key_manager](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_en_subscription_email.apprapp_email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_subscription_email) | resource | +| [ibm_en_subscription_email.en_email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_subscription_email) | resource | +| [ibm_en_topic.en_apprapp_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_topic) | resource | +| [ibm_en_topic.en_sm_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_topic) | resource | +| [ibm_iam_authorization_policy.cos_secrets_manager_key_manager](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_iam_authorization_policy.en_secrets_manager_key_manager](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | | [time_sleep.wait_for_cos_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_en_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [time_sleep.wait_for_secrets_manager](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | -| [ibm_en_destinations.en_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/en_destinations) | data source | +| [ibm_en_destinations.en_apprapp_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/en_destinations) | data source | +| [ibm_en_destinations.en_sm_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/en_destinations) | data source | ### Inputs @@ -83,14 +94,19 @@ module "monolith_ocp_add_ons" { | [activity\_tracker\_cos\_target\_bucket\_class](#input\_activity\_tracker\_cos\_target\_bucket\_class) | The storage class of the newly provisioned Cloud Object Storage bucket. Specify one of the following values for the storage class: `standard`, `vault`, `cold`, `smart` (default), or `onerate_active`. | `string` | `"smart"` | no | | [activity\_tracker\_cos\_target\_bucket\_name](#input\_activity\_tracker\_cos\_target\_bucket\_name) | The name of the Cloud Object Storage bucket to create for the Cloud Object Storage target to store AT events. Cloud Object Storage bucket names are globally unique. If the `add_bucket_name_suffix` variable is set to `true`, 4 random characters are added to this name to ensure that the name of the bucket is globally unique. If the prefix input variable is passed, the name of the instance is prefixed to the value in the `-value` format. | `string` | `"at-events-cos-bucket"` | no | | [address\_prefixes](#input\_address\_prefixes) | The IP range that will be defined for the VPC for a certain location. Use only with manual address prefixes. |
object({
zone-1 = optional(list(string))
zone-2 = optional(list(string))
zone-3 = optional(list(string))
})
|
{
"zone-1": null,
"zone-2": null,
"zone-3": null
}
| no | -| [app\_config\_crn](#input\_app\_config\_crn) | The CRN of an existing App Config instance to use with the SCC Workload Protection instance. Required if `cspm_enabled` is true. NOTE: Ensure the App Config instance has configuration aggregator enabled. | `string` | `null` | no | +| [app\_config\_collections](#input\_app\_config\_collections) | (Optional, list) A list of collections to be added to the App Configuration instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-app-configuration/tree/main/solutions/fully-configurable/DA-collections.md). |
list(object({
name = string
collection_id = string
description = optional(string, null)
tags = optional(string, null)
}))
| `[]` | no | +| [app\_config\_event\_notifications\_source\_name](#input\_app\_config\_event\_notifications\_source\_name) | The name by which Event Notifications source will be created in the existing Event Notification instance. | `string` | `"app-config-en"` | no | +| [app\_config\_name](#input\_app\_config\_name) | Name for the App Configuration service instance. | `string` | `"app-config"` | no | +| [app\_config\_plan](#input\_app\_config\_plan) | Plan for the App Configuration service instance. | `string` | `"enterprise"` | no | +| [app\_config\_service\_endpoints](#input\_app\_config\_service\_endpoints) | Service Endpoints for the App Configuration service instance, valid endpoints are public or public-and-private. | `string` | `"public-and-private"` | no | +| [app\_config\_tags](#input\_app\_config\_tags) | Optional list of tags to be added to the App Config instance. | `list(string)` | `[]` | no | | [append\_random\_bucket\_name\_suffix](#input\_append\_random\_bucket\_name\_suffix) | Append random generated suffix (4 characters long) to the newly provisioned IBM Cloud Logs Object Storage bucket names. | `bool` | `true` | no | +| [apprapp\_cbr\_rules](#input\_apprapp\_cbr\_rules) | The list of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/fully-configurable/DA-cbr_rules.md). |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | | [boot\_volume\_kms\_key\_name](#input\_boot\_volume\_kms\_key\_name) | The name for the key created for the block storage volumes. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"boot-volume-key"` | no | | [boot\_volume\_kms\_key\_ring\_name](#input\_boot\_volume\_kms\_key\_ring\_name) | The name for the key ring created for the block storage volumes key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"boot-volume-key-ring"` | no | | [clean\_default\_security\_group\_acl](#input\_clean\_default\_security\_group\_acl) | Remove all rules from the default VPC security group and VPC ACL (less permissive). | `bool` | `true` | no | | [cloud\_logs\_access\_tags](#input\_cloud\_logs\_access\_tags) | A list of access tags to apply to the IBM Cloud Logs instance created by the DA. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial. | `list(string)` | `[]` | no | | [cloud\_logs\_cbr\_rules](#input\_cloud\_logs\_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
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | -| [cloud\_logs\_cos\_buckets\_class](#input\_cloud\_logs\_cos\_buckets\_class) | The storage class of the newly provisioned IBM Cloud Logs Object Storage buckets. Possible values: `standard` or `smart`. Applies only if `existing_cloud_logs_crn` is not provided. | `string` | `"smart"` | no | | [cloud\_logs\_data\_cos\_bucket\_name](#input\_cloud\_logs\_data\_cos\_bucket\_name) | The name of an to be given to a new bucket inside the existing Object Storage instance to use for IBM Cloud Logs. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cloud-logs-logs-bucket"` | no | | [cloud\_logs\_instance\_name](#input\_cloud\_logs\_instance\_name) | The name of the IBM Cloud Logs instance to create. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cloud-logs"` | no | | [cloud\_logs\_metrics\_cos\_bucket\_name](#input\_cloud\_logs\_metrics\_cos\_bucket\_name) | The name of an to be given to a new bucket inside the existing Object Storage instance to use for IBM Cloud Logs. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cloud-logs-metrics-bucket"` | no | @@ -105,27 +121,48 @@ module "monolith_ocp_add_ons" { | [cloud\_monitoring\_resource\_tags](#input\_cloud\_monitoring\_resource\_tags) | Tags associated with the IBM Cloud Monitoring instance (Optional, array of strings). | `list(string)` | `[]` | no | | [cluster\_kms\_key\_name](#input\_cluster\_kms\_key\_name) | The name of the key to be created for the cluster's Object Storage bucket encryption. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cluster-key"` | no | | [cluster\_kms\_key\_ring\_name](#input\_cluster\_kms\_key\_ring\_name) | The name of the key ring to be created for the cluster's Object Storage bucket encryption key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"cluster-key-ring"` | no | +| [config\_aggregator\_enterprise\_account\_group\_ids\_to\_assign](#input\_config\_aggregator\_enterprise\_account\_group\_ids\_to\_assign) | A list of enterprise account group IDs to assign the trusted profile template to in order for the accounts to be scanned. Supports passing the string 'all' in the list to assign to all account groups. Only applies if `enable_config_aggregator` is true and a value is being passed for `config_aggregator_enterprise_id`. | `list(string)` |
[
"all"
]
| no | +| [config\_aggregator\_enterprise\_account\_ids\_to\_assign](#input\_config\_aggregator\_enterprise\_account\_ids\_to\_assign) | A list of enterprise account IDs to assign the trusted profile template to in order for the accounts to be scanned. Supports passing the string 'all' in the list to assign to all accounts. Only applies if `enable_config_aggregator` is true and a value is being passed for `config_aggregator_enterprise_id`. | `list(string)` | `[]` | no | +| [config\_aggregator\_enterprise\_id](#input\_config\_aggregator\_enterprise\_id) | If the account is an enterprise account, this value should be set to the enterprise ID (NOTE: This is different to the account ID). | `string` | `null` | no | +| [config\_aggregator\_enterprise\_trusted\_profile\_name](#input\_config\_aggregator\_enterprise\_trusted\_profile\_name) | The name to give the enterprise viewer trusted profile with that will be created if `enable_config_aggregator` is set to `true` and a value is passed for `config_aggregator_enterprise_id`. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"config-aggregator-enterprise-trusted-profile"` | no | +| [config\_aggregator\_enterprise\_trusted\_profile\_template\_name](#input\_config\_aggregator\_enterprise\_trusted\_profile\_template\_name) | The name to give the trusted profile template that will be created if `enable_config_aggregator` is set to `true` and a value is passed for `config_aggregator_enterprise_id`. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"config-aggregator-trusted-profile-template"` | no | +| [config\_aggregator\_resource\_collection\_regions](#input\_config\_aggregator\_resource\_collection\_regions) | From which region do you want to collect configuration data? Only applies if `enable_config_aggregator` is set to true. | `list(string)` |
[
"all"
]
| no | +| [config\_aggregator\_trusted\_profile\_name](#input\_config\_aggregator\_trusted\_profile\_name) | The name to give the trusted profile that will be created if `enable_config_aggregator` is set to `true`. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"config-aggregator-trusted-profile"` | no | +| [cos\_buckets\_class](#input\_cos\_buckets\_class) | The storage class of the newly provisioned IBM Cloud Logs Object Storage buckets. Possible values: `standard` or `smart`. Applies only if `existing_cloud_logs_crn` is not provided. | `string` | `"smart"` | no | | [cos\_instance\_access\_tags](#input\_cos\_instance\_access\_tags) | A list of access tags to apply to the Object Storage instance created by the module. | `list(string)` | `[]` | no | | [cos\_instance\_cbr\_rules](#input\_cos\_instance\_cbr\_rules) | The list of context-based restriction rules to create for the instance. |
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 | | [cos\_instance\_name](#input\_cos\_instance\_name) | The name for the IBM Cloud Object Storage instance provisioned by this solution. If a value is passed for `prefix`, the instance will be named with the prefix value in the format of `-value`. | `string` | `"cos-instance"` | no | | [cos\_instance\_plan](#input\_cos\_instance\_plan) | The plan to use when Object Storage instances are created. | `string` | `"standard"` | no | | [cos\_instance\_resource\_tags](#input\_cos\_instance\_resource\_tags) | A list of resource tags to apply to the Object Storage instance. | `list(string)` | `[]` | no | | [cos\_target\_name](#input\_cos\_target\_name) | Name of the cos target for activity tracker event routing. | `string` | `null` | no | -| [cspm\_enabled](#input\_cspm\_enabled) | Enable Cloud Security Posture Management (CSPM) for the Workload Protection instance. This will create a trusted profile associated with the SCC Workload Protection instance that has viewer / reader access to the App Config service and viewer access to the Enterprise service. | `bool` | `false` | no | +| [cspm\_enabled](#input\_cspm\_enabled) | Enable Cloud Security Posture Management (CSPM) for the Workload Protection instance. This will create a trusted profile associated with the SCC Workload Protection instance that has viewer / reader access to the App Config service and viewer access to the Enterprise service. | `bool` | `true` | no | | [default\_network\_acl\_name](#input\_default\_network\_acl\_name) | Name of the Default ACL. If null, a name will be automatically generated. | `string` | `null` | no | | [default\_routing\_table\_name](#input\_default\_routing\_table\_name) | Name of the Default Routing Table. If null, a name will be automatically generated. | `string` | `null` | no | | [default\_security\_group\_name](#input\_default\_security\_group\_name) | Name of the Default Security Group. If null, a name will be automatically generated. | `string` | `null` | no | | [disable\_access\_key\_creation](#input\_disable\_access\_key\_creation) | When set to true, disables the creation of a default manager access key which is required by agents to ingest metrics. | `bool` | `false` | no | | [dual\_auth\_delete\_enabled](#input\_dual\_auth\_delete\_enabled) | If set to `true`, a dual authorization policy is enabled on the Key Protect instance. After the dual authorization policy is set on the instance, it cannot be reverted. An instance with dual authorization policy enabled cannot be destroyed by using Terraform. Only used if 'create\_key\_protect\_instance' is set to `true`. | `bool` | `false` | no | +| [en\_access\_tags](#input\_en\_access\_tags) | A list of access tags to apply to the Event Notifications instance created by the solution. For more information, [see here](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial). | `list(string)` | `[]` | no | +| [en\_cbr\_rules](#input\_en\_cbr\_rules) | The list of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/fully-configurable/DA-cbr_rules.md). |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [en\_cos\_bucket\_access\_tags](#input\_en\_cos\_bucket\_access\_tags) | A list of access tags to apply to the Cloud Object Storage bucket created by the solution. For more information, [see here](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial). | `list(string)` | `[]` | no | +| [en\_cos\_bucket\_name](#input\_en\_cos\_bucket\_name) | The name to use when creating the Object Storage bucket for the storage of failed delivery events. Bucket names are globally unique. If `add_bucket_name_suffix` is set to `true`, a random 4 character string is added to this name to help ensure that the bucket name is unique. If a `prefix` input variable is specified, it is added to this name in the `-value` format. | `string` | `"base-event-notifications-bucket"` | no | +| [en\_resource\_tags](#input\_en\_resource\_tags) | The list of tags to add to the Event Notifications instance. | `list(string)` | `[]` | no | +| [en\_service\_credential\_names](#input\_en\_service\_credential\_names) | A mapping of names and associated roles for service credentials that you want to create for the Event Notifications instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/blob/main/solutions/fully-configurable/DA-types.md#service-credentials-). | `map(string)` | `{}` | no | +| [en\_service\_credential\_secrets](#input\_en\_service\_credential\_secrets) | Service credential secrets configuration for Event Notification. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/fully-configurable/DA-types.md#service-credential-secrets). |
list(object({
secret_group_name = string # pragma: allowlist secret
secret_group_description = optional(string) # pragma: allowlist secret
existing_secret_group = optional(bool) # pragma: allowlist secret
service_credentials = list(object({ # pragma: allowlist secret
secret_name = string # pragma: allowlist secret
service_credentials_source_service_role_crn = string # pragma: allowlist secret
secret_labels = optional(list(string)) # pragma: allowlist secret
secret_auto_rotation = optional(bool) # pragma: allowlist secret
secret_auto_rotation_unit = optional(string) # pragma: allowlist secret
secret_auto_rotation_interval = optional(number) # pragma: allowlist secret
service_credentials_ttl = optional(string) # pragma: allowlist secret
service_credential_secret_description = optional(string) # pragma: allowlist secret

}))
}))
| `[]` | no | +| [en\_service\_endpoints](#input\_en\_service\_endpoints) | Specify whether you want to enable public, private, or both public and private service endpoints. Possible values: `public`, `private`, `public-and-private`. | `string` | `"private"` | no | +| [en\_service\_plan](#input\_en\_service\_plan) | The pricing plan of the Event Notifications instance. Possible values: `Lite`, `Standard`. | `string` | `"standard"` | no | | [enable\_activity\_tracker\_event\_routing\_to\_cloud\_logs](#input\_enable\_activity\_tracker\_event\_routing\_to\_cloud\_logs) | When set to `true`, you must provide a value for `existing_cloud_logs_crn` to enable event routing from Activity Tracker to a Cloud Logs instance. | `bool` | `true` | no | | [enable\_activity\_tracker\_event\_routing\_to\_cos\_bucket](#input\_enable\_activity\_tracker\_event\_routing\_to\_cos\_bucket) | When set to `true`, you must provide a value for `existing_cos_instance_crn` to enable event routing from Activity Tracker to a Object Storage bucket. | `bool` | `true` | no | +| [enable\_collecting\_failed\_events](#input\_enable\_collecting\_failed\_events) | Set to true to enable Cloud Object Storage integration. If enabled, you must also provide a Cloud Object Storage instance (for storing failed events) using the `existing_cos_instance_crn` variable. For more information, [see here](https://cloud.ibm.com/docs/event-notifications?topic=event-notifications-en-cfe-integrations). | `bool` | `true` | no | +| [enable\_config\_aggregator](#input\_enable\_config\_aggregator) | Set to true to enable configuration aggregator. By setting to true a trusted profile will be created with the required access to record configuration data from all resources across regions in your account. [Learn more](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-ac-configuration-aggregator). | `bool` | `true` | no | | [enable\_metrics](#input\_enable\_metrics) | Set to `true` to enable metrics on the Key Protect instance. Only used if 'create\_key\_protect\_instance' is set to `true`. In order to view metrics, you need an IBM Cloud Monitoring (Sysdig) instance that is located in the same region as the Key Protect instance. After you provision a Monitoring instance, enable platform metrics to monitor your Key Protect instance. | `bool` | `true` | no | | [enable\_metrics\_routing\_to\_cloud\_monitoring](#input\_enable\_metrics\_routing\_to\_cloud\_monitoring) | Whether to enable metrics routing from IBM Cloud Metric Routing to Cloud Monitoring. | `bool` | `true` | no | | [enable\_platform\_metrics](#input\_enable\_platform\_metrics) | When set to `true`, the IBM Cloud Monitoring instance collects the platform metrics. | `bool` | `false` | no | | [enable\_primary\_metadata\_region](#input\_enable\_primary\_metadata\_region) | When set to `true`, sets `primary_metadata_region` to `region`, storing Metrics Router metadata in that region. When `false`, no region is set and the default global region is used. For new accounts, creating targets and routes will fail until primary\_metadata\_region is set, so it is recommended to default enable\_primary\_metadata\_region to true. | `bool` | `true` | no | | [enable\_vpc\_flow\_logs](#input\_enable\_vpc\_flow\_logs) | To enable VPC Flow logs, set this to true. | `bool` | `false` | no | | [event\_notifications\_email\_list](#input\_event\_notifications\_email\_list) | The list of email address to target out when Secrets Manager triggers an event | `list(string)` | `[]` | no | +| [event\_notifications\_endpoint\_url](#input\_event\_notifications\_endpoint\_url) | The URL of the Event Notifications service endpoint to use for notifying configuration changes. For more information on the endpoint URL for Event Notifications, go to [Service endpoints](https://cloud.ibm.com/docs/event-notifications?topic=event-notifications-en-regions-endpoints#en-service-endpoints). It is required if `enable_event_notifications` is set to true. | `string` | `null` | no | | [event\_notifications\_from\_email](#input\_event\_notifications\_from\_email) | The email address used to send any Secrets Manager event coming via Event Notifications | `string` | `"compliancealert@ibm.com"` | no | +| [event\_notifications\_instance\_name](#input\_event\_notifications\_instance\_name) | The name of the Event Notifications instance that is created by this solution. If a `prefix` input variable is specified, it is added to this name in the `-value` format. | `string` | `"event-notifications"` | no | | [event\_notifications\_reply\_to\_email](#input\_event\_notifications\_reply\_to\_email) | The email address specified in the 'reply\_to' section for any Secret Manager event coming via Event Notifications | `string` | `"no-reply@ibm.com"` | no | | [existing\_activity\_tracker\_cos\_target\_bucket\_endpoint](#input\_existing\_activity\_tracker\_cos\_target\_bucket\_endpoint) | The name of an existing Cloud Object Storage bucket endpoint to use for setting up IBM Cloud Activity Tracker Event Routing. If an existing endpoint is not specified, the endpoint of the new Cloud Object Storage bucket is used. | `string` | `null` | no | | [existing\_activity\_tracker\_cos\_target\_bucket\_name](#input\_existing\_activity\_tracker\_cos\_target\_bucket\_name) | The name of an existing bucket within the Cloud Object Storage instance in which to store IBM Cloud Activity Tracker Event Routing. If an existing Cloud Object Storage bucket is not specified, a bucket is created. | `string` | `null` | no | @@ -156,6 +193,7 @@ module "monolith_ocp_add_ons" { | [kms\_encryption\_enabled\_buckets](#input\_kms\_encryption\_enabled\_buckets) | Set to true to enable KMS encryption on the Object Storage buckets created for the IBM Cloud Logs instance. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_cloud_logs_crn`. | `bool` | `false` | no | | [kms\_encryption\_enabled\_cluster](#input\_kms\_encryption\_enabled\_cluster) | Set to true to enable KMS encryption for the cluster's Object Storage bucket. When set to true, a value must be passed for either `existing_cluster_kms_key_crn` or `existing_kms_instance_crn`. | `bool` | `false` | no | | [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_cluster` is true | `string` | `"private"` | no | +| [kms\_endpoint\_url](#input\_kms\_endpoint\_url) | The KMS endpoint URL to use when you configure KMS encryption. When set to true, a value must be passed for either `existing_kms_root_key_crn` or `existing_kms_instance_crn` (to create a new key). The Hyper Protect Crypto Services endpoint URL format is `https://api.private..hs-crypto.cloud.ibm.com:` and the Key Protect endpoint URL format is `https://.kms.cloud.ibm.com`. Not required if passing an existing instance using the `existing_event_notifications_instance_crn` input. | `string` | `null` | no | | [kms\_instance\_name](#input\_kms\_instance\_name) | The name to give the Key Protect instance that that is created by this module. Only used if 'create\_key\_protect\_instance' is set to `true`. | `string` | `"key-protect"` | no | | [kms\_plan](#input\_kms\_plan) | Plan for the Key Protect instance. Supported values are 'tiered-pricing' and 'cross-region-resiliency'. Only used if 'create\_key\_protect\_instance' is set to `true`. | `string` | `"tiered-pricing"` | no | | [kms\_resource\_tags](#input\_kms\_resource\_tags) | Optional list of tags to add to the Key Protect instance. Only used if 'create\_key\_protect\_instance' is set to `true`. | `list(string)` | `[]` | no | @@ -189,7 +227,12 @@ module "monolith_ocp_add_ons" { | [security\_group\_rules](#input\_security\_group\_rules) | A list of security group rules to be added to the default vpc security group (default empty). |
list(
object({
name = string
direction = string
remote = optional(string)
local = optional(string)
ip_version = optional(string)
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
| `[]` | no | | [service\_cred](#input\_service\_cred) | Service configuration for COS. |
list(object({
secret_group_name = string # pragma: allowlist secret
secret_group_description = optional(string) # pragma: allowlist secret
existing_secret_group = optional(bool) # pragma: allowlist secret
service_credentials = list(object({ # pragma: allowlist secret
secret_name = string # pragma: allowlist secret
service_credentials_source_service_role_crn = string # pragma: allowlist secret
secret_labels = optional(list(string)) # pragma: allowlist secret
secret_auto_rotation = optional(bool) # pragma: allowlist secret
secret_auto_rotation_unit = optional(string) # pragma: allowlist secret
secret_auto_rotation_interval = optional(number) # pragma: allowlist secret
service_credentials_ttl = optional(string) # pragma: allowlist secret
service_credential_secret_description = optional(string) # pragma: allowlist secret

}))
}))
| `[]` | no | | [skip\_activity\_tracker\_cos\_auth\_policy](#input\_skip\_activity\_tracker\_cos\_auth\_policy) | To skip creating an IAM authorization policy that allows the Activity Tracker to write to the Cloud Object Storage instance, set this variable to `true`. | `bool` | `false` | no | +| [skip\_app\_config\_event\_notifications\_auth\_policy](#input\_skip\_app\_config\_event\_notifications\_auth\_policy) | Set to true to skip the creation of an IAM authorization policy that permits App configuration instances to integrate with Event Notification in the same account. | `bool` | `false` | no | +| [skip\_app\_config\_kms\_auth\_policy](#input\_skip\_app\_config\_kms\_auth\_policy) | Set to true to skip the creation of an IAM authorization policy that permits App configuration instances in the resource group to read the encryption key from the KMS instance in the same account. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the other account. | `bool` | `false` | no | | [skip\_cloud\_logs\_cos\_auth\_policy](#input\_skip\_cloud\_logs\_cos\_auth\_policy) | To skip creating an IAM authorization policy that allows the IBM Cloud logs to write to the Cloud Object Storage bucket, set this variable to `true`. | `bool` | `false` | no | +| [skip\_event\_notifications\_cos\_auth\_policy](#input\_skip\_event\_notifications\_cos\_auth\_policy) | Set to `true` to skip the creation of an IAM authorization policy that permits the Event Notifications instance `Object Writer` and `Reader` access to the given Object Storage bucket. Set to `true` to use an existing policy. | `bool` | `false` | no | +| [skip\_event\_notifications\_kms\_auth\_policy](#input\_skip\_event\_notifications\_kms\_auth\_policy) | Set to true to skip the creation of an IAM authorization policy that permits the Event Notifications instance to read the encryption key from the KMS instance. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. | `bool` | `false` | no | +| [skip\_event\_notifications\_secrets\_manager\_auth\_policy](#input\_skip\_event\_notifications\_secrets\_manager\_auth\_policy) | Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Event Notification.If set to false, the Secrets Manager instance passed by the user is granted the Key Manager access to the Event Notifications 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\_crn' is not passed. | `bool` | `false` | no | | [skip\_logs\_routing\_auth\_policy](#input\_skip\_logs\_routing\_auth\_policy) | Whether to create an IAM authorization policy that permits the Logs Routing server 'Sender' access to the IBM Cloud Logs instance created by this Deployable Architecture. | `bool` | `false` | no | | [skip\_secrets\_manager\_cos\_iam\_auth\_policy](#input\_skip\_secrets\_manager\_cos\_iam\_auth\_policy) | Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Cloud Object Storage. Set to `true` to use an existing policy. | `bool` | `false` | no | | [skip\_secrets\_manager\_event\_notifications\_iam\_auth\_policy](#input\_skip\_secrets\_manager\_event\_notifications\_iam\_auth\_policy) | If set to true, this skips the creation of a service to service authorization from Secrets Manager to Event Notifications. If false, the service to service authorization is created. | `bool` | `false` | no | @@ -232,6 +275,8 @@ module "monolith_ocp_add_ons" { | [cos\_instance\_crn](#output\_cos\_instance\_crn) | COS instance crn | | [cos\_instance\_guid](#output\_cos\_instance\_guid) | COS instance guid | | [cos\_instance\_id](#output\_cos\_instance\_id) | COS instance ID | +| [en\_crn](#output\_en\_crn) | Event Notification crn | +| [en\_guid](#output\_en\_guid) | Event Notification guid | | [key\_protect\_id](#output\_key\_protect\_id) | Key Protect instance ID when an instance is created, otherwise null | | [kms\_account\_id](#output\_kms\_account\_id) | The account ID of the KMS instance. | | [kms\_config](#output\_kms\_config) | The KMS config needed for OCP cluster | diff --git a/modules/monolith/main.tf b/modules/monolith/main.tf index e5a4551b3..7a33e6fad 100644 --- a/modules/monolith/main.tf +++ b/modules/monolith/main.tf @@ -5,21 +5,21 @@ module "existing_kms_crn_parser" { count = var.existing_kms_instance_crn != null ? 1 : 0 source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.2.0" + version = "1.3.0" crn = var.existing_kms_instance_crn } module "existing_cluster_kms_key_crn_parser" { count = var.existing_cluster_kms_key_crn != null ? 1 : 0 source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.2.0" + version = "1.3.0" crn = var.existing_cluster_kms_key_crn } module "existing_boot_volume_kms_key_crn_parser" { count = var.existing_boot_volume_kms_key_crn != null ? 1 : 0 source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.2.0" + version = "1.3.0" crn = var.existing_boot_volume_kms_key_crn } @@ -101,6 +101,217 @@ module "kms" { cbr_rules = var.kms_cbr_rules } +################################################################################# +# Cloud Monitoring +################################################################################# + +module "existing_cloud_monitoring_crn_parser" { + count = var.existing_cloud_monitoring_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.3.0" + crn = var.existing_cloud_monitoring_crn +} + +locals { + create_cloud_monitoring = var.existing_cloud_monitoring_crn == null + cloud_monitoring_crn = local.create_cloud_monitoring ? module.cloud_monitoring[0].crn : var.existing_cloud_monitoring_crn + cloud_monitoring_instance_name = "${local.prefix}${var.cloud_monitoring_instance_name}" + metrics_router_target_name = "${local.prefix}${var.metrics_routing_target_name}" + metrics_router_route_name = "${local.prefix}${var.metrics_routing_route_name}" + + default_metrics_router_route = var.enable_metrics_routing_to_cloud_monitoring ? [{ + name = local.metrics_router_route_name + rules = [{ + action = "send" + targets = [{ + id = module.metrics_routing[0].metrics_router_targets[local.metrics_router_target_name].id + }] + inclusion_filters = [] + }] + }] : [] +} + +module "cloud_monitoring" { + count = local.create_cloud_monitoring ? 1 : 0 + source = "terraform-ibm-modules/cloud-monitoring/ibm" + version = "1.11.0" + resource_group_id = var.resource_group_id + region = var.region + instance_name = local.cloud_monitoring_instance_name + plan = var.cloud_monitoring_plan + resource_tags = var.cloud_monitoring_resource_tags + access_tags = var.cloud_monitoring_access_tags + resource_keys = var.cloud_monitoring_resource_keys + disable_access_key_creation = var.disable_access_key_creation + service_endpoints = "public-and-private" + enable_platform_metrics = var.enable_platform_metrics + cbr_rules = var.cloud_monitoring_cbr_rules +} + +module "metrics_routing" { + count = var.enable_metrics_routing_to_cloud_monitoring ? 1 : 0 + source = "terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing" + version = "1.11.0" + metrics_router_targets = [ + { + destination_crn = local.cloud_monitoring_crn + target_name = local.metrics_router_target_name + target_region = var.region + skip_metrics_router_auth_policy = false + } + ] + + metrics_router_routes = length(var.metrics_router_routes) != 0 ? var.metrics_router_routes : local.default_metrics_router_route + metrics_router_settings = var.enable_primary_metadata_region ? { primary_metadata_region = var.region } : null +} + + + +######################################################################################################################## +# Event Notifications +######################################################################################################################## + +# If existing EN instance CRN passed, parse details from it +module "existing_en_crn_parser" { + count = var.existing_event_notifications_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.3.0" + crn = var.existing_event_notifications_instance_crn +} + +locals { + use_existing_en_instance = var.existing_event_notifications_instance_crn != null + existing_en_instance_guid = local.use_existing_en_instance ? module.existing_en_crn_parser[0].service_instance : null + eventnotification_guid = local.use_existing_en_instance ? local.existing_en_instance_guid : module.event_notifications[0].guid + eventnotification_crn = local.use_existing_en_instance ? var.existing_event_notifications_instance_crn : module.event_notifications[0].crn + en_cos_bucket_name = "${local.prefix}${var.en_cos_bucket_name}" +} + +module "event_notifications" { + count = local.use_existing_en_instance ? 0 : 1 + source = "terraform-ibm-modules/event-notifications/ibm" + version = "2.7.0" + resource_group_id = var.resource_group_id + region = var.region + name = "${local.prefix}${var.event_notifications_instance_name}" + plan = var.en_service_plan + tags = var.en_resource_tags + access_tags = var.en_access_tags + service_endpoints = var.en_service_endpoints + service_credential_names = var.en_service_credential_names + # KMS Related + kms_encryption_enabled = var.kms_encryption_enabled_cluster + kms_endpoint_url = (var.kms_encryption_enabled_boot_volume && var.existing_boot_volume_kms_key_crn == null) || (var.kms_encryption_enabled_cluster && var.existing_cluster_kms_key_crn == null) ? var.kms_endpoint_type == "private" ? module.kms[0].kms_private_endpoint : module.kms[0].kms_public_endpoint : var.kms_endpoint_url + existing_kms_instance_crn = var.existing_kms_instance_crn != null ? var.existing_kms_instance_crn : module.kms[0].key_protect_crn + root_key_id = local.cluster_kms_key_id + skip_en_kms_auth_policy = var.skip_event_notifications_kms_auth_policy + # COS Related + cos_integration_enabled = var.enable_collecting_failed_events + cos_bucket_name = var.existing_event_notifications_instance_crn == null && var.enable_collecting_failed_events ? module.en_cos_buckets[0].buckets[local.en_cos_bucket_name].bucket_name : null + cos_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id + skip_en_cos_auth_policy = var.skip_event_notifications_cos_auth_policy + cos_endpoint = var.existing_event_notifications_instance_crn == null && var.enable_collecting_failed_events ? "https://${module.en_cos_buckets[0].buckets[local.en_cos_bucket_name].s3_endpoint_direct}" : null + cbr_rules = var.en_cbr_rules +} + +locals { + bucket_config = [{ + access_tags = var.en_cos_bucket_access_tags + bucket_name = local.en_cos_bucket_name + add_bucket_name_suffix = var.append_random_bucket_name_suffix + kms_encryption_enabled = var.kms_encryption_enabled_buckets + kms_guid = local.cluster_existing_kms_guid + kms_key_crn = local.cluster_kms_key_crn + skip_iam_authorization_policy = false + management_endpoint_type = var.management_endpoint_type_for_buckets + storage_class = var.cos_buckets_class + resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id + region_location = var.region + activity_tracking = { + read_data_events = true + write_data_events = true + management_events = true + } + metrics_monitoring = { + usage_metrics_enabled = true + request_metrics_enabled = true + metrics_monitoring_crn = var.existing_cloud_monitoring_crn != null ? var.existing_cloud_monitoring_crn : module.cloud_monitoring[0].crn + } + force_delete = true + }] +} + +module "en_cos_buckets" { + count = var.enable_collecting_failed_events && var.existing_event_notifications_instance_crn == null ? 1 : 0 + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.8" + bucket_configs = local.bucket_config +} + +######################################################################################################################## +# Service Credentials +######################################################################################################################## + +# If existing EN instance CRN passed, parse details from it +module "existing_sm_crn_parser" { + count = var.existing_secrets_manager_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.3.0" + crn = var.existing_secrets_manager_crn +} + +locals { + en_service_credential_secrets = [ + for service_credentials in var.en_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_crn = secret.service_credentials_source_service_role_crn + service_credentials_source_service_crn = local.eventnotification_crn + secret_type = "service_credentials" #checkov:skip=CKV_SECRET_6 + } + ] + } + ] +} + +# create a service authorization between Secrets Manager and the target service (Event Notification) +resource "ibm_iam_authorization_policy" "en_secrets_manager_key_manager" { + count = var.skip_event_notifications_secrets_manager_auth_policy || var.existing_secrets_manager_crn == null ? 0 : 1 + source_service_name = "secrets-manager" + source_resource_instance_id = local.existing_secrets_manager_instance_guid + target_service_name = "event-notifications" + target_resource_instance_id = local.eventnotification_guid + roles = ["Key Manager"] + description = "Allow Secrets Manager instance to manage key for the event-notification instance" +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_en_authorization_policy" { + depends_on = [ibm_iam_authorization_policy.en_secrets_manager_key_manager] + create_duration = "30s" +} + +module "en_secrets_manager_service_credentials" { + count = length(local.en_service_credential_secrets) > 0 ? 1 : 0 + depends_on = [time_sleep.wait_for_en_authorization_policy] + source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets" + version = "2.11.9" + existing_sm_instance_guid = local.existing_secrets_manager_instance_guid + existing_sm_instance_region = local.existing_secrets_manager_instance_region + endpoint_type = var.secrets_manager_endpoint_type + secrets = local.en_service_credential_secrets +} + ################################################################################# # Secrets Manager ################################################################################# @@ -111,7 +322,6 @@ locals { secrets_manager_guid = var.existing_secrets_manager_crn != null ? (length(local.parsed_existing_secrets_manager_crn) > 0 ? local.parsed_existing_secrets_manager_crn[7] : null) : module.secrets_manager[0].secrets_manager_guid secrets_manager_crn = var.existing_secrets_manager_crn != null ? var.existing_secrets_manager_crn : module.secrets_manager[0].secrets_manager_crn secrets_manager_region = var.existing_secrets_manager_crn != null ? (length(local.parsed_existing_secrets_manager_crn) > 0 ? local.parsed_existing_secrets_manager_crn[5] : null) : module.secrets_manager[0].secrets_manager_region - enable_event_notifications = var.existing_event_notifications_instance_crn == null || var.existing_event_notifications_instance_crn == "" ? false : true secret_groups_with_prefix = [ for group in var.secret_groups : merge(group, { access_group_name = group.access_group_name != null ? "${local.prefix}${group.access_group_name}" : null @@ -143,8 +353,8 @@ module "secrets_manager" { kms_key_crn = local.cluster_kms_key_crn skip_kms_iam_authorization_policy = var.skip_secrets_manager_kms_iam_auth_policy #|| local.create_cross_account_auth_policy # event notifications dependency - enable_event_notification = local.enable_event_notifications - existing_en_instance_crn = local.enable_event_notifications ? var.existing_event_notifications_instance_crn : null + enable_event_notification = true + existing_en_instance_crn = local.eventnotification_crn skip_en_iam_authorization_policy = var.skip_secrets_manager_event_notifications_iam_auth_policy cbr_rules = var.secrets_manager_cbr_rules endpoint_type = var.secrets_manager_endpoint_type @@ -157,28 +367,28 @@ module "secrets_manager" { ################################################################################# locals { - parsed_existing_en_instance_crn = var.existing_event_notifications_instance_crn == null || var.existing_event_notifications_instance_crn == "" ? [] : split(":", var.existing_event_notifications_instance_crn) + parsed_existing_en_instance_crn = split(":", local.eventnotification_crn) existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null } -data "ibm_en_destinations" "en_destinations" { +data "ibm_en_destinations" "en_sm_destinations" { # if existing SM instance CRN is passed (!= null), then never do data lookup for EN destinations - count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && local.enable_secrets_manager_cluster ? 1 : 0 + count = var.existing_secrets_manager_crn == null && local.enable_secrets_manager_cluster ? 1 : 0 instance_guid = local.existing_en_guid } # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5533 resource "time_sleep" "wait_for_secrets_manager" { # if existing SM instance CRN is passed (!= null), then never work with EN - count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && local.enable_secrets_manager_cluster ? 1 : 0 + count = var.existing_secrets_manager_crn == null && local.enable_secrets_manager_cluster ? 1 : 0 depends_on = [module.secrets_manager] create_duration = "30s" } -resource "ibm_en_topic" "en_topic" { +resource "ibm_en_topic" "en_sm_topic" { # if existing SM instance CRN is passed (!= null), then never create EN topic - count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && local.enable_secrets_manager_cluster ? 1 : 0 + count = var.existing_secrets_manager_crn == null && local.enable_secrets_manager_cluster ? 1 : 0 depends_on = [time_sleep.wait_for_secrets_manager] instance_guid = local.existing_en_guid name = "Topic for Secrets Manager instance ${module.secrets_manager[0].secrets_manager_guid}" @@ -192,14 +402,14 @@ resource "ibm_en_topic" "en_topic" { } } -resource "ibm_en_subscription_email" "email_subscription" { +resource "ibm_en_subscription_email" "en_email_subscription" { # if existing SM instance CRN is passed (!= null), then never create EN email subscription - count = var.existing_secrets_manager_crn == null && local.enable_event_notifications && length(var.event_notifications_email_list) > 0 && local.enable_secrets_manager_cluster ? 1 : 0 + count = var.existing_secrets_manager_crn == null && length(var.event_notifications_email_list) > 0 && local.enable_secrets_manager_cluster ? 1 : 0 instance_guid = local.existing_en_guid name = "Email for Secrets Manager Subscription" description = "Subscription for Secret Manager Events" - destination_id = [for s in toset(data.ibm_en_destinations.en_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] - topic_id = ibm_en_topic.en_topic[count.index].topic_id + destination_id = [for s in toset(data.ibm_en_destinations.en_sm_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_sm_topic[count.index].topic_id attributes { add_notification_payload = true reply_to_mail = var.event_notifications_reply_to_email @@ -218,7 +428,7 @@ locals { existing_secrets_manager_instance_guid = var.existing_secrets_manager_crn != null ? module.secrets_manager_crn_parser[0].service_instance : local.enable_secrets_manager_cluster ? module.secrets_manager[0].secrets_manager_guid : "" existing_secrets_manager_instance_region = var.existing_secrets_manager_crn != null ? module.secrets_manager_crn_parser[0].region : local.enable_secrets_manager_cluster ? module.secrets_manager[0].secrets_manager_region : "" - service_credential_secrets = [ + cos_service_credential_secrets = [ for service_credentials in var.service_cred : { secret_group_name = service_credentials.secret_group_name secret_group_description = service_credentials.secret_group_description @@ -267,7 +477,7 @@ module "cos" { ################################################################################# # create s2s auth policy with Secrets Manager -resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { +resource "ibm_iam_authorization_policy" "cos_secrets_manager_key_manager" { count = !var.skip_secrets_manager_cos_iam_auth_policy && (var.existing_secrets_manager_crn != null || local.enable_secrets_manager_cluster) ? 1 : 0 source_service_name = "secrets-manager" source_resource_instance_id = local.existing_secrets_manager_instance_guid @@ -279,84 +489,20 @@ resource "ibm_iam_authorization_policy" "secrets_manager_key_manager" { # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 resource "time_sleep" "wait_for_cos_authorization_policy" { - count = length(local.service_credential_secrets) > 0 ? 1 : 0 - depends_on = [ibm_iam_authorization_policy.secrets_manager_key_manager] + count = length(local.cos_service_credential_secrets) > 0 ? 1 : 0 + depends_on = [ibm_iam_authorization_policy.cos_secrets_manager_key_manager] create_duration = "30s" } -module "secrets_manager_service_credentials" { - count = length(local.service_credential_secrets) > 0 ? 1 : 0 +module "cos_secrets_manager_service_credentials" { + count = length(local.cos_service_credential_secrets) > 0 ? 1 : 0 depends_on = [time_sleep.wait_for_cos_authorization_policy] source = "terraform-ibm-modules/secrets-manager/ibm//modules/secrets" version = "2.11.9" existing_sm_instance_guid = local.existing_secrets_manager_instance_guid existing_sm_instance_region = local.existing_secrets_manager_instance_region endpoint_type = var.secrets_manager_endpoint_type - secrets = local.service_credential_secrets -} - -################################################################################# -# Cloud Monitoring -################################################################################# - -module "existing_cloud_monitoring_crn_parser" { - count = var.existing_cloud_monitoring_crn != null ? 1 : 0 - source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.3.0" - crn = var.existing_cloud_monitoring_crn -} - -locals { - create_cloud_monitoring = var.existing_cloud_monitoring_crn == null - cloud_monitoring_crn = local.create_cloud_monitoring ? module.cloud_monitoring[0].crn : var.existing_cloud_monitoring_crn - cloud_monitoring_instance_name = "${local.prefix}${var.cloud_monitoring_instance_name}" - metrics_router_target_name = "${local.prefix}${var.metrics_routing_target_name}" - metrics_router_route_name = "${local.prefix}${var.metrics_routing_route_name}" - - default_metrics_router_route = var.enable_metrics_routing_to_cloud_monitoring ? [{ - name = local.metrics_router_route_name - rules = [{ - action = "send" - targets = [{ - id = module.metrics_routing[0].metrics_router_targets[local.metrics_router_target_name].id - }] - inclusion_filters = [] - }] - }] : [] -} - -module "cloud_monitoring" { - count = local.create_cloud_monitoring ? 1 : 0 - source = "terraform-ibm-modules/cloud-monitoring/ibm" - version = "1.11.0" - resource_group_id = var.resource_group_id - region = var.region - instance_name = local.cloud_monitoring_instance_name - plan = var.cloud_monitoring_plan - resource_tags = var.cloud_monitoring_resource_tags - access_tags = var.cloud_monitoring_access_tags - resource_keys = var.cloud_monitoring_resource_keys - disable_access_key_creation = var.disable_access_key_creation - service_endpoints = "public-and-private" - enable_platform_metrics = var.enable_platform_metrics - cbr_rules = var.cloud_monitoring_cbr_rules -} - -module "metrics_routing" { - count = var.enable_metrics_routing_to_cloud_monitoring ? 1 : 0 - source = "terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing" - version = "1.11.0" - metrics_router_targets = [ - { - destination_crn = local.cloud_monitoring_crn - target_name = local.metrics_router_target_name - target_region = var.region - skip_metrics_router_auth_policy = false - } - ] - - metrics_router_routes = length(var.metrics_router_routes) != 0 ? var.metrics_router_routes : local.default_metrics_router_route - metrics_router_settings = var.enable_primary_metadata_region ? { primary_metadata_region = var.region } : null + secrets = local.cos_service_credential_secrets } ################################################################################# @@ -409,7 +555,7 @@ module "cloud_logs" { module "cloud_logs_buckets" { source = "terraform-ibm-modules/cos/ibm//modules/buckets" - version = "10.5.7" + version = "10.5.8" bucket_configs = [ { bucket_name = local.data_bucket_name @@ -420,7 +566,7 @@ module "cloud_logs_buckets" { resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id add_bucket_name_suffix = var.append_random_bucket_name_suffix management_endpoint_type = var.management_endpoint_type_for_buckets - storage_class = var.cloud_logs_cos_buckets_class + storage_class = var.cos_buckets_class force_delete = true # If this is set to false, and the bucket contains data, the destroy will fail. Setting it to false on destroy has no impact, it has to be set on apply, so hence hard coding to true." activity_tracking = { read_data_events = true @@ -442,7 +588,7 @@ module "cloud_logs_buckets" { resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id add_bucket_name_suffix = var.append_random_bucket_name_suffix management_endpoint_type = var.management_endpoint_type_for_buckets - storage_class = var.cloud_logs_cos_buckets_class + storage_class = var.cos_buckets_class skip_iam_authorization_policy = true force_delete = true # If this is set to false, and the bucket contains data, the destroy will fail. Setting it to false on destroy has no impact, it has to be set on apply, so hence hard coding to true." activity_tracking = { @@ -571,6 +717,79 @@ module "at_cos_bucket" { ] } +######################################################################################################################## +# App Config +######################################################################################################################## +module "app_config" { + source = "terraform-ibm-modules/app-configuration/ibm" + version = "1.14.2" + resource_group_id = var.resource_group_id + region = var.region + app_config_name = "${local.prefix}${var.app_config_name}" + app_config_plan = var.app_config_plan + app_config_service_endpoints = var.app_config_service_endpoints + app_config_tags = var.app_config_tags + app_config_collections = var.app_config_collections + enable_config_aggregator = var.enable_config_aggregator + config_aggregator_trusted_profile_name = "${local.prefix}${var.config_aggregator_trusted_profile_name}" + config_aggregator_resource_collection_regions = var.config_aggregator_resource_collection_regions + config_aggregator_enterprise_id = var.config_aggregator_enterprise_id + config_aggregator_enterprise_trusted_profile_name = "${local.prefix}${var.config_aggregator_enterprise_trusted_profile_name}" + config_aggregator_enterprise_trusted_profile_template_name = "${local.prefix}${var.config_aggregator_enterprise_trusted_profile_template_name}" + config_aggregator_enterprise_account_group_ids_to_assign = var.config_aggregator_enterprise_account_group_ids_to_assign + config_aggregator_enterprise_account_ids_to_assign = var.config_aggregator_enterprise_account_ids_to_assign + cbr_rules = var.apprapp_cbr_rules + kms_encryption_enabled = var.kms_encryption_enabled_cluster + skip_app_config_kms_auth_policy = var.skip_app_config_kms_auth_policy + existing_kms_instance_crn = var.existing_kms_instance_crn != null ? var.existing_kms_instance_crn : module.kms[0].key_protect_crn + kms_endpoint_url = (var.kms_encryption_enabled_boot_volume && var.existing_boot_volume_kms_key_crn == null) || (var.kms_encryption_enabled_cluster && var.existing_cluster_kms_key_crn == null) ? var.kms_endpoint_type == "private" ? module.kms[0].kms_private_endpoint : module.kms[0].kms_public_endpoint : var.kms_endpoint_url + root_key_id = local.cluster_kms_key_id + enable_event_notifications = true + skip_app_config_event_notifications_auth_policy = var.skip_app_config_event_notifications_auth_policy + existing_event_notifications_instance_crn = local.eventnotification_crn + event_notifications_endpoint_url = var.existing_event_notifications_instance_crn != null ? var.event_notifications_endpoint_url : var.en_service_endpoints == "private" ? module.event_notifications[0].event_notifications_private_endpoint : module.event_notifications[0].event_notifications_public_endpoint + app_config_event_notifications_source_name = "${local.prefix}${var.app_config_event_notifications_source_name}" + event_notifications_integration_description = "The App Configuration integration to send notifications of events to users from the Event Notifications instance GUID ${local.existing_en_guid}" +} + +####################################################################################################################### +# App Configuration Event Notifications Configuration +####################################################################################################################### + +data "ibm_en_destinations" "en_apprapp_destinations" { + instance_guid = local.existing_en_guid +} + +resource "ibm_en_topic" "en_apprapp_topic" { + depends_on = [module.app_config] + instance_guid = local.existing_en_guid + name = "Topic for App Configuration instance ${module.app_config.app_config_guid}" + description = "Topic for App Configuration events routing" + sources { + id = module.app_config.app_config_crn + rules { + enabled = true + event_type_filter = "$.*" + } + } +} + +resource "ibm_en_subscription_email" "apprapp_email_subscription" { + count = length(var.event_notifications_email_list) > 0 ? 1 : 0 + instance_guid = local.existing_en_guid + name = "Email for App Configuration Subscription" + description = "Subscription for App Configuration Events" + destination_id = [for s in toset(data.ibm_en_destinations.en_apprapp_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_apprapp_topic[count.index].topic_id + attributes { + add_notification_payload = true + reply_to_mail = var.event_notifications_reply_to_email + reply_to_name = "App Configuration Event Notifications Bot" + from_name = var.event_notifications_from_email + invited = var.event_notifications_email_list + } +} + ################################################################################# # SCC Workload Protection ################################################################################# @@ -592,14 +811,12 @@ module "scc_wp" { cloud_monitoring_instance_crn = var.existing_cloud_monitoring_crn != null ? var.existing_cloud_monitoring_crn : module.cloud_monitoring[0].crn access_tags = var.scc_workload_protection_access_tags scc_wp_service_plan = var.scc_workload_protection_service_plan - app_config_crn = var.app_config_crn + app_config_crn = module.app_config.app_config_crn scc_workload_protection_trusted_profile_name = "${local.prefix}${var.scc_workload_protection_trusted_profile_name}" cbr_rules = var.scc_wp_cbr_rules cspm_enabled = var.cspm_enabled } - - ############################################################################# # COS Bucket for VPC flow logs ############################################################################# @@ -617,7 +834,7 @@ locals { kms_key_crn = local.cluster_kms_key_crn skip_iam_authorization_policy = true management_endpoint_type = var.management_endpoint_type_for_buckets - storage_class = var.cloud_logs_cos_buckets_class + storage_class = var.cos_buckets_class resource_instance_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_id region_location = var.region force_delete = true diff --git a/modules/monolith/outputs.tf b/modules/monolith/outputs.tf index d43df4a98..b66be2b21 100644 --- a/modules/monolith/outputs.tf +++ b/modules/monolith/outputs.tf @@ -145,6 +145,21 @@ output "boot_volume_kms_account_id" { value = local.boot_volume_kms_account_id } +############################################################################## +# EN Outputs +############################################################################## + +output "en_crn" { + description = "Event Notification crn" + value = local.eventnotification_crn +} + +output "en_guid" { + description = "Event Notification guid" + value = local.eventnotification_guid +} + + ############################################################################## # SM Outputs ############################################################################## diff --git a/modules/monolith/variables.tf b/modules/monolith/variables.tf index 73ca707b8..4025f2ec9 100644 --- a/modules/monolith/variables.tf +++ b/modules/monolith/variables.tf @@ -253,6 +253,178 @@ variable "kms_cbr_rules" { } } +######################################################################################################################## +# Event Notifications +######################################################################################################################## + +variable "event_notifications_instance_name" { + type = string + description = "The name of the Event Notifications instance that is created by this solution. If a `prefix` input variable is specified, it is added to this name in the `-value` format." + default = "event-notifications" +} + +variable "en_service_plan" { + type = string + description = "The pricing plan of the Event Notifications instance. Possible values: `Lite`, `Standard`." + default = "standard" + validation { + condition = contains(["lite", "standard"], var.en_service_plan) + error_message = "The specified pricing plan is not available. The following plans are supported: `Lite`, `Standard`" + } +} + +variable "en_service_endpoints" { + type = string + description = "Specify whether you want to enable public, private, or both public and private service endpoints. Possible values: `public`, `private`, `public-and-private`." + default = "private" + validation { + condition = contains(["public", "private", "public-and-private"], var.en_service_endpoints) + error_message = "The specified service endpoint is not supported. The following endpoint options are supported: `public`, `private`, `public-and-private`" + } +} + +variable "en_resource_tags" { + type = list(string) + description = "The list of tags to add to the Event Notifications instance." + default = [] +} + +variable "en_access_tags" { + type = list(string) + description = "A list of access tags to apply to the Event Notifications instance created by the solution. For more information, [see here](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial)." + default = [] + + validation { + condition = alltrue([ + for tag in var.en_access_tags : can(regex("[\\w\\-_\\.]+:[\\w\\-_\\.]+", tag)) && length(tag) <= 128 + ]) + error_message = "Tags must match the regular expression \"[\\w\\-_\\.]+:[\\w\\-_\\.]+\". For more information, [see here](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#limit)." + } +} + +variable "en_service_credential_names" { + type = map(string) + description = "A mapping of names and associated roles for service credentials that you want to create for the Event Notifications instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/blob/main/solutions/fully-configurable/DA-types.md#service-credentials-)." + default = {} + + validation { + condition = alltrue([for name, role in var.en_service_credential_names : contains(["Manager", "Writer", "Reader", "Event Source Manager", "Channel Editor", "Event Notification Publisher", "Status Reporter", "Device Manager", "Email Sender", "Custom Email Status Reporter"], role)]) + error_message = "The specified service credential role is not valid. The following values are valid for service credential roles: 'Manager', 'Writer', 'Reader', 'Event Source Manager', 'Channel Editor', 'Event Notification Publisher', 'Status Reporter', 'Device Manager', 'Email Sender', 'Custom Email Status Reporter'" + } +} + +variable "kms_endpoint_url" { + type = string + description = "The KMS endpoint URL to use when you configure KMS encryption. When set to true, a value must be passed for either `existing_kms_root_key_crn` or `existing_kms_instance_crn` (to create a new key). The Hyper Protect Crypto Services endpoint URL format is `https://api.private..hs-crypto.cloud.ibm.com:` and the Key Protect endpoint URL format is `https://.kms.cloud.ibm.com`. Not required if passing an existing instance using the `existing_event_notifications_instance_crn` input." + default = null +} + +variable "skip_event_notifications_kms_auth_policy" { + type = bool + description = "Set to true to skip the creation of an IAM authorization policy that permits the Event Notifications instance to read the encryption key from the KMS instance. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account." + default = false +} + +variable "enable_collecting_failed_events" { + type = bool + description = "Set to true to enable Cloud Object Storage integration. If enabled, you must also provide a Cloud Object Storage instance (for storing failed events) using the `existing_cos_instance_crn` variable. For more information, [see here](https://cloud.ibm.com/docs/event-notifications?topic=event-notifications-en-cfe-integrations)." + default = true +} + +variable "en_cos_bucket_name" { + type = string + description = "The name to use when creating the Object Storage bucket for the storage of failed delivery events. Bucket names are globally unique. If `add_bucket_name_suffix` is set to `true`, a random 4 character string is added to this name to help ensure that the bucket name is unique. If a `prefix` input variable is specified, it is added to this name in the `-value` format." + default = "base-event-notifications-bucket" +} + +variable "en_cos_bucket_access_tags" { + type = list(string) + description = "A list of access tags to apply to the Cloud Object Storage bucket created by the solution. For more information, [see here](https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial)." + default = [] + + validation { + condition = alltrue([ + for tag in var.en_cos_bucket_access_tags : can(regex("[\\w\\-_\\.]+:[\\w\\-_\\.]+", tag)) && length(tag) <= 128 + ]) + error_message = "Tags must match the regular expression \"[\\w\\-_\\.]+:[\\w\\-_\\.]+\". For more information, [see here](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#limits)." + } +} + +variable "skip_event_notifications_secrets_manager_auth_policy" { + type = bool + default = false + description = "Whether an IAM authorization policy is created for Secrets Manager instance to create a service credential secrets for Event Notification.If set to false, the Secrets Manager instance passed by the user is granted the Key Manager access to the Event Notifications 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_crn' is not passed." +} + +variable "en_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The list of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/fully-configurable/DA-cbr_rules.md)." + default = [] +} + +variable "en_service_credential_secrets" { # pragma: allowlist secret + type = list(object({ + secret_group_name = string # pragma: allowlist secret + secret_group_description = optional(string) # pragma: allowlist secret + existing_secret_group = optional(bool) # pragma: allowlist secret + service_credentials = list(object({ # pragma: allowlist secret + secret_name = string # pragma: allowlist secret + service_credentials_source_service_role_crn = string # pragma: allowlist secret + secret_labels = optional(list(string)) # pragma: allowlist secret + secret_auto_rotation = optional(bool) # pragma: allowlist secret + secret_auto_rotation_unit = optional(string) # pragma: allowlist secret + secret_auto_rotation_interval = optional(number) # pragma: allowlist secret + service_credentials_ttl = optional(string) # pragma: allowlist secret + service_credential_secret_description = optional(string) # pragma: allowlist secret + + })) + })) + default = [] + description = "Service credential secrets configuration for Event Notification. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/fully-configurable/DA-types.md#service-credential-secrets)." + + validation { + # Service roles CRNs can be found at https://cloud.ibm.com/iam/roles, select Event Notifications and select the role + condition = alltrue([ + for group in var.en_service_credential_secrets : alltrue([ + # crn:v?:bluemix; two non-empty segments; three possibly empty segments; :serviceRole or role: non-empty segment + for credential in group.service_credentials : can(regex("^crn:v[0-9]:bluemix(:..*){2}(:.*){3}:(serviceRole|role):..*$", credential.service_credentials_source_service_role_crn)) + ]) + ]) + error_message = "Provided value of `service_credentials_source_service_role_crn` is not valid. Refer [this](https://cloud.ibm.com/iam/roles) for allowed role/values." + } + validation { + condition = length(var.en_service_credential_secrets) > 0 ? var.existing_secrets_manager_crn != null : true + error_message = "'existing_secrets_manager_crn' is required when adding service credentials with the 'service_credential_secrets' input." + } + +} + +variable "skip_event_notifications_cos_auth_policy" { + type = bool + description = "Set to `true` to skip the creation of an IAM authorization policy that permits the Event Notifications instance `Object Writer` and `Reader` access to the given Object Storage bucket. Set to `true` to use an existing policy." + default = false +} + +variable "event_notifications_endpoint_url" { + type = string + description = "The URL of the Event Notifications service endpoint to use for notifying configuration changes. For more information on the endpoint URL for Event Notifications, go to [Service endpoints](https://cloud.ibm.com/docs/event-notifications?topic=event-notifications-en-regions-endpoints#en-service-endpoints). It is required if `enable_event_notifications` is set to true." + default = null +} + ############################################################## # Secrets Manager ############################################################## @@ -783,12 +955,12 @@ variable "management_endpoint_type_for_buckets" { } } -variable "cloud_logs_cos_buckets_class" { +variable "cos_buckets_class" { type = string default = "smart" description = "The storage class of the newly provisioned IBM Cloud Logs Object Storage buckets. Possible values: `standard` or `smart`. Applies only if `existing_cloud_logs_crn` is not provided." validation { - condition = contains(["standard", "smart"], var.cloud_logs_cos_buckets_class) + condition = contains(["standard", "smart"], var.cos_buckets_class) error_message = "Allowed values for cos_bucket_class are \"standard\" or \"smart\"." } } @@ -1018,6 +1190,186 @@ variable "skip_activity_tracker_cos_auth_policy" { default = false } +######################################################################################################################## +# App Config variables +######################################################################################################################## + +variable "app_config_name" { + type = string + description = "Name for the App Configuration service instance." + default = "app-config" + nullable = false +} + +variable "app_config_plan" { + type = string + description = "Plan for the App Configuration service instance." + default = "enterprise" + nullable = false +} + +variable "app_config_service_endpoints" { + type = string + description = "Service Endpoints for the App Configuration service instance, valid endpoints are public or public-and-private." + default = "public-and-private" + nullable = false + + validation { + condition = contains(["public", "public-and-private"], var.app_config_service_endpoints) + error_message = "Value for service endpoints must be one of the following: \"public\" or \"public-and-private\"." + } +} + +variable "app_config_collections" { + description = "(Optional, list) A list of collections to be added to the App Configuration instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-app-configuration/tree/main/solutions/fully-configurable/DA-collections.md)." + type = list(object({ + name = string + collection_id = string + description = optional(string, null) + tags = optional(string, null) + })) + default = [] + + validation { + condition = ( + var.app_config_plan != "lite" || + length(var.app_config_collections) <= 1 + ) + error_message = "When using the 'lite' plan, you can define at most 1 App Configuration collection." + } +} + +variable "app_config_tags" { + type = list(string) + description = "Optional list of tags to be added to the App Config instance." + default = [] +} + +variable "enable_config_aggregator" { + description = "Set to true to enable configuration aggregator. By setting to true a trusted profile will be created with the required access to record configuration data from all resources across regions in your account. [Learn more](https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-ac-configuration-aggregator)." + type = bool + default = true + nullable = false + + # Lite plan does not support enabling Config Aggregator as mention in doc : https://cloud.ibm.com/docs/app-configuration?topic=app-configuration-ac-configuration-aggregator + validation { + condition = !(var.enable_config_aggregator && var.app_config_plan == "lite") + error_message = "The configuration aggregator cannot be enabled when the app_config_plan is set to 'lite'. Please use a different plan (e.g., 'basic', 'standardv2', or 'enterprise')." + } +} + +variable "config_aggregator_trusted_profile_name" { + description = "The name to give the trusted profile that will be created if `enable_config_aggregator` is set to `true`. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string + default = "config-aggregator-trusted-profile" + + validation { + condition = var.enable_config_aggregator ? var.config_aggregator_trusted_profile_name != null : true + error_message = "'config_aggregator_trusted_profile_name' cannot be null if 'enable_config_aggregator' is true." + } +} + +variable "config_aggregator_resource_collection_regions" { + type = list(string) + description = "From which region do you want to collect configuration data? Only applies if `enable_config_aggregator` is set to true." + default = ["all"] +} + +variable "config_aggregator_enterprise_id" { + type = string + description = "If the account is an enterprise account, this value should be set to the enterprise ID (NOTE: This is different to the account ID). " + default = null + + validation { + condition = !var.enable_config_aggregator ? var.config_aggregator_enterprise_id == null : true + error_message = "A value can only be passed for 'config_aggregator_enterprise_id' if 'enable_config_aggregator' is true." + } +} + +variable "config_aggregator_enterprise_trusted_profile_name" { + description = "The name to give the enterprise viewer trusted profile with that will be created if `enable_config_aggregator` is set to `true` and a value is passed for `config_aggregator_enterprise_id`. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string + default = "config-aggregator-enterprise-trusted-profile" + + validation { + condition = var.enable_config_aggregator && var.config_aggregator_enterprise_id != null ? var.config_aggregator_enterprise_trusted_profile_name != null : true + error_message = "'config_aggregator_enterprise_trusted_profile_name' cannot be null if 'enable_config_aggregator' is true and a value is being passed for 'config_aggregator_enterprise_id'." + } +} + +variable "config_aggregator_enterprise_trusted_profile_template_name" { + description = "The name to give the trusted profile template that will be created if `enable_config_aggregator` is set to `true` and a value is passed for `config_aggregator_enterprise_id`. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string + default = "config-aggregator-trusted-profile-template" + + validation { + condition = var.enable_config_aggregator && var.config_aggregator_enterprise_id != null ? var.config_aggregator_enterprise_trusted_profile_template_name != null : true + error_message = "'config_aggregator_enterprise_trusted_profile_template_name' cannot be null if 'enable_config_aggregator' is true and a value is being passed for 'config_aggregator_enterprise_id'." + } +} + +variable "config_aggregator_enterprise_account_group_ids_to_assign" { + type = list(string) + default = ["all"] + description = "A list of enterprise account group IDs to assign the trusted profile template to in order for the accounts to be scanned. Supports passing the string 'all' in the list to assign to all account groups. Only applies if `enable_config_aggregator` is true and a value is being passed for `config_aggregator_enterprise_id`." + nullable = false + + validation { + condition = contains(var.config_aggregator_enterprise_account_group_ids_to_assign, "all") ? length(var.config_aggregator_enterprise_account_group_ids_to_assign) == 1 : true + error_message = "When specifying 'all' in the list, you cannot add any other values to the list" + } +} + +variable "config_aggregator_enterprise_account_ids_to_assign" { + type = list(string) + default = [] + description = "A list of enterprise account IDs to assign the trusted profile template to in order for the accounts to be scanned. Supports passing the string 'all' in the list to assign to all accounts. Only applies if `enable_config_aggregator` is true and a value is being passed for `config_aggregator_enterprise_id`." + nullable = false + + validation { + condition = contains(var.config_aggregator_enterprise_account_ids_to_assign, "all") ? length(var.config_aggregator_enterprise_account_ids_to_assign) == 1 : true + error_message = "When specifying 'all' in the list, you cannot add any other values to the list" + } +} + +variable "skip_app_config_kms_auth_policy" { + type = bool + description = "Set to true to skip the creation of an IAM authorization policy that permits App configuration instances in the resource group to read the encryption key from the KMS instance in the same account. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the other account." + default = false +} + +variable "skip_app_config_event_notifications_auth_policy" { + type = bool + description = "Set to true to skip the creation of an IAM authorization policy that permits App configuration instances to integrate with Event Notification in the same account." + default = false +} + +variable "app_config_event_notifications_source_name" { + type = string + description = "The name by which Event Notifications source will be created in the existing Event Notification instance." + default = "app-config-en" +} + +variable "apprapp_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "The list of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-event-notifications/tree/main/solutions/fully-configurable/DA-cbr_rules.md)." + default = [] +} + ####################################################################################################################### # SCC Workload Protection ####################################################################################################################### @@ -1083,27 +1435,10 @@ variable "scc_workload_protection_service_plan" { variable "cspm_enabled" { description = "Enable Cloud Security Posture Management (CSPM) for the Workload Protection instance. This will create a trusted profile associated with the SCC Workload Protection instance that has viewer / reader access to the App Config service and viewer access to the Enterprise service." type = bool - default = false + default = true nullable = false } -variable "app_config_crn" { - description = "The CRN of an existing App Config instance to use with the SCC Workload Protection instance. Required if `cspm_enabled` is true. NOTE: Ensure the App Config instance has configuration aggregator enabled." - type = string - default = null - validation { - condition = var.cspm_enabled ? var.app_config_crn != null : true - error_message = "Cannot be `null` if CSPM is enabled." - } - validation { - condition = anytrue([ - can(regex("^crn:(.*:){3}apprapp:(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.app_config_crn)), - var.app_config_crn == null, - ]) - error_message = "The provided CRN is not a valid App Config CRN." - } -} - variable "scc_wp_cbr_rules" { type = list(object({ description = string diff --git a/tests/other_test.go b/tests/other_test.go index 8a26d9a1a..7e581746e 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -2,18 +2,11 @@ package test import ( - "fmt" - "os" - "strings" "testing" "github.com/IBM/go-sdk-core/v5/core" - "github.com/gruntwork-io/terratest/modules/files" - "github.com/gruntwork-io/terratest/modules/logger" - "github.com/gruntwork-io/terratest/modules/random" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testaddons" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" @@ -201,99 +194,45 @@ func TestFSCloudInSchematic(t *testing.T) { assert.Nil(t, err, "This should not have errored") } -func provisionPreReq(t *testing.T, p string) (string, *terraform.Options, error) { - // ------------------------------------------------------------------------------------ - // Provision existing resources first - // ------------------------------------------------------------------------------------ - prefix := fmt.Sprintf("%s-%s", p, strings.ToLower(random.UniqueId())) - realTerraformDir := "./existing-resources-monolith" - tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, prefix) - - // Verify ibmcloud_api_key variable is set - checkVariable := "TF_VAR_ibmcloud_api_key" - val, present := os.LookupEnv(checkVariable) - require.True(t, present, checkVariable+" environment variable not set") - require.NotEqual(t, "", val, checkVariable+" environment variable is empty") - - logger.Log(t, "Tempdir: ", tempTerraformDir) - existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ - TerraformDir: tempTerraformDir, - Vars: map[string]interface{}{ - "prefix": prefix, - }, - // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. - // This is the same as setting the -upgrade=true flag with terraform. - Upgrade: true, - }) - - terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) - _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) - if existErr != nil { - // assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") - return "", nil, existErr - } - return prefix, existingTerraformOptions, nil -} - func TestMonolithExample(t *testing.T) { t.Parallel() - prefix, existingTerraformOptions, existErr := provisionPreReq(t, "mon-ocp") - - if existErr != nil { - assert.True(t, existErr == nil, "Init and Apply of temp existing resource failed") - } else { - options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ - Testing: t, - Prefix: prefix, - TarIncludePatterns: []string{ - "*.tf", - monolithExampleDir + "/*.tf", - fullyConfigurableTerraformDir + "/scripts/*.*", - "/scripts/*.*", - "kubeconfig/*.*", - "modules/kube-audit/*.*", - "modules/worker-pool/*.*", - "modules/kube-audit/kubeconfig/*.*", - "modules/kube-audit/scripts/*.*", - "modules/kube-audit/helm-charts/kube-audit/*.*", - "modules/kube-audit/helm-charts/kube-audit/templates/*.*", - "modules/monolith/*.tf", - }, - TemplateFolder: monolithExampleDir, - Tags: []string{"monolith-base-ocp-test"}, - DeleteWorkspaceOnFail: false, - WaitJobCompleteMinutes: 240, - IgnoreAdds: testhelper.Exemptions{ - List: []string{"module.monolith_add_ons.module.scc_wp.restapi_object.cspm"}, - }, - IgnoreUpdates: testhelper.Exemptions{ - List: []string{"module.ocp_base.ibm_container_addons.addons"}, - }, - }) - options.TerraformVars = []testschematic.TestSchematicTerraformVar{ - {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, - {Name: "prefix", Value: prefix, DataType: "string"}, - {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, - {Name: "kms_encryption_enabled_cluster", Value: true, DataType: "bool"}, - {Name: "existing_event_notifications_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "event_notifications_instance_crn"), DataType: "string"}, - } - - err := options.RunSchematicTest() - assert.Nil(t, err, "This should not have errored") + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Prefix: "mon-ocp", + TarIncludePatterns: []string{ + "*.tf", + monolithExampleDir + "/*.tf", + fullyConfigurableTerraformDir + "/scripts/*.*", + "/scripts/*.*", + "kubeconfig/*.*", + "modules/kube-audit/*.*", + "modules/worker-pool/*.*", + "modules/kube-audit/kubeconfig/*.*", + "modules/kube-audit/scripts/*.*", + "modules/kube-audit/helm-charts/kube-audit/*.*", + "modules/kube-audit/helm-charts/kube-audit/templates/*.*", + "modules/monolith/*.tf", + }, + TemplateFolder: monolithExampleDir, + Tags: []string{"monolith-base-ocp-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 240, + IgnoreAdds: testhelper.Exemptions{ + List: []string{"module.monolith_add_ons.module.scc_wp.restapi_object.cspm"}, + }, + IgnoreUpdates: testhelper.Exemptions{ + List: []string{"module.ocp_base.ibm_container_addons.addons"}, + }, + }) + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + {Name: "kms_encryption_enabled_cluster", Value: true, DataType: "bool"}, } - // Check if "DO_NOT_DESTROY_ON_FAILURE" is set - envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") - // Destroy the temporary existing resources if required - if t.Failed() && strings.ToLower(envVal) == "true" { - fmt.Println("Terratest failed. Debug the test and delete resources manually.") - } else { - logger.Log(t, "START: Destroy (prereq resources)") - terraform.Destroy(t, existingTerraformOptions) - terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) - logger.Log(t, "END: Destroy (prereq resources)") - } + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") } func TestAddonPermutations(t *testing.T) { From 2e1a549d81e217b01c142246f5cdbdfb3d474aea Mon Sep 17 00:00:00 2001 From: mukul-palit Date: Wed, 3 Dec 2025 12:14:28 +0530 Subject: [PATCH 4/4] remove existing resources --- tests/existing-resources-monolith/README.md | 1 - tests/existing-resources-monolith/main.tf | 24 -------------- tests/existing-resources-monolith/outputs.tf | 18 ----------- tests/existing-resources-monolith/provider.tf | 4 --- .../existing-resources-monolith/variables.tf | 32 ------------------- tests/existing-resources-monolith/version.tf | 9 ------ 6 files changed, 88 deletions(-) delete mode 100644 tests/existing-resources-monolith/README.md delete mode 100644 tests/existing-resources-monolith/main.tf delete mode 100644 tests/existing-resources-monolith/outputs.tf delete mode 100644 tests/existing-resources-monolith/provider.tf delete mode 100644 tests/existing-resources-monolith/variables.tf delete mode 100644 tests/existing-resources-monolith/version.tf diff --git a/tests/existing-resources-monolith/README.md b/tests/existing-resources-monolith/README.md deleted file mode 100644 index 705db15d6..000000000 --- a/tests/existing-resources-monolith/README.md +++ /dev/null @@ -1 +0,0 @@ -The terraform code in this directory is used by the existing resource test in tests/other_test.go diff --git a/tests/existing-resources-monolith/main.tf b/tests/existing-resources-monolith/main.tf deleted file mode 100644 index 3aa2b0abf..000000000 --- a/tests/existing-resources-monolith/main.tf +++ /dev/null @@ -1,24 +0,0 @@ -############################################################################# -# Provision Resource Group -############################################################################# -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.4.0" - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group -} - -############################################################################## -# Event Notification -############################################################################## - -module "event_notifications" { - source = "terraform-ibm-modules/event-notifications/ibm" - version = "2.7.0" - resource_group_id = module.resource_group.resource_group_id - name = "${var.prefix}-en" - tags = var.resource_tags - plan = "lite" - service_endpoints = "public-and-private" - region = var.region -} diff --git a/tests/existing-resources-monolith/outputs.tf b/tests/existing-resources-monolith/outputs.tf deleted file mode 100644 index 4deb3162c..000000000 --- a/tests/existing-resources-monolith/outputs.tf +++ /dev/null @@ -1,18 +0,0 @@ -######################################################################################################################## -# Outputs -######################################################################################################################## - -output "resource_group_id" { - description = "The id of the resource group where resources are created" - value = module.resource_group.resource_group_id -} - -output "resource_group_name" { - description = "The name of the resource group where resources are created" - value = module.resource_group.resource_group_name -} - -output "event_notifications_instance_crn" { - value = module.event_notifications.crn - description = "CRN of created event notification" -} diff --git a/tests/existing-resources-monolith/provider.tf b/tests/existing-resources-monolith/provider.tf deleted file mode 100644 index df45ef50b..000000000 --- a/tests/existing-resources-monolith/provider.tf +++ /dev/null @@ -1,4 +0,0 @@ -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} diff --git a/tests/existing-resources-monolith/variables.tf b/tests/existing-resources-monolith/variables.tf deleted file mode 100644 index 4b4575848..000000000 --- a/tests/existing-resources-monolith/variables.tf +++ /dev/null @@ -1,32 +0,0 @@ -############################################################################## -# Input variables -############################################################################## - -variable "ibmcloud_api_key" { - type = string - description = "The IBM Cloud API Key" - sensitive = true -} - -variable "region" { - type = string - description = "Region to provision all resources created by this example" - default = "us-south" -} - -variable "prefix" { - type = string - description = "Prefix to append to all resources created by this example" -} - -variable "resource_group" { - type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" - default = null -} - -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} diff --git a/tests/existing-resources-monolith/version.tf b/tests/existing-resources-monolith/version.tf deleted file mode 100644 index 97b20938f..000000000 --- a/tests/existing-resources-monolith/version.tf +++ /dev/null @@ -1,9 +0,0 @@ -terraform { - required_version = ">= 1.3.0" - required_providers { - ibm = { - source = "ibm-cloud/ibm" - version = ">= 1.64.1" - } - } -}