diff --git a/README.md b/README.md index af23f2ba0..bdedcce4a 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,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 000000000..bd1759ca5 --- /dev/null +++ b/examples/containerized_app_landing_zone/README.md @@ -0,0 +1,145 @@ +# Landing zone for containerized applications with OpenShift example + +This example 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 example 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. + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >=1.9.0 | +| [helm](#requirement\_helm) | >= 3.0.0, <4.0.0 | +| [ibm](#requirement\_ibm) | >= 1.78.2, < 2.0.0 | +| [kubernetes](#requirement\_kubernetes) | >= 2.16.1 | +| [restapi](#requirement\_restapi) | >= 2.0.1 | +| [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [activity\_tracker](#module\_activity\_tracker) | terraform-ibm-modules/activity-tracker/ibm | 1.5.0 | +| [app\_config](#module\_app\_config) | terraform-ibm-modules/app-configuration/ibm | 1.14.2 | +| [at\_cos\_bucket](#module\_at\_cos\_bucket) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [cloud\_logs](#module\_cloud\_logs) | terraform-ibm-modules/cloud-logs/ibm | 1.10.0 | +| [cloud\_logs\_buckets](#module\_cloud\_logs\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [cloud\_monitoring](#module\_cloud\_monitoring) | terraform-ibm-modules/cloud-monitoring/ibm | 1.11.0 | +| [cos](#module\_cos) | terraform-ibm-modules/cos/ibm//modules/fscloud | 10.5.9 | +| [en\_cos\_buckets](#module\_en\_cos\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [event\_notifications](#module\_event\_notifications) | terraform-ibm-modules/event-notifications/ibm | 2.7.0 | +| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 5.4.5 | +| [logs\_agent](#module\_logs\_agent) | terraform-ibm-modules/logs-agent/ibm | 1.10.0 | +| [metrics\_routing](#module\_metrics\_routing) | terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing | 1.11.0 | +| [monitoring\_agent](#module\_monitoring\_agent) | terraform-ibm-modules/monitoring-agent/ibm | 1.19.0 | +| [ocp\_base](#module\_ocp\_base) | ../.. | n/a | +| [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.4.0 | +| [scc\_wp](#module\_scc\_wp) | terraform-ibm-modules/scc-workload-protection/ibm | 1.16.4 | +| [secret\_group](#module\_secret\_group) | terraform-ibm-modules/secrets-manager-secret-group/ibm | 1.3.15 | +| [secrets\_manager](#module\_secrets\_manager) | terraform-ibm-modules/secrets-manager/ibm | 2.11.9 | +| [trusted\_profile](#module\_trusted\_profile) | terraform-ibm-modules/trusted-profile/ibm | 3.2.0 | +| [vpc](#module\_vpc) | terraform-ibm-modules/landing-zone-vpc/ibm | 8.9.1 | +| [vpc\_cos\_buckets](#module\_vpc\_cos\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 10.5.8 | +| [vpe\_gateway](#module\_vpe\_gateway) | terraform-ibm-modules/vpe-gateway/ibm | 4.6.6 | + +### Resources + +| Name | Type | +|------|------| +| [ibm_en_subscription_email.apprapp_email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_subscription_email) | resource | +| [ibm_en_subscription_email.en_email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_subscription_email) | resource | +| [ibm_en_topic.en_apprapp_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_topic) | resource | +| [ibm_en_topic.en_sm_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/en_topic) | resource | +| [ibm_iam_authorization_policy.cos_secrets_manager_key_manager](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_iam_authorization_policy.en_secrets_manager_key_manager](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [terraform_data.delete_secrets](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource | +| [time_sleep.wait_for_cos_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_en_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_secrets_manager](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [ibm_container_cluster_config.cluster_config](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/container_cluster_config) | data source | +| [ibm_en_destinations.en_apprapp_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/en_destinations) | data source | +| [ibm_en_destinations.en_sm_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/en_destinations) | data source | +| [ibm_iam_auth_token.auth_token](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/iam_auth_token) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [event\_notifications\_email\_list](#input\_event\_notifications\_email\_list) | The list of email address to target out when an event is triggered | `list(string)` | `[]` | no | +| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision the resources. | `string` | `"Default"` | no | +| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud api token | `string` | n/a | yes | +| [prefix](#input\_prefix) | Prefix for name of all resource created by this example | `string` | `"ocp-lz"` | no | +| [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) | Region where resources are created | `string` | `"us-south"` | 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\_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 | +| [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\_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\_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/examples/containerized_app_landing_zone/kubeconfig/.gitignore b/examples/containerized_app_landing_zone/kubeconfig/.gitignore new file mode 100644 index 000000000..632a28fbd --- /dev/null +++ b/examples/containerized_app_landing_zone/kubeconfig/.gitignore @@ -0,0 +1,6 @@ +# Ignore everything +* + +# But not these files... +!.gitignore +!README.md diff --git a/examples/containerized_app_landing_zone/kubeconfig/README.md b/examples/containerized_app_landing_zone/kubeconfig/README.md new file mode 100644 index 000000000..e85afee8d --- /dev/null +++ b/examples/containerized_app_landing_zone/kubeconfig/README.md @@ -0,0 +1,2 @@ +This directory must exist in source control so the `ibm_container_cluster_config` data lookup can use it to place the +config.yml used to connect to a kubernetes cluster. diff --git a/examples/containerized_app_landing_zone/main.tf b/examples/containerized_app_landing_zone/main.tf new file mode 100644 index 000000000..acfb444a3 --- /dev/null +++ b/examples/containerized_app_landing_zone/main.tf @@ -0,0 +1,982 @@ +######################################################################################################### +# 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 +} + +######################################################################################################### +# KMS +######################################################################################################### + +locals { + cluster_key_ring_name = "${var.prefix}-cluster-key-ring" + cluster_key_name = "${var.prefix}-cluster-key" + boot_volume_key_ring_name = "${var.prefix}-boot-volume-key-ring" + boot_volume_key_name = "${var.prefix}-boot-volume-key" + keys = [{ + 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 + } + ] + }, + { + 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 + } + ] + } + ] +} + + +module "kms" { + source = "terraform-ibm-modules/kms-all-inclusive/ibm" + version = "5.4.5" + resource_group_id = module.resource_group.resource_group_id + region = var.region + create_key_protect_instance = true + key_protect_instance_name = "${var.prefix}-key-protect" + key_protect_plan = "tiered-pricing" + enable_metrics = true + key_protect_allowed_network = "private-only" # Possible values are 'private-only', or 'public-and-private'. + key_ring_endpoint_type = "private" # Possible values are `public` or `private`. + key_endpoint_type = "private" # Possible values are `public` or `private`. + keys = [for key in local.keys : key if key != null] +} + +######################################################################################################### +# Cloud Monitoring +######################################################################################################### + +locals { + default_metrics_router_route = [{ + name = "${var.prefix}-metrics-routing-route" + rules = [{ + action = "send" + targets = [{ + id = module.metrics_routing.metrics_router_targets["${var.prefix}-cloud-monitoring-target"].id + }] + inclusion_filters = [] + }] + }] +} + +module "cloud_monitoring" { + source = "terraform-ibm-modules/cloud-monitoring/ibm" + version = "1.11.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + instance_name = "${var.prefix}-cloud-monitoring" + plan = "graduated-tier" # Possible values are `lite` and `graduated-tier` and graduated-tier-sysdig-secure-plus-monitor (available in region eu-fr2 only). + service_endpoints = "public-and-private" + disable_access_key_creation = false + enable_platform_metrics = false +} + +module "metrics_routing" { + source = "terraform-ibm-modules/cloud-monitoring/ibm//modules/metrics_routing" + version = "1.11.0" + metrics_router_targets = [ + { + destination_crn = module.cloud_monitoring.crn + target_name = "${var.prefix}-cloud-monitoring-target" + target_region = var.region + skip_metrics_router_auth_policy = false + } + ] + + metrics_router_routes = local.default_metrics_router_route + metrics_router_settings = { primary_metadata_region = var.region } +} + +######################################################################################################### +# Event Notifications +######################################################################################################### + +locals { + en_cos_bucket_name = "${var.prefix}-base-event-notifications-bucket" +} + +module "event_notifications" { + source = "terraform-ibm-modules/event-notifications/ibm" + version = "2.7.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + name = "${var.prefix}-event-notifications" + plan = "standard" # Possible values are `lite`, `standard`. + service_endpoints = "public-and-private" # Possible values are `public`, `private`, `public-and-private`. + # KMS Related + kms_encryption_enabled = true + kms_endpoint_url = module.kms.kms_private_endpoint + existing_kms_instance_crn = module.kms.key_protect_crn + root_key_id = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].key_id + skip_en_kms_auth_policy = false + # COS Related + cos_integration_enabled = true + cos_bucket_name = module.en_cos_buckets.buckets[local.en_cos_bucket_name].bucket_name + cos_instance_id = module.cos.cos_instance_id + skip_en_cos_auth_policy = false + cos_endpoint = "https://${module.en_cos_buckets.buckets[local.en_cos_bucket_name].s3_endpoint_direct}" +} + +locals { + en_cos_bucket_config = [{ + bucket_name = local.en_cos_bucket_name + add_bucket_name_suffix = true + kms_encryption_enabled = true + kms_guid = module.kms.kms_guid + kms_key_crn = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn + skip_iam_authorization_policy = false + management_endpoint_type = "direct" # Possible values are `public`, `private` or `direct`. + storage_class = "smart" # Possible values are `standard` or `smart`. + resource_instance_id = module.cos.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 = module.cloud_monitoring.crn + } + force_delete = true + }] +} + +module "en_cos_buckets" { + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.8" + bucket_configs = local.en_cos_bucket_config +} + +######################################################################################################### +# Service Credentials +######################################################################################################### + +# create a service authorization between Secrets Manager and the target service (Event Notification) +resource "ibm_iam_authorization_policy" "en_secrets_manager_key_manager" { + source_service_name = "secrets-manager" + source_resource_instance_id = module.secrets_manager.secrets_manager_guid + target_service_name = "event-notifications" + target_resource_instance_id = module.event_notifications.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" +} + +######################################################################################################### +# Secrets Manager +######################################################################################################### + +locals { + secret_groups = [ + { + secret_group_name = "General" + secret_group_description = "A general purpose secrets group with an associated access group which has a secrets reader role" + create_access_group = true + access_group_name = "general-secrets-group-access-group" + access_group_roles = ["SecretsReader"] + } + ] + secret_groups_with_prefix = [ + for group in local.secret_groups : merge(group, { + access_group_name = group.access_group_name != null ? "${var.prefix}-${group.access_group_name}" : null + }) + ] + # parsed_existing_en_instance_crn = split(":", module.event_notifications.crn) + # existing_en_guid = length(local.parsed_existing_en_instance_crn) > 0 ? local.parsed_existing_en_instance_crn[7] : null +} + +module "secrets_manager" { + source = "terraform-ibm-modules/secrets-manager/ibm" + version = "2.11.9" + resource_group_id = module.resource_group.resource_group_id + region = var.region + secrets_manager_name = "${var.prefix}-secrets-manager" + sm_service_plan = "standard" # Possible values are `standard` or `trial`. + skip_iam_authorization_policy = false + # kms dependency + is_hpcs_key = false + kms_encryption_enabled = true + kms_key_crn = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn + skip_kms_iam_authorization_policy = false + # event notifications dependency + enable_event_notification = true + existing_en_instance_crn = module.event_notifications.crn + skip_en_iam_authorization_policy = false + endpoint_type = "private" # Possible values are `public` or `private`. + allowed_network = "private-only" # Possible values are 'private-only', or 'public-and-private'. + secrets = local.secret_groups_with_prefix +} + +######################################################################################################### +# Secrets Manager Event Notifications Configuration +######################################################################################################### + +data "ibm_en_destinations" "en_sm_destinations" { + instance_guid = module.event_notifications.guid +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5533 +resource "time_sleep" "wait_for_secrets_manager" { + depends_on = [module.secrets_manager] + create_duration = "30s" +} + +resource "ibm_en_topic" "en_sm_topic" { + depends_on = [time_sleep.wait_for_secrets_manager] + instance_guid = module.event_notifications.guid + name = "Topic for Secrets Manager instance ${module.secrets_manager.secrets_manager_guid}" + description = "Topic for Secrets Manager events routing" + sources { + id = module.secrets_manager.secrets_manager_crn + rules { + enabled = true + event_type_filter = "$.*" + } + } +} + +resource "ibm_en_subscription_email" "en_email_subscription" { + count = length(var.event_notifications_email_list) > 0 ? 1 : 0 + instance_guid = module.event_notifications.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.destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_sm_topic.topic_id + attributes { + add_notification_payload = true + reply_to_mail = "no-reply@ibm.com" + reply_to_name = "Secret Manager Event Notifications Bot" + from_name = "compliancealert@ibm.com" + invited = var.event_notifications_email_list + } +} + +######################################################################################################### +# COS +######################################################################################################### + +module "cos" { + source = "terraform-ibm-modules/cos/ibm//modules/fscloud" + version = "10.5.9" + resource_group_id = module.resource_group.resource_group_id + create_cos_instance = true + cos_instance_name = "${var.prefix}-cos-instance" + cos_plan = "standard" # Possible values are `standard` or `cos-one-rate-plan`. +} + +######################################################################################################### +# Secrets Manager service credentials for COS +######################################################################################################### + +# create s2s auth policy with Secrets Manager +resource "ibm_iam_authorization_policy" "cos_secrets_manager_key_manager" { + source_service_name = "secrets-manager" + source_resource_instance_id = module.secrets_manager.secrets_manager_guid + target_service_name = "cloud-object-storage" + target_resource_instance_id = module.cos.cos_instance_guid + roles = ["Key Manager"] + description = "Allow Secrets Manager with instance id ${module.secrets_manager.secrets_manager_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" { + depends_on = [ibm_iam_authorization_policy.cos_secrets_manager_key_manager] + create_duration = "30s" +} + +######################################################################################################### +# Cloud Logs +######################################################################################################### + +locals { + data_bucket_name = "${var.prefix}-cloud-logs-logs-bucket" + metrics_bucket_name = "${var.prefix}-cloud-logs-metrics-bucket" +} + +module "cloud_logs" { + depends_on = [time_sleep.wait_for_cos_authorization_policy] + source = "terraform-ibm-modules/cloud-logs/ibm" + version = "1.10.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + instance_name = "${var.prefix}-cloud-logs" + plan = "standard" # not a variable because there is only one option + service_endpoints = "public-and-private" # not a variable because there is only one option + 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 = false + }, + 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 = false + } + } + skip_logs_routing_auth_policy = false +} + +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 = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn + kms_guid = module.kms.kms_guid + kms_encryption_enabled = false + region_location = var.region + resource_instance_id = module.cos.cos_instance_id + add_bucket_name_suffix = true + management_endpoint_type = "direct" + storage_class = "smart" + 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 = module.cloud_monitoring.crn + } + }, + { + bucket_name = local.metrics_bucket_name + kms_key_crn = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn + kms_guid = module.kms.kms_guid + kms_encryption_enabled = false + region_location = var.region + resource_instance_id = module.cos.cos_instance_id + add_bucket_name_suffix = true + management_endpoint_type = "direct" + storage_class = "smart" + 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 = module.cloud_monitoring.crn + } + } + ] +} + +######################################################################################################### +# Activity Tracker +######################################################################################################### + +locals { + activity_tracker_bucket_config = { + class = "smart" + name = local.activity_tracker_cos_target_bucket_name + } + + 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_target_bucket_name = "${var.prefix}-at-events-cos-bucket" + activity_tracker_cos_route = [{ + route_name = "${var.prefix}-at-cos-route" + locations = ["*"] + target_ids = [module.activity_tracker.activity_tracker_targets[module.cos.cos_instance_name].id] + }] + activity_tracker_cloud_logs_route = [{ + route_name = "${var.prefix}-at-cloud-logs-route" + locations = ["*"] + target_ids = [module.activity_tracker.activity_tracker_targets[module.cos.cos_instance_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 = [ + { + bucket_name = module.at_cos_bucket.buckets[local.activity_tracker_cos_target_bucket_name].bucket_name + endpoint = module.at_cos_bucket.buckets[local.activity_tracker_cos_target_bucket_name].s3_endpoint_private + instance_id = module.cos.cos_instance_crn + target_region = var.region + target_name = module.cos.cos_instance_name + skip_atracker_cos_iam_auth_policy = false + service_to_service_enabled = true + } + ] + + cloud_logs_targets = [ + { + instance_id = module.cloud_logs.crn + target_region = var.region + target_name = module.cos.cos_instance_name + } + ] + + # Routes + activity_tracker_routes = local.activity_tracker_routes +} + +module "at_cos_bucket" { + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.8" + bucket_configs = [ + for value in local.at_buckets_config : + { + bucket_name = value.name + add_bucket_name_suffix = true + kms_guid = module.kms.kms_guid + kms_encryption_enabled = false + kms_key_crn = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn + skip_iam_authorization_policy = false + management_endpoint_type = "direct" + storage_class = "smart" + resource_instance_id = module.cos.cos_instance_id + region_location = var.region + force_delete = true + archive_rule = local.archive_rule + expire_rule = local.expire_rule + 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 = module.cloud_monitoring.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 = module.resource_group.resource_group_id + region = var.region + app_config_name = "${var.prefix}-app-config" + app_config_plan = "enterprise" + app_config_service_endpoints = "public-and-private" # Possible values are `public` or `public-and-private`. + enable_config_aggregator = true + config_aggregator_trusted_profile_name = "${var.prefix}-config-aggregator-trusted-profile" + config_aggregator_resource_collection_regions = ["all"] + config_aggregator_enterprise_trusted_profile_name = "${var.prefix}-config-aggregator-enterprise-trusted-profile" + config_aggregator_enterprise_trusted_profile_template_name = "${var.prefix}-config-aggregator-trusted-profile-template" + config_aggregator_enterprise_account_group_ids_to_assign = ["all"] + kms_encryption_enabled = true + skip_app_config_kms_auth_policy = false + existing_kms_instance_crn = module.kms.key_protect_crn + kms_endpoint_url = module.kms.kms_private_endpoint + root_key_id = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].key_id + enable_event_notifications = true + skip_app_config_event_notifications_auth_policy = false + existing_event_notifications_instance_crn = module.event_notifications.crn + event_notifications_endpoint_url = module.event_notifications.event_notifications_private_endpoint + app_config_event_notifications_source_name = "${var.prefix}-app-config-en" + event_notifications_integration_description = "The App Configuration integration to send notifications of events to users from the Event Notifications instance GUID ${module.event_notifications.guid}" +} + +######################################################################################################### +# App Configuration Event Notifications Configuration +######################################################################################################### + +data "ibm_en_destinations" "en_apprapp_destinations" { + instance_guid = module.event_notifications.guid +} + +resource "ibm_en_topic" "en_apprapp_topic" { + depends_on = [module.app_config] + instance_guid = module.event_notifications.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 = module.event_notifications.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.destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_apprapp_topic.topic_id + attributes { + add_notification_payload = true + reply_to_mail = "no-reply@ibm.com" + reply_to_name = "App Configuration Event Notifications Bot" + from_name = "compliancealert@ibm.com" + invited = var.event_notifications_email_list + } +} + +######################################################################################################### +# SCC Workload Protection +######################################################################################################### + +module "scc_wp" { + source = "terraform-ibm-modules/scc-workload-protection/ibm" + version = "1.16.4" + name = "${var.prefix}-scc-workload-protection" + region = var.region + resource_group_id = module.resource_group.resource_group_id + resource_key_name = "${var.prefix}-scc-workload-protection-key" + cloud_monitoring_instance_crn = module.cloud_monitoring.crn + scc_wp_service_plan = "graduated-tier" # Possible values are `free-trial` or `graduated-tier`. + app_config_crn = module.app_config.app_config_crn + scc_workload_protection_trusted_profile_name = "${var.prefix}-workload-protection-trusted-profile" + cspm_enabled = true +} + +######################################################################################################### +# COS Bucket for VPC flow logs +######################################################################################################### + + +locals { + vpc_flow_logs_bucket_name = "${var.prefix}-flow-logs-bucket" + # configuration for the flow logs bucket + flow_logs_bucket_config = [{ + bucket_name = local.vpc_flow_logs_bucket_name + add_bucket_name_suffix = true + kms_encryption_enabled = false + kms_guid = module.kms.kms_guid + kms_key_crn = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].crn + skip_iam_authorization_policy = true + management_endpoint_type = "direct" + storage_class = "smart" + resource_instance_id = module.cos.cos_instance_id + region_location = var.region + force_delete = true + archive_rule = { + enable = true + days = 90 + type = "Glacier" # Possible values are `Glacier` or `Accelerated`. + } + expire_rule = { + enable = true + days = 366 + } + object_versioning_enabled = false + }] +} + +# Create COS bucket using the defined bucket configuration +module "vpc_cos_buckets" { + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "10.5.8" + bucket_configs = local.flow_logs_bucket_config +} + +######################################################################################################### +# VPC +######################################################################################################### + +locals { + subnets = { + zone-1 = [ + { + name = "subnet-a" + cidr = "10.10.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ], + zone-2 = [ + { + name = "subnet-b" + cidr = "10.20.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ], + zone-3 = [ + { + name = "subnet-c" + cidr = "10.30.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ] + } + + network_acls = [ + { + name = "vpc-acl" + add_ibm_cloud_internal_rules = true + add_vpc_connectivity_rules = true + prepend_ibm_rules = true + rules = [ + { + name = "allow-443-inbound-source" + action = "allow" + direction = "inbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-443-inbound-dest" + action = "allow" + direction = "inbound" + tcp = { + port_max = 443 + port_min = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-80-inbound" + action = "allow" + direction = "inbound" + tcp = { + source_port_min = 80 + source_port_max = 80 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-ingress-inbound" + action = "allow" + direction = "inbound" + tcp = { + source_port_min = 30000 + source_port_max = 32767 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-443-outbound-source" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-443-outbound-dest" + action = "allow" + direction = "outbound" + tcp = { + port_min = 443 + port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-80-outbound" + action = "allow" + direction = "outbound" + tcp = { + port_min = 80 + port_max = 80 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-ingress-outbound" + action = "allow" + direction = "outbound" + tcp = { + port_min = 30000 + port_max = 32767 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + } + ] + } + ] + # create 'use_public_gateways' object + public_gateway_object = { + for key, value in local.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 = module.resource_group.resource_group_id + region = var.region + create_vpc = true + name = "vpc" + prefix = var.prefix + subnets = local.subnets + network_acls = local.network_acls + clean_default_sg_acl = true + use_public_gateways = local.public_gateway_object + address_prefixes = { + zone-1 = null + zone-2 = null + zone-3 = null + } + enable_vpc_flow_logs = true + create_authorization_policy_vpc_to_cos = true + existing_cos_instance_guid = module.cos.cos_instance_guid + existing_storage_bucket_name = module.vpc_cos_buckets.buckets[local.vpc_flow_logs_bucket_name].bucket_name +} + +######################################################################################################### +# VPE Gateway +######################################################################################################### + +module "vpe_gateway" { + source = "terraform-ibm-modules/vpe-gateway/ibm" + version = "4.6.6" + resource_group_id = module.resource_group.resource_group_id + region = var.region + prefix = var.prefix + vpc_name = module.vpc.vpc_name + vpc_id = module.vpc.vpc_id + subnet_zone_list = module.vpc.subnet_zone_list + service_endpoints = "private" # Possible values are `private` or `public`. +} + +######################################################################################################### +# 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 = [ + { + subnet_prefix = "default" + pool_name = "default" + machine_type = "bx2.4x16" + workers_per_zone = 1 + resource_group_id = module.resource_group.resource_group_id + operating_system = "RHCOS" + minSize = 1 + maxSize = 3 + enableAutoscaling = false + boot_volume_encryption_kms_config = { + crk = module.kms.keys[format("%s.%s", local.boot_volume_key_ring_name, local.boot_volume_key_name)].key_id + kms_instance_id = module.kms.kms_guid + kms_account_id = module.kms.kms_account_id + } + additional_security_group_ids = [] + } + ] + cluster_name = "${var.prefix}-openshift" + kms_config = { + crk_id = module.kms.keys[format("%s.%s", local.cluster_key_ring_name, local.cluster_key_name)].key_id + instance_id = module.kms.kms_guid + private_endpoint = true + account_id = module.kms.kms_account_id + } +} + +module "ocp_base" { + source = "../.." + resource_group_id = module.resource_group.resource_group_id + region = var.region + cluster_name = local.cluster_name + force_delete_storage = true + use_existing_cos = true + existing_cos_id = module.cos.cos_instance_crn + vpc_id = module.vpc.vpc_id + vpc_subnets = local.vpc_subnets + ocp_version = "4.19" + worker_pools = local.worker_pools + kms_config = local.kms_config + existing_secrets_manager_instance_crn = module.secrets_manager.secrets_manager_crn + secrets_manager_secret_group_id = module.secret_group.secret_group_id +} + +resource "terraform_data" "delete_secrets" { + input = { + secret_id = module.secret_group.secret_group_id + provider_visibility = var.provider_visibility + secrets_manager_instance_id = module.secrets_manager.secrets_manager_guid + secrets_manager_region = module.secrets_manager.secrets_manager_region + secrets_manager_endpoint = "private" + } + # 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" { + source = "terraform-ibm-modules/secrets-manager-secret-group/ibm" + version = "1.3.15" + region = module.secrets_manager.secrets_manager_region + secrets_manager_guid = module.secrets_manager.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 = "private" +} + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.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.ocp_base.cluster_id + cluster_resource_group_id = module.resource_group.resource_group_id + is_vpc_cluster = true + access_key = module.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.ocp_base.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.ocp_base.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.cloud_logs.ingress_private_endpoint + cloud_logs_ingress_port = 3443 + logs_agent_additional_metadata = [{ + key = "cluster_id" + value = module.ocp_base.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 000000000..04820d97d --- /dev/null +++ b/examples/containerized_app_landing_zone/outputs.tf @@ -0,0 +1,294 @@ +############################################################################## +# 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 = module.kms.kms_guid +} + +output "kms_account_id" { + description = "The account ID of the KMS instance." + value = module.kms.kms_account_id +} + +output "kms_instance_crn" { + value = module.kms.key_protect_crn + description = "The CRN of the KMS instance" +} + +############################################################################## +# Events Notification Outputs +############################################################################## + +output "events_notification_crn" { + description = "Event Notification crn" + value = module.event_notifications.crn +} + +output "events_notification_guid" { + description = "Event Notification guid" + value = module.event_notifications.guid +} + +############################################################################## +# Secrets Manager Outputs +############################################################################## + +output "secrets_manager_guid" { + description = "GUID of Secrets Manager instance" + value = module.secrets_manager.secrets_manager_guid +} + +output "secrets_manager_crn" { + value = module.secrets_manager.secrets_manager_crn + description = "CRN of the Secrets Manager instance" +} + +output "secrets_manager_region" { + value = module.secrets_manager.secrets_manager_region + description = "Region of the Secrets Manager instance" +} + +############################################################################## +# COS Outputs +############################################################################## + +output "cos_instance_crn" { + description = "COS instance crn" + value = module.cos.cos_instance_crn +} + +output "cos_instance_guid" { + description = "COS instance guid" + value = module.cos.cos_instance_guid +} + +############################################################################## +# Cloud Monitoring Outputs +############################################################################## + +output "cloud_monitoring_crn" { + value = module.cloud_monitoring.crn + description = "The id of the provisioned IBM Cloud Monitoring instance." +} +output "cloud_monitoring_name" { + value = module.cloud_monitoring.name + description = "The name of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_guid" { + value = module.cloud_monitoring.guid + description = "The guid of the provisioned IBM Cloud Monitoring instance." +} + +output "cloud_monitoring_access_key_name" { + value = module.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.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.cloud_logs.crn + description = "The id of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_guid" { + value = module.cloud_logs.guid + description = "The guid of the provisioned IBM Cloud Logs instance." +} + +output "cloud_logs_name" { + value = module.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.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 = module.at_cos_bucket.buckets[local.activity_tracker_cos_target_bucket_name].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 +} diff --git a/examples/containerized_app_landing_zone/provider.tf b/examples/containerized_app_landing_zone/provider.tf new file mode 100644 index 000000000..af8cd0bf5 --- /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 000000000..5f25467bb --- /dev/null +++ b/examples/containerized_app_landing_zone/variables.tf @@ -0,0 +1,47 @@ +######################################################################################################################## +# 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 "event_notifications_email_list" { + type = list(string) + description = "The list of email address to target out when an event is triggered" + default = [] +} diff --git a/examples/containerized_app_landing_zone/version.tf b/examples/containerized_app_landing_zone/version.tf new file mode 100644 index 000000000..5ea3aca45 --- /dev/null +++ b/examples/containerized_app_landing_zone/version.tf @@ -0,0 +1,25 @@ +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" + } + time = { + source = "hashicorp/time" + version = ">= 0.9.1, < 1.0.0" + } + } +} diff --git a/tests/other_test.go b/tests/other_test.go index e25d9e8bb..a82f00a67 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -17,6 +17,7 @@ const advancedExampleDir = "examples/advanced" const basicExampleDir = "examples/basic" const fscloudExampleDir = "examples/fscloud" const crossKmsSupportExampleDir = "examples/cross_kms_support" +const openshiftLandingZoneExampleDir = "examples/containerized_app_landing_zone" func setupOptions(t *testing.T, prefix string, terraformDir string, ocpVersion string) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ @@ -193,6 +194,55 @@ func TestFSCloudInSchematic(t *testing.T) { assert.Nil(t, err, "This should not have errored") } +func TestOpenshiftLandingZoneExample(t *testing.T) { + t.Parallel() + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Prefix: "ocp-lz", + TarIncludePatterns: []string{ + "*.tf", + openshiftLandingZoneExampleDir + "/*.tf", + openshiftLandingZoneExampleDir + "/kubeconfig/*.*", + fullyConfigurableTerraformDir + "/scripts/*.*", + "/scripts/*.*", + "kubeconfig/*.*", + "modules/kube-audit/*.*", + "modules/worker-pool/*.*", + "modules/kube-audit/kubeconfig/*.*", + "modules/kube-audit/scripts/*.*", + "modules/kube-audit/helm-charts/kube-audit/*.*", + "modules/kube-audit/helm-charts/kube-audit/templates/*.*", + }, + TemplateFolder: openshiftLandingZoneExampleDir, + Tags: []string{"openshift-landing-zone-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 240, + IgnoreAdds: testhelper.Exemptions{ + List: []string{ + "module.scc_wp.restapi_object.cspm", + }, + }, + IgnoreUpdates: testhelper.Exemptions{ + List: []string{ + "module.ocp_base.ibm_container_addons.addons", + "module.logs_agent.helm_release.logs_agent", + "module.monitoring_agent.helm_release.cloud_monitoring_agent", + // Have to ignore account settings as other tests may be updating them concurrently + // which can cause consistency test to fail if not ignored. + "metrics_routing[0].ibm_metrics_router_settings.metrics_router_settings[0]", + }, + }, + }) + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") +} + func TestAddonPermutations(t *testing.T) { testCases := []testaddons.AddonTestCase{ {