diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d545b875..ba718417 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,3 @@ # Primary owner should be listed first in list of global owners, followed by any secondary owners -* @ocofaigh @daniel-butler-irl + +* @iamar7 @shemau diff --git a/.github/settings.yml b/.github/settings.yml index 7409366e..df22076e 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -22,7 +22,7 @@ repository: # Uncomment this description property # and update the description to the current repo description. - # description: "" + description: "This module supports provisioning an IBM Cloud Activity Tracker Event Routing target & routes" # Use a comma-separated list of topics to set on the repo (ensure not to use any caps in the topic string). topics: terraform, ibm-cloud, terraform-module, core-team, activity-tracker, event-routing, at, observability diff --git a/.secrets.baseline b/.secrets.baseline index 0a4efa4a..9e5cca5f 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2024-11-22T17:36:38Z", + "generated_at": "2025-04-17T11:02:06Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -82,7 +82,7 @@ "hashed_secret": "ff9ee043d85595eb255c05dfe32ece02a53efbb2", "is_secret": false, "is_verified": false, - "line_number": 74, + "line_number": 54, "type": "Secret Keyword", "verified_result": null } diff --git a/README.md b/README.md index 1ac84d68..3b6a4dfa 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,13 @@ - -# Terraform modules template project +# IBM Cloud Activity Tracker Event Routing - -[![Incubating (Not yet consumable)](https://img.shields.io/badge/status-Incubating%20(Not%20yet%20consumable)-red)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) -[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-activity-tracker?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-activity-tracker/releases/latest) +[![Graduated (Supported)](https://img.shields.io/badge/Status-Graduated%20(Supported)-brightgreen)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) +[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-activity-tracker?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-activity-tracker/releases/latest) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) -[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) - +This module supports configuring an IBM Cloud Activity Tracker event routing target, routes and settings. -TODO: Replace this with a description of the modules in this repo. - - - ## Overview * [terraform-ibm-activity-tracker](#terraform-ibm-activity-tracker) @@ -33,7 +17,6 @@ TODO: Replace this with a description of the modules in this repo. * [Contributing](#contributing) - - ## terraform-ibm-activity-tracker ### Usage - - ```hcl terraform { required_version = ">= 1.9.0" @@ -68,6 +43,11 @@ terraform { locals { region = "us-south" + target_ids = [ + module.activity_tracker.activity_tracker_targets["icl-target"].id, + module.activity_tracker.activity_tracker_targets["cos-target"].id, + module.activity_tracker.activity_tracker_targets["es-target"].id + ] } provider "ibm" { @@ -75,12 +55,53 @@ provider "ibm" { region = local.region } -module "module_template" { - source = "terraform-ibm-modules//ibm" +module "activity_tracker" { + source = "terraform-ibm-modules/activity-tracker/ibm" version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - region = local.region - name = "instance-name" - resource_group_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" # Replace with the actual ID of resource group to use + + # Cloud Logs target + cloud_logs_targets = [ + { + instance_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" + target_region = local.region + target_name = "icl-target" + } + ] + + # COS target + cos_targets = [ + { + bucket_name = "cos-bucket" + endpoint = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" + instance_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" + target_region = local.region + target_name = "cos-target" + skip_atracker_cos_iam_auth_policy = false + service_to_service_enabled = true + } + ] + + # Event Stream target + eventstreams_targets = [ + { + instance_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" + brokers = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" + topic = "es-topic" + target_region = local.region + target_name = "es-target" + service_to_service_enabled = true + skip_atracker_es_iam_auth_policy = false + } + ] + + # AT Event routing route + activity_tracker_routes = [ + { + locations = ["*", "global"] + target_ids = local.target_ids + route_name = "at-route" + } + ] } ``` @@ -115,7 +136,6 @@ statement instead the previous block. - ### Requirements @@ -123,7 +143,8 @@ statement instead the previous block. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.9.0 | -| [ibm](#requirement\_ibm) | >= 1.71.2, < 2.0.0 | +| [ibm](#requirement\_ibm) | >= 1.76.0, < 2.0.0 | +| [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | ### Modules @@ -133,25 +154,36 @@ No modules. | Name | Type | |------|------| -| [ibm_resource_instance.cos_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource | +| [ibm_atracker_route.atracker_routes](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/atracker_route) | resource | +| [ibm_atracker_settings.atracker_settings](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/atracker_settings) | resource | +| [ibm_atracker_target.atracker_cloud_logs_targets](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/atracker_target) | resource | +| [ibm_atracker_target.atracker_cos_targets](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/atracker_target) | resource | +| [ibm_atracker_target.atracker_eventstreams_targets](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/atracker_target) | resource | +| [ibm_iam_authorization_policy.atracker_cloud_logs](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_iam_authorization_policy.atracker_cos](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [ibm_iam_authorization_policy.atracker_es](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource | +| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_cloud_logs_auth_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [time_sleep.wait_for_event_stream_auth_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | +| [ibm_iam_account_settings.iam_account_settings](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/data-sources/iam_account_settings) | data source | ### Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [name](#input\_name) | A descriptive name used to identify the resource instance. | `string` | n/a | yes | -| [plan](#input\_plan) | The name of the plan type supported by service. | `string` | `"standard"` | no | -| [resource\_group\_id](#input\_resource\_group\_id) | The ID of the resource group where you want to create the service. | `string` | n/a | yes | -| [resource\_tags](#input\_resource\_tags) | List of resource tag to associate with the instance. | `list(string)` | `[]` | no | +| [activity\_tracker\_routes](#input\_activity\_tracker\_routes) | List of routes to be created, maximum four routes are allowed |
list(object({
locations = list(string)
target_ids = list(string)
route_name = string
}))
| `[]` | no | +| [cloud\_logs\_targets](#input\_cloud\_logs\_targets) | List of Cloud Logs targets to be created |
list(object({
instance_id = string
target_region = optional(string)
target_name = string
skip_atracker_cloud_logs_iam_auth_policy = optional(bool, false)
}))
| `[]` | no | +| [cos\_targets](#input\_cos\_targets) | List of Cloud Object Storage targets to be created |
list(object({
endpoint = string
bucket_name = string
instance_id = string
api_key = optional(string)
service_to_service_enabled = optional(bool, true)
target_region = optional(string)
target_name = string
skip_atracker_cos_iam_auth_policy = optional(bool, false)
}))
| `[]` | no | +| [eventstreams\_targets](#input\_eventstreams\_targets) | List of Event Streams targets to be created |
list(object({
instance_id = string
brokers = list(string)
topic = string
api_key = optional(string)
service_to_service_enabled = optional(bool, true)
target_region = optional(string)
target_name = string
skip_atracker_es_iam_auth_policy = optional(bool, false)
}))
| `[]` | no | +| [global\_event\_routing\_settings](#input\_global\_event\_routing\_settings) | Global account settings for event routing. [Learn more](https://cloud.ibm.com/docs/atracker?topic=atracker-settings&interface=ui) |
object({
default_targets = optional(list(string), [])
metadata_region_primary = string
metadata_region_backup = optional(string)
permitted_target_regions = list(string)
private_api_endpoint_only = optional(bool, false)
})
| `null` | no | ### Outputs | Name | Description | |------|-------------| -| [account\_id](#output\_account\_id) | An alpha-numeric value identifying the account ID. | -| [crn](#output\_crn) | The CRN of the resource instance. | -| [guid](#output\_guid) | The GUID of the resource instance. | -| [id](#output\_id) | The unique identifier of the resource instance. | +| [activity\_tracker\_routes](#output\_activity\_tracker\_routes) | The map of created routes | +| [activity\_tracker\_settings](#output\_activity\_tracker\_settings) | AT event routing account global settings. | +| [activity\_tracker\_targets](#output\_activity\_tracker\_targets) | The map of created targets | diff --git a/examples/advanced/main.tf b/examples/advanced/main.tf index 88360afb..3f3eccce 100644 --- a/examples/advanced/main.tf +++ b/examples/advanced/main.tf @@ -1,6 +1,6 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## +############################################################################## +# Resource Group +############################################################################## module "resource_group" { source = "terraform-ibm-modules/resource-group/ibm" @@ -10,23 +10,185 @@ module "resource_group" { existing_resource_group_name = var.resource_group } -######################################################################################################################## -# COS -######################################################################################################################## +############################################################################## +# Cloud Logs +############################################################################## -# -# Developer tips: -# - Call the local module / modules in the example to show how they can be consumed -# - Include the actual module source as a code comment like below so consumers know how to consume from correct location -# +module "cloud_logs" { + source = "terraform-ibm-modules/cloud-logs/ibm" + version = "1.0.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + data_storage = { + logs_data = { + enabled = false + }, + metrics_data = { + enabled = false + } + } +} -module "cos" { - source = "../.." - # remove the above line and uncomment the below 2 lines to consume the module from the registry - # source = "terraform-ibm-modules//ibm" - # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - name = "${var.prefix}-cos" +############################################################################## +# Event Streams +############################################################################## + +locals { + topic_name = "${var.prefix}-topic" +} + +module "event_streams" { + source = "terraform-ibm-modules/event-streams/ibm" + version = "3.4.2" + es_name = "${var.prefix}-eventsteams-instance" + tags = var.resource_tags + region = var.region resource_group_id = module.resource_group.resource_group_id + plan = "standard" + topics = [{ + name = local.topic_name + partitions = 1 + config = { + "cleanup.policy" = "delete" + "retention.ms" = "86400000" # 1 Day + "retention.bytes" = "10485760" # 10 MB + "segment.bytes" = "536870912" # 512 MB + } + }, ] +} + +############################################################################## +# Key Protect Instance + Key (used to encrypt bucket) +############################################################################## + +locals { + key_ring_name = "at" + key_name = "at-key" +} + +module "key_protect" { + source = "terraform-ibm-modules/kms-all-inclusive/ibm" + version = "4.21.6" + resource_group_id = module.resource_group.resource_group_id + region = var.region resource_tags = var.resource_tags - plan = "cos-one-rate-plan" + keys = [ + { + key_ring_name = local.key_ring_name + keys = [ + { + key_name = local.key_name + } + ] + } + ] + key_protect_instance_name = "${var.prefix}-kp" +} + +############################################################################## +# COS instance (used for AT target) +############################################################################## + +module "cos" { + source = "terraform-ibm-modules/cos/ibm" + version = "8.21.8" + resource_group_id = module.resource_group.resource_group_id + cos_instance_name = "${var.prefix}-cos" + cos_tags = var.resource_tags + create_cos_bucket = false +} + +locals { + at_bucket_name = "${var.prefix}-at-data" +} + +module "buckets" { + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "8.21.8" + bucket_configs = [ + { + bucket_name = local.at_bucket_name + kms_encryption_enabled = true + region_location = var.region + resource_instance_id = module.cos.cos_instance_id + kms_guid = module.key_protect.kms_guid + kms_key_crn = module.key_protect.keys["${local.key_ring_name}.${local.key_name}"].crn + skip_iam_authorization_policy = false # Auth policy created in first bucket + } + ] +} + +############################################################################## +# - Activity Tracker Event Routing config: +# - COS AT target +# - Cloud Logs AT target +# - Event Streams AT target +# - AT route to all above targets +# - Global Event Routing configuration +############################################################################## + +locals { + icl_target_name = "${var.prefix}-icl-target" + es_target_name = "${var.prefix}-es-target" + cos_target_name = "${var.prefix}-cos-target" + target_ids = [ + module.activity_tracker.activity_tracker_targets[local.cos_target_name].id, + module.activity_tracker.activity_tracker_targets[local.es_target_name].id, + module.activity_tracker.activity_tracker_targets[local.icl_target_name].id + ] +} + +module "activity_tracker" { + source = "../../" + # delete line above and use below syntax to pull module source from hashicorp when consuming this module + # source = "terraform-ibm-modules/observability-instances/ibm" + # version = "X.Y.Z" # Replace "X.X.X" with a release version to lock into a specific release + + # Activity Tracker targets + cloud_logs_targets = [ + { + instance_id = module.cloud_logs.crn + target_region = var.region + target_name = local.icl_target_name + } + ] + cos_targets = [ + { + bucket_name = local.at_bucket_name + endpoint = module.buckets.buckets[local.at_bucket_name].s3_endpoint_direct + instance_id = module.cos.cos_instance_id + target_region = var.region + target_name = local.cos_target_name + skip_atracker_cos_iam_auth_policy = false + service_to_service_enabled = true + } + ] + eventstreams_targets = [ + { + instance_id = module.event_streams.id + brokers = [module.event_streams.kafka_brokers_sasl[0]] + topic = local.topic_name + target_region = var.region + target_name = local.es_target_name + service_to_service_enabled = true + skip_atracker_es_iam_auth_policy = false + } + ] + + # Activity Tracker route + activity_tracker_routes = [ + { + locations = ["*", "global"] + target_ids = local.target_ids + route_name = "${var.prefix}-route" + } + ] + + # Global Event Routing Settings + global_event_routing_settings = { + default_targets = local.target_ids + permitted_target_regions = ["us-south", "eu-de", "us-east", "eu-es", "eu-gb", "au-syd", "br-sao", "ca-tor", "eu-es", "jp-tok", "jp-osa", "in-che", "eu-fr2"] + metadata_region_primary = "us-south" + private_api_endpoint_only = false + } } diff --git a/examples/advanced/outputs.tf b/examples/advanced/outputs.tf index 316751fb..c51cc0c2 100644 --- a/examples/advanced/outputs.tf +++ b/examples/advanced/outputs.tf @@ -2,37 +2,42 @@ # Outputs ############################################################################## -# -# Developer tips: -# - Include all relevant outputs from the modules being called in the example -# +output "resource_group_name" { + description = "Resource group name." + value = module.resource_group.resource_group_name +} -output "account_id" { - description = "An alpha-numeric value identifying the account ID." - value = module.cos.account_id +output "resource_group_id" { + description = "Resource group ID." + value = module.resource_group.resource_group_id } -output "guid" { - description = "The GUID of the resource instance." - value = module.cos.account_id +output "cloud_logs_crn" { + value = module.cloud_logs.crn + description = "The crn of the provisioned IBM Cloud Logs instance." } -output "id" { - description = "The unique identifier of the resource instance." - value = module.cos.id +output "cos_crn" { + value = module.cos.cos_instance_crn + description = "The crn of the provisioned object storage instance." } -output "crn" { - description = "The CRN of the resource instance." - value = module.cos.crn +output "event_streams_crn" { + value = module.event_streams.crn + description = "The crn of the provisioned event stream instance." } -output "resource_group_name" { - description = "Resource group name." - value = module.resource_group.resource_group_name +output "event_routing_targets" { + value = module.activity_tracker.activity_tracker_targets + description = "The created AT event routing targets." } -output "resource_group_id" { - description = "Resource group ID." - value = module.resource_group.resource_group_id +output "event_routing_routes" { + value = module.activity_tracker.activity_tracker_routes + description = "The created AT event routing routes." +} + +output "global_event_routing_settings" { + value = module.activity_tracker.activity_tracker_settings + description = "The global event routing settings of the account." } diff --git a/examples/advanced/variables.tf b/examples/advanced/variables.tf index d4603642..440bbebf 100644 --- a/examples/advanced/variables.tf +++ b/examples/advanced/variables.tf @@ -2,38 +2,31 @@ # Input variables ######################################################################################################################## -# -# Module developer tips: -# - Examples are references that consumers can use to see how the module can be consumed. They are not designed to be -# flexible re-usable solutions for general consumption, so do not expose any more variables here and instead hard -# code things in the example main.tf with code comments explaining the different configurations. -# - For the same reason as above, do not add default values to the example inputs. -# - variable "ibmcloud_api_key" { type = string - description = "The IBM Cloud API Key." + description = "The IBM Cloud API Token" sensitive = true } variable "region" { type = string - description = "Region to provision all resources created by this example." + description = "Region where resources will be created" + default = "us-south" } variable "prefix" { type = string - description = "A string value to prefix to all resources created by this example." + description = "Prefix for name of all resource created by this example" } variable "resource_group" { type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable." + description = "An existing resource group name to use for this example, if unset a new resource group will be created" default = null } variable "resource_tags" { type = list(string) - description = "List of resource tag to associate with all resource instances created by this example." + description = "Optional list of tags to be added to created resources" default = [] } diff --git a/examples/advanced/version.tf b/examples/advanced/version.tf index ecfa9780..5ac5801d 100644 --- a/examples/advanced/version.tf +++ b/examples/advanced/version.tf @@ -1,16 +1,11 @@ terraform { required_version = ">= 1.9.0" - - # - # Developer tips: - # - Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. - # - + # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (basic), and 1 example that will always use the latest provider version (advanced). required_providers { ibm = { - source = "IBM-Cloud/ibm" - version = ">= 1.71.2, < 2.0.0" + source = "ibm-cloud/ibm" + version = ">= 1.76.0" } } } diff --git a/examples/basic/main.tf b/examples/basic/main.tf index cf665dbd..c5959a54 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -1,6 +1,6 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## +############################################################################## +# Resource Group +############################################################################## module "resource_group" { source = "terraform-ibm-modules/resource-group/ibm" @@ -10,22 +10,69 @@ module "resource_group" { existing_resource_group_name = var.resource_group } -######################################################################################################################## -# COS -######################################################################################################################## - -# -# Developer tips: -# - Call the local module / modules in the example to show how they can be consumed -# - include the actual module source as a code comment like below so consumers know how to consume from correct location -# - -module "cos" { - source = "../.." - # remove the above line and uncomment the below 2 lines to consume the module from the registry - # source = "terraform-ibm-modules//ibm" - # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - name = "${var.prefix}-cos" +############################################################################## +# Event Streams +############################################################################## + +locals { + topic_name = "${var.prefix}-topic" +} + +module "event_streams" { + source = "terraform-ibm-modules/event-streams/ibm" + version = "3.4.2" + es_name = "${var.prefix}-eventsteams" + tags = var.resource_tags + region = var.region resource_group_id = module.resource_group.resource_group_id - resource_tags = var.resource_tags + plan = "standard" + topics = [{ + name = local.topic_name + partitions = 1 + config = { + "cleanup.policy" = "delete" + "retention.ms" = "86400000" # 1 Day + "retention.bytes" = "10485760" # 10 MB + "segment.bytes" = "536870912" # 512 MB + } + }, ] +} + +############################################################################## +# - Activity Tracker Event Routing config: +# - Event Streams AT target +# - AT route event stream target +############################################################################## + +locals { + es_target_name = "${var.prefix}-es-at-target" +} + +module "activity_tracker" { + source = "../../" + # delete line above and use below syntax to pull module source from hashicorp when consuming this module + # source = "terraform-ibm-modules/observability-instances/ibm" + # version = "X.Y.Z" # Replace "X.X.X" with a release version to lock into a specific release + + # Activity Tracker target + eventstreams_targets = [ + { + instance_id = module.event_streams.id + brokers = [module.event_streams.kafka_brokers_sasl[0]] + topic = local.topic_name + target_region = var.region + target_name = local.es_target_name + service_to_service_enabled = true + skip_atracker_es_iam_auth_policy = false + } + ] + + # Activity Tracker route + activity_tracker_routes = [ + { + locations = ["*", "global"] + target_ids = [module.activity_tracker.activity_tracker_targets[local.es_target_name].id] + route_name = "${var.prefix}-at-route" + } + ] } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 552db482..566bc90e 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -2,31 +2,6 @@ # Outputs ######################################################################################################################## -# -# Developer tips: -# - Include all relevant outputs from the modules being called in the example -# - -output "account_id" { - description = "An alpha-numeric value identifying the account ID." - value = module.cos.account_id -} - -output "guid" { - description = "The GUID of the resource instance." - value = module.cos.account_id -} - -output "id" { - description = "The unique identifier of the resource instance." - value = module.cos.id -} - -output "crn" { - description = "The CRN of the resource instance." - value = module.cos.crn -} - output "resource_group_name" { description = "Resource group name." value = module.resource_group.resource_group_name @@ -36,3 +11,18 @@ output "resource_group_id" { description = "Resource group ID." value = module.resource_group.resource_group_id } + +output "event_streams_crn" { + description = "The CRN of the event stream resource instance." + value = module.event_streams.crn +} + +output "event_routing_targets" { + value = module.activity_tracker.activity_tracker_targets + description = "The created AT event routing target." +} + +output "event_routing_routes" { + value = module.activity_tracker.activity_tracker_routes + description = "The created AT event routing route." +} diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index d4603642..440bbebf 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -2,38 +2,31 @@ # Input variables ######################################################################################################################## -# -# Module developer tips: -# - Examples are references that consumers can use to see how the module can be consumed. They are not designed to be -# flexible re-usable solutions for general consumption, so do not expose any more variables here and instead hard -# code things in the example main.tf with code comments explaining the different configurations. -# - For the same reason as above, do not add default values to the example inputs. -# - variable "ibmcloud_api_key" { type = string - description = "The IBM Cloud API Key." + description = "The IBM Cloud API Token" sensitive = true } variable "region" { type = string - description = "Region to provision all resources created by this example." + description = "Region where resources will be created" + default = "us-south" } variable "prefix" { type = string - description = "A string value to prefix to all resources created by this example." + description = "Prefix for name of all resource created by this example" } variable "resource_group" { type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable." + description = "An existing resource group name to use for this example, if unset a new resource group will be created" default = null } variable "resource_tags" { type = list(string) - description = "List of resource tag to associate with all resource instances created by this example." + description = "Optional list of tags to be added to created resources" default = [] } diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 401504c5..6dada8eb 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,16 +1,9 @@ terraform { required_version = ">= 1.9.0" - - # - # Developer tips: - # - Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. - # - required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.71.2" + version = "1.76.0" } } } diff --git a/main.tf b/main.tf index b6b879e2..7ecb0260 100644 --- a/main.tf +++ b/main.tf @@ -1,13 +1,196 @@ -# -# Developer tips: -# - Below code should be replaced with the code for the root level module -# - -resource "ibm_resource_instance" "cos_instance" { - name = var.name - resource_group_id = var.resource_group_id - service = "cloud-object-storage" - plan = var.plan - location = "global" - tags = var.resource_tags +######################################################################## +# Activity Tracker Event Routing +######################################################################### + +data "ibm_iam_account_settings" "iam_account_settings" { +} + +resource "time_sleep" "wait_for_authorization_policy" { + depends_on = [ibm_iam_authorization_policy.atracker_cos] + create_duration = "30s" +} + +# atracker to COS s2s auth policy +resource "ibm_iam_authorization_policy" "atracker_cos" { + for_each = nonsensitive({ for target in var.cos_targets : target.target_name => target if target.service_to_service_enabled && !target.skip_atracker_cos_iam_auth_policy }) + source_service_name = "atracker" + roles = ["Object Writer"] + description = "Permit AT service Object Writer access to COS instance ${each.value.instance_id}" + + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = data.ibm_iam_account_settings.iam_account_settings.account_id + } + + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = "cloud-object-storage" + } + + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = split(":", each.value.instance_id)[7] + } + + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "bucket" + } + + resource_attributes { + name = "resource" + operator = "stringEquals" + value = each.value.bucket_name + } + + lifecycle { + create_before_destroy = true + } +} + +resource "time_sleep" "wait_for_cloud_logs_auth_policy" { + depends_on = [ibm_iam_authorization_policy.atracker_cloud_logs] + create_duration = "30s" +} + +# atracker to cloud logs s2s auth policy +resource "ibm_iam_authorization_policy" "atracker_cloud_logs" { + for_each = { for target in var.cloud_logs_targets : target.target_name => target } + source_service_name = "atracker" + target_service_name = "logs" + target_resource_instance_id = regex(".*:(.*)::", each.value.instance_id)[0] + roles = ["Sender"] + description = "Permit AT service Sender access to Cloud Logs instance ${each.value.instance_id}" +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_event_stream_auth_policy" { + depends_on = [ibm_iam_authorization_policy.atracker_es] + create_duration = "30s" +} + +# atracker to event stream s2s auth policy +resource "ibm_iam_authorization_policy" "atracker_es" { + for_each = nonsensitive({ for target in var.eventstreams_targets : target.target_name => target if target.service_to_service_enabled && !target.skip_atracker_es_iam_auth_policy }) + source_service_name = "atracker" + target_service_name = "messagehub" + target_resource_instance_id = regex(".*:(.*)::", each.value.instance_id)[0] + roles = ["Writer"] + description = "Permit AT service `Writer` access to the eventstream instance ${each.value.instance_id}" +} + +# COS targets +resource "ibm_atracker_target" "atracker_cos_targets" { + depends_on = [time_sleep.wait_for_authorization_policy] + for_each = nonsensitive({ for target in var.cos_targets : target.target_name => target }) + cos_endpoint { + endpoint = each.value.endpoint + bucket = each.value.bucket_name + target_crn = each.value.instance_id + api_key = each.value.api_key + service_to_service_enabled = each.value.service_to_service_enabled + } + name = each.key + target_type = "cloud_object_storage" + region = each.value.target_region +} + +# Event Streams targets +resource "ibm_atracker_target" "atracker_eventstreams_targets" { + depends_on = [time_sleep.wait_for_event_stream_auth_policy] + for_each = nonsensitive({ for target in var.eventstreams_targets : target.target_name => target }) + eventstreams_endpoint { + target_crn = each.value.instance_id + brokers = each.value.brokers + topic = each.value.topic + api_key = each.value.api_key + service_to_service_enabled = each.value.service_to_service_enabled + } + name = each.key + target_type = "event_streams" + region = each.value.target_region +} + +# Cloud Logs targets +resource "ibm_atracker_target" "atracker_cloud_logs_targets" { + depends_on = [time_sleep.wait_for_cloud_logs_auth_policy] + for_each = { for target in var.cloud_logs_targets : target.target_name => target if !target.skip_atracker_cloud_logs_iam_auth_policy } + cloudlogs_endpoint { + target_crn = each.value.instance_id + } + name = each.key + target_type = "cloud_logs" + region = each.value.target_region +} + +# Routes +resource "ibm_atracker_route" "atracker_routes" { + for_each = { for route in var.activity_tracker_routes : route.route_name => route } + name = each.key + rules { + locations = each.value.locations + target_ids = each.value.target_ids + } + lifecycle { + create_before_destroy = true + } +} + +######################################################################## +# Event Routing Global Settings +######################################################################### + +resource "ibm_atracker_settings" "atracker_settings" { + count = var.global_event_routing_settings == null ? 0 : 1 + default_targets = var.global_event_routing_settings.default_targets + metadata_region_primary = var.global_event_routing_settings.metadata_region_primary + metadata_region_backup = var.global_event_routing_settings.metadata_region_backup + permitted_target_regions = var.global_event_routing_settings.permitted_target_regions + private_api_endpoint_only = var.global_event_routing_settings.private_api_endpoint_only + + lifecycle { + create_before_destroy = true + } +} + +locals { + # Used for outputs only + cos_targets = { + for cos_target in ibm_atracker_target.atracker_cos_targets : + cos_target["name"] => { + id = cos_target["id"] + crn = cos_target["crn"] + } + } + + eventstreams_targets = { + for eventstreams_target in ibm_atracker_target.atracker_eventstreams_targets : + eventstreams_target["name"] => { + id = eventstreams_target["id"] + crn = eventstreams_target["crn"] + } + } + + cloud_log_targets = { + for cloud_log_target in ibm_atracker_target.atracker_cloud_logs_targets : + cloud_log_target["name"] => { + id = cloud_log_target["id"] + crn = cloud_log_target["crn"] + } + } + + activity_tracker_routes = { + for atracker_route in ibm_atracker_route.atracker_routes : + atracker_route["name"] => { + id = atracker_route["id"] + crn = atracker_route["crn"] + } + } + + activity_tracker_targets = merge(local.cos_targets, local.eventstreams_targets, local.cloud_log_targets) + } diff --git a/outputs.tf b/outputs.tf index 1c0cf4cc..b17603dc 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,30 +1,22 @@ -######################################################################################################################## -# Outputs -######################################################################################################################## +######################################################################## +# Activity Tracker Event Routing +######################################################################### -# -# Developer tips: -# - Below are some good practise sample outputs -# - They should be updated for outputs applicable to the module being added -# - Use variable validation when possible -# - -output "account_id" { - description = "An alpha-numeric value identifying the account ID." - value = ibm_resource_instance.cos_instance.account_id +# Event Routing Target +output "activity_tracker_targets" { + value = local.activity_tracker_targets + description = "The map of created targets" } -output "guid" { - description = "The GUID of the resource instance." - value = ibm_resource_instance.cos_instance.account_id +# Event Routing Route +output "activity_tracker_routes" { + value = local.activity_tracker_routes + description = "The map of created routes" } -output "id" { - description = "The unique identifier of the resource instance." - value = ibm_resource_instance.cos_instance.id -} +# Event Routing Settings -output "crn" { - description = "The CRN of the resource instance." - value = ibm_resource_instance.cos_instance.crn +output "activity_tracker_settings" { + value = ibm_atracker_settings.atracker_settings + description = "AT event routing account global settings." } diff --git a/tests/pr_test.go b/tests/pr_test.go index 8867ed00..f886f96c 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -2,6 +2,7 @@ package test import ( + "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -15,12 +16,26 @@ const resourceGroup = "geretain-test-resources" const advancedExampleDir = "examples/advanced" const basicExampleDir = "examples/basic" +var validRegions = []string{ + "au-syd", + "br-sao", + "ca-tor", + "eu-de", + "eu-gb", + "eu-es", + "jp-osa", + "jp-tok", + "us-south", + "us-east", +} + func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ Testing: t, TerraformDir: dir, Prefix: prefix, ResourceGroup: resourceGroup, + Region: validRegions[rand.Intn(len(validRegions))], }) return options } @@ -29,7 +44,7 @@ func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptio func TestRunBasicExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-basic", basicExampleDir) + options := setupOptions(t, "at-basic", basicExampleDir) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") @@ -39,7 +54,7 @@ func TestRunBasicExample(t *testing.T) { func TestRunAdvancedExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-adv", advancedExampleDir) + options := setupOptions(t, "at-adv", advancedExampleDir) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") @@ -50,7 +65,7 @@ func TestRunAdvancedExample(t *testing.T) { func TestRunUpgradeExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-adv-upg", advancedExampleDir) + options := setupOptions(t, "at-adv-upg", advancedExampleDir) output, err := options.RunTestUpgrade() if !options.UpgradeTestSkipped { diff --git a/variables.tf b/variables.tf index a9d9899a..f1569c1b 100644 --- a/variables.tf +++ b/variables.tf @@ -1,36 +1,109 @@ -######################################################################################################################## -# Input Variables -######################################################################################################################## - -# -# Developer tips: -# - Below are some common module input variables -# - They should be updated for input variables applicable to the module being added -# - Use variable validation when possible -# - -variable "name" { - type = string - description = "A descriptive name used to identify the resource instance." +######################################################################## +# Activity Tracker Event Routing +######################################################################### + +# Cloud Object Storage Targets +variable "cos_targets" { + type = list(object({ + endpoint = string + bucket_name = string + instance_id = string + api_key = optional(string) + service_to_service_enabled = optional(bool, true) + target_region = optional(string) + target_name = string + skip_atracker_cos_iam_auth_policy = optional(bool, false) + })) + default = [] + description = "List of Cloud Object Storage targets to be created" + sensitive = true + + validation { + condition = alltrue([for cos_target in var.cos_targets : (cos_target.service_to_service_enabled == true && cos_target.api_key == null) || (cos_target.service_to_service_enabled == false && cos_target.api_key != null)]) + error_message = "The value of `api_key` should not be provided if 'service_to_service_enabled' is set to true for object storage targets. If you want to use 'api_key', set 'service_to_service_enabled' to false." + } } -variable "plan" { - type = string - description = "The name of the plan type supported by service." - default = "standard" +# Event Streams Targets +variable "eventstreams_targets" { + type = list(object({ + instance_id = string + brokers = list(string) + topic = string + api_key = optional(string) + service_to_service_enabled = optional(bool, true) + target_region = optional(string) + target_name = string + skip_atracker_es_iam_auth_policy = optional(bool, false) + })) + default = [] + description = "List of Event Streams targets to be created" + sensitive = true + validation { - condition = contains(["standard", "cos-one-rate-plan"], var.plan) - error_message = "The specified pricing plan is not available. The following plans are supported: 'standard', 'cos-one-rate-plan'" + condition = alltrue([for es_target in var.eventstreams_targets : (es_target.service_to_service_enabled == true && es_target.api_key == null) || (es_target.service_to_service_enabled == false && es_target.api_key != null)]) + error_message = "The value of `api_key` should not be provided if 'service_to_service_enabled' is set to tru for event stream targets. If you want to use 'api_key', set 'service_to_service_enabled' to false." } } -variable "resource_group_id" { - type = string - description = "The ID of the resource group where you want to create the service." +# Cloud Logs Targets +variable "cloud_logs_targets" { + type = list(object({ + instance_id = string + target_region = optional(string) + target_name = string + skip_atracker_cloud_logs_iam_auth_policy = optional(bool, false) + })) + default = [] + description = "List of Cloud Logs targets to be created" } -variable "resource_tags" { - type = list(string) - description = "List of resource tag to associate with the instance." +# Routes +variable "activity_tracker_routes" { + type = list(object({ + locations = list(string) + target_ids = list(string) + route_name = string + })) + description = "List of routes to be created, maximum four routes are allowed" default = [] + + validation { + condition = length(var.activity_tracker_routes) <= 4 + error_message = "The number of activity tracker event routing routes should be less than or equal to 4" + } + + validation { + condition = alltrue([for activity_tracker_route in var.activity_tracker_routes : length(activity_tracker_route.locations) > 0]) + error_message = "The length of locations can not be zero for activity tracker event routing routes" + } + + validation { + condition = alltrue([for activity_tracker_route in var.activity_tracker_routes : length(activity_tracker_route.target_ids) > 0]) + error_message = "The length of `target_ids` for activity tracker event routing can not be zero" + } +} +# Event Routing Setting +variable "global_event_routing_settings" { + type = object({ + default_targets = optional(list(string), []) + metadata_region_primary = string + metadata_region_backup = optional(string) + permitted_target_regions = list(string) + private_api_endpoint_only = optional(bool, false) + }) + description = "Global account settings for event routing. [Learn more](https://cloud.ibm.com/docs/atracker?topic=atracker-settings&interface=ui)" + default = null + + # https://cloud.ibm.com/docs/atracker?topic=atracker-regions#regions-atracker + validation { + error_message = "Valid regions for `permitted_target_regions` to control where targets collecting audit events can be located are: us-south, eu-de, us-east, eu-es, eu-gb, au-syd, br-sao, ca-tor, eu-es, jp-tok, jp-osa, in-che, eu-fr2" + condition = (var.global_event_routing_settings == null ? + true : + alltrue([ + for region in var.global_event_routing_settings.permitted_target_regions : + contains(["us-south", "eu-de", "us-east", "eu-es", "eu-gb", "au-syd", "br-sao", "ca-tor", "eu-es", "jp-tok", "jp-osa", "in-che", "eu-fr2"], region) + ]) + ) + } } diff --git a/version.tf b/version.tf index e51de7f6..4a705029 100644 --- a/version.tf +++ b/version.tf @@ -1,18 +1,14 @@ terraform { - # require 1.9 or later to make use of cross-object referencing for input variable validations - # more info: https://www.hashicorp.com/blog/terraform-1-9-enhances-input-variable-validations required_version = ">= 1.9.0" - - # - # Developer tips: - # - If your module requires any terraform providers, add them the "required_providers" section below. - # - Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions. - # - required_providers { + # Use "greater than or equal to" range in modules ibm = { - source = "IBM-Cloud/ibm" - version = ">= 1.71.2, < 2.0.0" + source = "ibm-cloud/ibm" + version = ">= 1.76.0, < 2.0.0" + } + time = { + source = "hashicorp/time" + version = ">= 0.9.1, < 1.0.0" } } }