diff --git a/README.md b/README.md index 79755b83..f27504a0 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ By default, the module automatically downloads the required dependencies if they ## Overview * [terraform-ibm-base-ocp-vpc](#terraform-ibm-base-ocp-vpc) * [Submodules](./modules) + * [containerized_app_landing_zone](./modules/containerized_app_landing_zone) * [fscloud](./modules/fscloud) * [kube-audit](./modules/kube-audit) * [worker-pool](./modules/worker-pool) @@ -34,6 +35,7 @@ By default, the module automatically downloads the required dependencies if they *
* * + * * * * diff --git a/examples/containerized_app_landing_zone/README.md b/examples/containerized_app_landing_zone/README.md new file mode 100644 index 00000000..2d910b98 --- /dev/null +++ b/examples/containerized_app_landing_zone/README.md @@ -0,0 +1,10 @@ +# IBM Cloud OpenShift Landing Zone with Integrated Services 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. + +The following resources are provisioned by this example: +* A new resource group if an existing resource group is not passed. +* Monitoring agent. +* A Trusted Profile with Sender role to logs service. +* Logs agent. +* All the resources that are provisioned by calling the `containerized_app_landing_zone` module can be referred [here](../../modules/containerized_app_landing_zone/README.md). diff --git a/examples/containerized_app_landing_zone/main.tf b/examples/containerized_app_landing_zone/main.tf new file mode 100644 index 00000000..d020b2ad --- /dev/null +++ b/examples/containerized_app_landing_zone/main.tf @@ -0,0 +1,131 @@ +######################################################################################################################## +# 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 +} + +######################################################################################################################## +# OpenShift cluster integrated with other services +######################################################################################################################## + +module "openshift_landing_zone" { + source = "../../modules/containerized_app_landing_zone" + prefix = var.prefix + region = var.region + ibmcloud_api_key = var.ibmcloud_api_key + provider_visibility = var.provider_visibility + resource_group_id = module.resource_group.resource_group_id + kms_encryption_enabled_cluster = true + existing_kms_instance_crn = var.existing_kms_instance_crn + existing_cluster_kms_key_crn = var.existing_cluster_kms_key_crn + kms_endpoint_type = "private" + key_protect_allowed_network = "private-only" + kms_encryption_enabled_boot_volume = true + existing_boot_volume_kms_key_crn = var.existing_boot_volume_kms_key_crn + kms_plan = "tiered-pricing" + en_service_plan = "standard" + en_service_endpoints = "public-and-private" + existing_secrets_manager_crn = var.existing_secrets_manager_crn + secrets_manager_service_plan = "standard" + secrets_manager_endpoint_type = "private" + existing_event_notifications_instance_crn = var.existing_event_notifications_instance_crn + existing_cos_instance_crn = var.existing_cos_instance_crn + cos_instance_plan = "standard" + management_endpoint_type_for_buckets = "direct" + existing_cloud_monitoring_crn = var.existing_cloud_monitoring_crn + cloud_monitoring_plan = "graduated-tier" + existing_cloud_logs_crn = var.existing_cloud_logs_crn + scc_workload_protection_service_plan = "graduated-tier" + enable_vpc_flow_logs = true + app_config_plan = "enterprise" + app_config_service_endpoints = "public-and-private" +} + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.openshift_landing_zone.cluster_id + resource_group_id = module.resource_group.resource_group_id + config_dir = "${path.module}/../../kubeconfig" +} + +############################################################################## +# Monitoring Agents +############################################################################## + +module "monitoring_agent" { + source = "terraform-ibm-modules/monitoring-agent/ibm" + version = "1.19.0" + cluster_id = module.openshift_landing_zone.cluster_id + cluster_resource_group_id = module.resource_group.resource_group_id + is_vpc_cluster = true + access_key = module.openshift_landing_zone.cloud_monitoring_access_key + instance_region = var.region + metrics_filter = [{ exclude = "metricA.*" }, { include = "metricB.*" }] + container_filter = [{ type = "exclude", parameter = "kubernetes.namespace.name", name = "kube-system" }] + blacklisted_ports = [22, 2379, 3306] + agent_tags = { "environment" : "test", "custom" : "value" } + agent_mode = "troubleshooting" +} + +############################################################################## +# Logs Agent +############################################################################## + +locals { + logs_agent_namespace = "ibm-observe" + logs_agent_name = "logs-agent" +} + +module "trusted_profile" { + source = "terraform-ibm-modules/trusted-profile/ibm" + version = "3.2.0" + trusted_profile_name = "${var.prefix}-profile" + trusted_profile_description = "Logs agent Trusted Profile" + trusted_profile_policies = [{ + roles = ["Sender"] + unique_identifier = "logs-agent" + resources = [{ + service = "logs" + }] + }] + trusted_profile_links = [{ + cr_type = "ROKS_SA" + unique_identifier = "logs-agent-link" + links = [{ + crn = module.openshift_landing_zone.cluster_crn + namespace = local.logs_agent_namespace + name = local.logs_agent_name + }] + } + ] +} + +module "logs_agent" { + source = "terraform-ibm-modules/logs-agent/ibm" + version = "1.10.0" + cluster_id = module.openshift_landing_zone.cluster_id + cluster_resource_group_id = module.resource_group.resource_group_id + logs_agent_trusted_profile_id = module.trusted_profile.trusted_profile.id + logs_agent_namespace = local.logs_agent_namespace + logs_agent_name = local.logs_agent_name + cloud_logs_ingress_endpoint = module.openshift_landing_zone.cloud_logs_ingress_private_endpoint + cloud_logs_ingress_port = 3443 + logs_agent_additional_metadata = [{ + key = "cluster_id" + value = module.openshift_landing_zone.cluster_id + }] + logs_agent_resources = { + limits = { + cpu = "500m" + memory = "3Gi" + } + requests = { + cpu = "100m" + memory = "1Gi" + } + } + logs_agent_system_logs = ["/logs/*.log"] +} diff --git a/examples/containerized_app_landing_zone/outputs.tf b/examples/containerized_app_landing_zone/outputs.tf new file mode 100644 index 00000000..48c60d01 --- /dev/null +++ b/examples/containerized_app_landing_zone/outputs.tf @@ -0,0 +1,294 @@ +############################################################################## +# Cluster Outputs +############################################################################## + +output "cluster_name" { + value = module.openshift_landing_zone.cluster_name + description = "The name of the provisioned OpenShift cluster." +} + +output "cluster_id" { + value = module.openshift_landing_zone.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.openshift_landing_zone.cluster_crn +} + +output "workerpools" { + description = "A list of worker pools associated with the provisioned cluster" + value = module.openshift_landing_zone.workerpools +} + +output "ocp_version" { + description = "The version of OpenShift running on the provisioned cluster." + value = module.openshift_landing_zone.ocp_version +} + + +############################################################################## +# VPC +############################################################################## + +output "vpc_name" { + description = "Name of the VPC created." + value = module.openshift_landing_zone.vpc_name +} + +output "vpc_id" { + description = "ID of the VPC created." + value = module.openshift_landing_zone.vpc_id +} + +output "vpc_crn" { + description = "CRN of the VPC created." + value = module.openshift_landing_zone.vpc_crn +} + +############################################################################## +# Public Gateways +############################################################################## + +output "public_gateways" { + description = "Map of the public gateways by zone." + value = module.openshift_landing_zone.public_gateways +} + +############################################################################## +# VPC flow logs +############################################################################## + +output "vpc_flow_logs" { + description = "Details of the VPC flow logs collector." + value = module.openshift_landing_zone.vpc_flow_logs +} + +############################################################################## +# Network ACLs +############################################################################## + +output "network_acls" { + description = "List of shortnames and IDs of network ACLs." + value = module.openshift_landing_zone.network_acls +} + +############################################################################## +# Subnet Outputs +############################################################################## + +output "subnet_ids" { + description = "The IDs of the subnets." + value = module.openshift_landing_zone.subnet_ids +} + +output "private_path_subnet_id" { + description = "The IDs of the subnets." + value = length(module.openshift_landing_zone.subnet_ids) > 0 ? module.openshift_landing_zone.subnet_ids[0] : null +} + +output "subnet_detail_list" { + description = "A list of subnets containing names, CIDR blocks, and zones." + value = module.openshift_landing_zone.subnet_detail_list +} + +output "subnet_zone_list" { + description = "A list of subnet IDs and subnet zones." + value = module.openshift_landing_zone.subnet_zone_list +} + +output "subnet_detail_map" { + description = "A map of subnets containing IDs, CIDR blocks, and zones." + value = module.openshift_landing_zone.subnet_detail_map +} + +############################################################################## +# VPN Gateways Outputs +############################################################################## + +output "vpn_gateways_name" { + description = "List of names of VPN gateways." + value = module.openshift_landing_zone.vpn_gateways_name +} + +output "vpn_gateways_data" { + description = "Details of VPN gateways data." + value = module.openshift_landing_zone.vpn_gateways_data +} + +############################################################################## +# VPE Outputs +############################################################################## + +output "vpe_ips" { + description = "The reserved IPs for endpoint gateways." + value = module.openshift_landing_zone.vpe_ips +} + +output "vpe_crn" { + description = "The CRN of the endpoint gateway." + value = module.openshift_landing_zone.vpe_crn +} + +############################################################################## +# KMS Outputs +############################################################################## + +output "kms_guid" { + description = "KMS instance GUID" + value = module.openshift_landing_zone.kms_guid +} + +output "kms_account_id" { + description = "The account ID of the KMS instance." + value = module.openshift_landing_zone.kms_account_id +} + +output "kms_instance_crn" { + value = module.openshift_landing_zone.kms_instance_crn + description = "The CRN of the KMS instance" +} + +############################################################################## +# Events Notification Outputs +############################################################################## + +output "events_notification_crn" { + description = "Event Notification crn" + value = module.openshift_landing_zone.events_notification_crn +} + +output "events_notification_guid" { + description = "Event Notification guid" + value = module.openshift_landing_zone.events_notification_guid +} + +############################################################################## +# Secrets Manager Outputs +############################################################################## + +output "secrets_manager_guid" { + description = "GUID of Secrets Manager instance" + value = module.openshift_landing_zone.secrets_manager_guid +} + +output "secrets_manager_crn" { + value = module.openshift_landing_zone.secrets_manager_crn + description = "CRN of the Secrets Manager instance" +} + +output "secrets_manager_region" { + value = module.openshift_landing_zone.secrets_manager_region + description = "Region of the Secrets Manager instance" +} + +############################################################################## +# COS Outputs +############################################################################## + +output "cos_instance_crn" { + description = "COS instance crn" + value = module.openshift_landing_zone.cos_instance_crn +} + +output "cos_instance_guid" { + description = "COS instance guid" + value = module.openshift_landing_zone.cos_instance_guid +} + +############################################################################## +# Cloud Monitoring Outputs +############################################################################## + +output "cloud_monitoring_crn" { + value = module.openshift_landing_zone.cloud_monitoring_crn + description = "The id of the provisioned IBM Cloud Monitoring instance." +} +output "cloud_monitoring_name" { + value = module.openshift_landing_zone.cloud_monitoring_name + description = "The name of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_guid" { + value = module.openshift_landing_zone.cloud_monitoring_guid + description = "The guid of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_access_key_name" { + value = module.openshift_landing_zone.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.openshift_landing_zone.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.openshift_landing_zone.cloud_logs_crn + description = "The id of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_guid" { + value = module.openshift_landing_zone.cloud_logs_guid + description = "The guid of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_name" { + value = module.openshift_landing_zone.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.openshift_landing_zone.logs_bucket_crn +} + +output "metrics_bucket_crn" { + description = "Metrics Cloud Object Storage bucket CRN" + value = module.openshift_landing_zone.metrics_bucket_crn +} + +############################################################################## +# Activity Tracker Event Routing Outputs +############################################################################## + +output "activity_tracker_cos_target_bucket_name" { + value = module.openshift_landing_zone.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.openshift_landing_zone.activity_tracker_targets + description = "The map of created Activity Tracker Event Routing targets" +} + +output "activity_tracker_routes" { + value = module.openshift_landing_zone.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.openshift_landing_zone.scc_workload_protection_id +} + +output "scc_workload_protection_crn" { + description = "SCC Workload Protection instance CRN" + value = module.openshift_landing_zone.scc_workload_protection_crn +} + +output "scc_workload_protection_name" { + description = "SCC Workload Protection instance name" + value = module.openshift_landing_zone.scc_workload_protection_name +} diff --git a/examples/containerized_app_landing_zone/provider.tf b/examples/containerized_app_landing_zone/provider.tf new file mode 100644 index 00000000..af8cd0bf --- /dev/null +++ b/examples/containerized_app_landing_zone/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.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate +} diff --git a/examples/containerized_app_landing_zone/variables.tf b/examples/containerized_app_landing_zone/variables.tf new file mode 100644 index 00000000..1e948315 --- /dev/null +++ b/examples/containerized_app_landing_zone/variables.tf @@ -0,0 +1,119 @@ +######################################################################################################################## +# 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 = "ocp-lz" + 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 "existing_kms_instance_crn" { + type = string + default = null + description = "The CRN of an existing KMS instance." + + 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 "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 "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 "existing_cos_instance_crn" { + type = string + description = "The CRN of an existing Object Storage instance." + default = null +} + +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 "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." +} diff --git a/examples/containerized_app_landing_zone/version.tf b/examples/containerized_app_landing_zone/version.tf new file mode 100644 index 00000000..a1a72fb0 --- /dev/null +++ b/examples/containerized_app_landing_zone/version.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">=1.9.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.78.2, < 2.0.0" + } + restapi = { + source = "Mastercard/restapi" + version = ">= 2.0.1" + } + helm = { + source = "hashicorp/helm" + version = ">= 3.0.0, <4.0.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1" + } + } +} diff --git a/modules/containerized_app_landing_zone/README.md b/modules/containerized_app_landing_zone/README.md new file mode 100644 index 00000000..dd522ca7 --- /dev/null +++ b/modules/containerized_app_landing_zone/README.md @@ -0,0 +1,361 @@ +# Landing zone for containerized applications with OpenShift + +This module provides a **terraform implementation** of the secure landing zone architecture - a production-grade Red Hat OpenShift platform on IBM Cloud VPC by providing a fully integrated ecosystem. Rather than just provisioning compute resources, it orchestrates the critical **operational glue** required for enterprise workloads—automatically wiring together **Key Management**, **Secrets Manager**, **Cloud Logs**, **Cloud Monitoring**, **Cloud Object Storage** and **Events Notification**. This comprehensive approach reduces operational overhead and eliminates manual configuration errors, ensuring your environment is secure, observable, and ready. + +Secure, Compliant, and Scalable Designed to support a wide range of business needs, the architecture is secure by design and fully configurable. It incorporates robust compliance features, such as **SCC Workload Protection**, while allowing you to tailor specific integrations and worker pools to your requirements. This flexibility enables organizations to standardize on a single, reliable architectural pattern that streamlines security approvals and scales effortlessly with business demand. + +### Reference Architecture + + + +### 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. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/landing-zone-vpc/ibm/8.9.1) about the service module. +* `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. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/kms-all-inclusive/ibm/5.4.5) about the service module. +* `Secrets Management`: Optional provision and configuration of an IBM Secrets Manager instance to securely store service credentials and other secrets. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/secrets-manager/ibm/2.11.9) about the service module. +* `Cloud Object Storage (COS)`: Optional provision and configuration of COS instances and buckets for flow logs, activity tracker, and other data storage needs. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/cos/ibm/10.5.9) about the service module. +* `Monitoring & Logging`: Optional provision and configuration of IBM Cloud Monitoring and IBM Cloud Logs instances for centralized observability. Learn more about the [Cloud Monitoring](https://registry.terraform.io/modules/terraform-ibm-modules/cloud-monitoring/ibm/1.11.0) and [Cloud Logs](https://registry.terraform.io/modules/terraform-ibm-modules/cloud-logs/ibm/1.10.0) service module. +* `Activity Tracker and Event Routing`: Configure event routing for platform audit logs to a COS bucket or IBM Cloud Logs. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/activity-tracker/ibm/1.5.0) about the service module. +* `Security & Compliance`: Optional integration with IBM Cloud Security and Compliance Center (SCC) Workload Protection. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/scc-workload-protection/ibm/1.16.4) about the service module. +* `VPE Gateways`: Optional configuration of Virtual Private Endpoint (VPE) gateways for secure private connectivity to cloud services. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/vpe-gateway/ibm/4.6.6) about the service module. +* `Event Notifications`: Optional provision and configuration of IBM Cloud Event Notifications for centralized event routing and management, with support for KMS encryption and failed event collection in COS. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/event-notifications/ibm/2.7.0) about the service module. +* `App Configuration`: Optional provision and configuration of IBM Cloud App Configuration for centralized feature flag and property management, securely integrated with KMS and Event Notifications. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/app-configuration/ibm/1.14.2) about the service module. +* `Context-Based Restrictions (CBR)`: Optional support for defining and attaching network access rules (CBR zones and rules) to all supported services (KMS, COS, Secrets Manager) to enforce zero-trust networking. [Learn more](https://registry.terraform.io/modules/terraform-ibm-modules/cbr/ibm/1.34.0) about the service module. + +## Usage + +```hcl +module "openshift_landing_zone" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm//modules/containerized_app_landing_zone" + version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release + prefix = "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 `object({
master = optional(list(string), [])
registry = optional(list(string), [])
api = optional(list(string), [])
}) | `{}` | no |
+| [additional\_worker\_pools](#input\_additional\_worker\_pools) | List of additional worker pools. | 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))
})) | `[]` | no |
+| [addons](#input\_addons) | 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). | 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)
}))
}) | `{}` | 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 |
+| [allow\_default\_worker\_pool\_replacement](#input\_allow\_default\_worker\_pool\_replacement) | 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. | `bool` | `false` | no |
+| [allow\_outbound\_traffic](#input\_allow\_outbound\_traffic) | Set to true to allow public outbound access from the cluster workers. | `bool` | `true` | no |
+| [allow\_public\_access\_to\_cluster\_management](#input\_allow\_public\_access\_to\_cluster\_management) | Set to true to access the cluster through a public cloud service endpoint. | `bool` | `true` | 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 |
+| [attach\_ibm\_managed\_security\_group](#input\_attach\_ibm\_managed\_security\_group) | Specify whether to attach the IBM-defined default security group (whose name is kube-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\_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 `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 `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\_config\_endpoint\_type](#input\_cluster\_config\_endpoint\_type) | 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. | `string` | `"default"` | 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 `[| 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 `
"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 `
"all"
]
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 `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 `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\_autoscaling\_for\_default\_pool](#input\_enable\_autoscaling\_for\_default\_pool) | Set `true` to enable automatic scaling of worker based on workload demand. | `bool` | `false` | 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\_ocp\_console](#input\_enable\_ocp\_console) | 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. | `bool` | `null` | 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\_secrets\_manager\_integration](#input\_enable\_secrets\_manager\_integration) | Integrate with IBM Cloud Secrets Manager so you can centrally manage Ingress subdomain certificates and other secrets. | `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 `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. | `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 |
+| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud api token | `string` | n/a | yes |
+| [ignore\_worker\_pool\_size\_changes](#input\_ignore\_worker\_pool\_size\_changes) | Enable if using worker autoscaling. Stops Terraform managing worker count. | `bool` | `false` | 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\_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.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 |
+| [manage\_all\_addons](#input\_manage\_all\_addons) | 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. | `bool` | `false` | 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 `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)
})
)
})
)
})
)
[| no | +| [number\_of\_lbs](#input\_number\_of\_lbs) | 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. | `number` | `1` | no | +| [ocp\_cbr\_rules](#input\_ocp\_cbr\_rules) | The list of context-based restriction rules to create. |
{
"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-443-inbound-source",
"source": "0.0.0.0/0",
"tcp": {
"source_port_max": 443,
"source_port_min": 443
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-443-inbound-dest",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 443,
"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": {
"source_port_max": 80,
"source_port_min": 80
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-ingress-inbound",
"source": "0.0.0.0/0",
"tcp": {
"source_port_max": 32767,
"source_port_min": 30000
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-443-outbound-source",
"source": "0.0.0.0/0",
"tcp": {
"source_port_max": 443,
"source_port_min": 443
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-443-outbound-dest",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 443,
"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
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-ingress-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 32767,
"port_min": 30000
}
}
]
}
]
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 |
+| [ocp\_entitlement](#input\_ocp\_entitlement) | Value that is applied to the entitlements for OCP cluster provisioning. | `string` | `null` | no |
+| [openshift\_version](#input\_openshift\_version) | Version of the OpenShift cluster to provision. | `string` | `"4.19"` | no |
+| [pod\_subnet\_cidr](#input\_pod\_subnet\_cidr) | 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`. | `string` | `null` | 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 |
+| [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. | `string` | `"private"` | no |
+| [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(| `[]` | 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 `
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
})
))
})
)
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 `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))
})) | [| 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. |
{
"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"
}
]
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 `list(| `[]` | no | +| [service\_cred](#input\_service\_cred) | Service configuration for COS. |
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)
})
)
})
)
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 |
+| [service\_subnet\_cidr](#input\_service\_subnet\_cidr) | 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`. | `string` | `null` | 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\_ocp\_secrets\_manager\_iam\_auth\_policy](#input\_skip\_ocp\_secrets\_manager\_iam\_auth\_policy) | To skip creating auth policy that allows OCP cluster 'Manager' role access in the existing Secrets Manager instance for managing ingress certificates. | `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 |
+| [verify\_worker\_network\_readiness](#input\_verify\_worker\_network\_readiness) | 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. | `bool` | `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 `set(| `[]` | 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 `
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)
})
)
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(| `[]` | no | +| [worker\_pools\_taints](#input\_worker\_pools\_taints) | Optional, Map of lists containing node taints by node-pool name. | `map(list(object({ key = string, value = string, effect = string })))` | `null` | 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 | +| [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. | +| [cluster\_crn](#output\_cluster\_crn) | The Cloud Resource Name (CRN) of the provisioned OpenShift cluster. | +| [cluster\_id](#output\_cluster\_id) | The unique identifier assigned to the provisioned OpenShift cluster. | +| [cluster\_name](#output\_cluster\_name) | The name of the provisioned OpenShift cluster. | +| [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 | +| [events\_notification\_crn](#output\_events\_notification\_crn) | Event Notification crn | +| [events\_notification\_guid](#output\_events\_notification\_guid) | Event Notification guid | +| [kms\_account\_id](#output\_kms\_account\_id) | The account ID of the KMS instance. | +| [kms\_guid](#output\_kms\_guid) | KMS instance GUID | +| [kms\_instance\_crn](#output\_kms\_instance\_crn) | The CRN of the KMS 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. | +| [ocp\_version](#output\_ocp\_version) | The version of OpenShift running on the provisioned cluster. | +| [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. | +| [workerpools](#output\_workerpools) | A list of worker pools associated with the provisioned cluster | + diff --git a/modules/containerized_app_landing_zone/main.tf b/modules/containerized_app_landing_zone/main.tf new file mode 100644 index 00000000..fc2dc5c0 --- /dev/null +++ b/modules/containerized_app_landing_zone/main.tf @@ -0,0 +1,1072 @@ +################################################################################# +# 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.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.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.3.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}" + cluster_name = "${local.prefix}${var.cluster_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 +} + +################################################################################# +# 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 +################################################################################# + +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 + 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 = 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 + allowed_network = var.secrets_manager_allowed_network + secrets = local.secret_groups_with_prefix +} + +################################################################################# +# Secrets Manager Event Notifications Configuration +################################################################################# + +locals { + 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_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_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_secrets_manager_cluster ? 1 : 0 + depends_on = [module.secrets_manager] + + create_duration = "30s" +} + +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_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" "en_email_subscription" { + # if existing SM instance CRN is passed (!= null), then never create EN email subscription + 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_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 + 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 : "" + + 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 + 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" "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 + 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.cos_service_credential_secrets) > 0 ? 1 : 0 + depends_on = [ibm_iam_authorization_policy.cos_secrets_manager_key_manager] + create_duration = "30s" +} + +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.cos_service_credential_secrets +} + +################################################################################# +# 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.8" + 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.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.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 + } + } + ] +} + +######################################################################################################################## +# 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 +################################################################################# + +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 = 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 +############################################################################# + + +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.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 +} + +######################################################################################################################## +# 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.vpc.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 = var.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 = local.boot_volume_kms_key_id + kms_instance_id = local.boot_volume_existing_kms_guid + kms_account_id = local.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 = var.resource_group_id + boot_volume_encryption_kms_config = { + crk = local.boot_volume_kms_key_id + kms_instance_id = local.boot_volume_existing_kms_guid + kms_account_id = local.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 = var.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 = local.boot_volume_kms_key_id + kms_instance_id = local.boot_volume_existing_kms_guid + kms_account_id = local.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" { + source = "../.." + resource_group_id = var.resource_group_id + region = var.region + tags = var.cluster_resource_tags + cluster_name = local.cluster_name + force_delete_storage = true + use_existing_cos = true + existing_cos_id = var.existing_cos_instance_crn != null ? module.existing_cos_instance_crn_parser[0].resource : module.cos[0].cos_instance_crn + vpc_id = module.vpc.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 = local.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 = local.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" { + 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 = local.secrets_manager_guid + secrets_manager_region = local.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 = local.secrets_manager_region + secrets_manager_guid = local.secrets_manager_guid + secret_group_name = module.ocp_base.cluster_id + secret_group_description = "Secret group for storing ingress certificates for cluster ${local.cluster_name} with id: ${module.ocp_base.cluster_id}" + endpoint_type = var.secrets_manager_endpoint_type +} diff --git a/modules/containerized_app_landing_zone/outputs.tf b/modules/containerized_app_landing_zone/outputs.tf new file mode 100644 index 00000000..a2009339 --- /dev/null +++ b/modules/containerized_app_landing_zone/outputs.tf @@ -0,0 +1,326 @@ +############################################################################## +# 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 +} + +############################################################################## +# 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 = "KMS instance GUID" + 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 "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 KMS instance" +} + +############################################################################## +# Events Notification Outputs +############################################################################## + +output "events_notification_crn" { + description = "Event Notification crn" + value = local.eventnotification_crn +} + +output "events_notification_guid" { + description = "Event Notification guid" + value = local.eventnotification_guid +} + + +############################################################################## +# Secrets Manager 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/containerized_app_landing_zone/variables.tf b/modules/containerized_app_landing_zone/variables.tf new file mode 100644 index 00000000..3d3008d7 --- /dev/null +++ b/modules/containerized_app_landing_zone/variables.tf @@ -0,0 +1,2352 @@ +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud api token" + sensitive = true +} + +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 "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." + + 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 `
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), [])
})
)