diff --git a/README.md b/README.md index 58e47fe..c088a91 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ A module for provisioning an [IBM Cloud Security and Compliance Center Workload * [Examples](./examples) * [Advanced example](./examples/advanced) * [Basic example](./examples/basic) + * [Enterprise Example: SCC-WP with App Config and Trusted Profiles](./examples/enterprise) * [Contributing](#contributing) diff --git a/examples/enterprise/README.md b/examples/enterprise/README.md new file mode 100644 index 0000000..2765fbd --- /dev/null +++ b/examples/enterprise/README.md @@ -0,0 +1,172 @@ +# Enterprise Example: SCC-WP with App Config and Trusted Profiles + +> Only supported in an enterprise account. + +This example demonstrates the full deployment of: + +- IBM Cloud App Configuration +- IBM Cloud Security and Compliance Center Workload Protection (SCC-WP) +- IAM Trusted Profile Template with 3 Trusted Profiles +- Template assignment to account groups +- Configuration Aggregator to link SCC-WP with App Config + +--- + +## Flow Overview + +1. **Create or reuse a resource group** + A resource group is created or reused. + +2. **Deploy App Config** + App Config is deployed along with a collection for organizing features and properties. + +3. **Deploy SCC Workload Protection** + SCC-WP is deployed with the `graduated-tier` plan. + +4. **Create a Trusted Profile Template with 3 profiles** + - **App Config -- Enterprise** + For IAM template management across the enterprise. + - **App Config -- General** + For reading platform and IAM services. + - **SCC-WP Profile** + For integrating SCC-WP with App Config and enterprise usage. + +5. **Assign the template to account groups** + All child accounts or specific account groups receive the profile template. + +6. **Create SCC-WP Config Aggregator** + The aggregator connects SCC-WP to App Config and uses the enterprise trusted profile and template ID to enforce secure access. + +--- + +## Notes + +- The `trusted_profile_links` block in each trusted profile is used to **link the profile to a specific CRN**, like a VSI or App Config instance, enabling the identity to assume the trusted profile. + +--- + +## Usage + +```bash +terraform init +terraform apply +``` + +--- + +## Known issue + +There is a [known issue](https://github.com/IBM-Cloud/terraform-provider-ibm/issues/6164) which you will face if you attempt a re-apply of this example after the initial apply has complete. + +- The `ibm_iam_trusted_profile_template` will detect a update in place which looks something like this: + ``` + Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + ~ update in-place + + Terraform will perform the following actions: + + # module.trusted_profile_template.ibm_iam_trusted_profile_template.trusted_profile_template_instance will be updated in-place + ~ resource "ibm_iam_trusted_profile_template" "trusted_profile_template_instance" { + id = "ProfileTemplate-8b16cb82-b9b4-434a-b678-12c82033e9a7/1" + name = "Trusted Profile Template for SCC-WP" + # (11 unchanged attributes hidden) + + ~ profile { + name = "Trusted Profile for IBM Cloud CSPM in SCC-WP" + # (1 unchanged attribute hidden) + + ~ identities { + ~ iam_id = "crn-crn:v1:bluemix:public:apprapp:us-south:a/1f27e30e31f0486980cb0b2657d483f7:c89c16ce-3505-453e-8990-c7473657779b::" -> "crn:v1:bluemix:public:apprapp:us-south:a/1f27e30e31f0486980cb0b2657d483f7:c89c16ce-3505-453e-8990-c7473657779b::" + # (4 unchanged attributes hidden) + } + } + + # (2 unchanged blocks hidden) + } + ``` +- Any account groups that were assigned the trusted profile template will also see an update in place. For example: + ``` + # module.trusted_profile_template.ibm_iam_trusted_profile_template_assignment.account_settings_template_assignment_instance["AccountGroup-3596923e5a674a7fa7eb01c5b17fce8e"] will be updated in-place + ~ resource "ibm_iam_trusted_profile_template_assignment" "account_settings_template_assignment_instance" { + id = "TemplateAssignment-befcf82f-6bd2-4922-b2c1-5c161685488c" + + resources = (known after apply) + # (13 unchanged attributes hidden) + } + ``` +- If you then proceed with the apply, it will fail with the following error: + ``` + module.trusted_profile_template.ibm_iam_trusted_profile_template.trusted_profile_template_instance: Modifying... [id=ProfileTemplate-8b16cb82-b9b4-434a-b678-12c82033e9a7/1] + ╷ + │ Error: UpdateProfileTemplateVersionWithContext failed Template in committed state. + │ { + │ "StatusCode": 422, + │ "Headers": { + │ "Akamai-Grn": [ + │ "0.bdb01302.1744900183.cacb5e65" + │ ], + │ "Cache-Control": [ + │ "no-cache, no-store, must-revalidate" + │ ], + │ "Content-Language": [ + │ "en-US" + │ ], + │ "Content-Length": [ + │ "334" + │ ], + │ "Content-Type": [ + │ "application/json" + │ ], + │ "Date": [ + │ "Thu, 17 Apr 2025 14:29:43 GMT" + │ ], + │ "Expires": [ + │ "0" + │ ], + │ "Ibm-Cloud-Service-Name": [ + │ "iam-identity" + │ ], + │ "Pragma": [ + │ "no-cache" + │ ], + │ "Set-Cookie": [ + │ "ak_bmsc=540034860F090FE00019133754696C9B~000000000000000000000000000000~YAAQvbATAmL0BRuWAQAA59YnRBuMehleeYJJD1yOUDM/362Yj0eaMmjUwIsm8G4Muf/XUfjIHA5XJGWRI1lc21CDcPI7yVqdHcX5h4l59hxg+cqzHDBeNUIojafPY7k82U8X9ECSo5XFuyfFx4tlSOVclDZ05o2vLfNlpsi+Gr8kBbwySy/XGjfPi5g0ZLRq1Segl+vK7mV2HNdboRRw2MKdZpxYUgIrx/WhFgsuIgZBx6xzDLVjLYZHfFhZ1pF/s/vgOC9pPv8oAOxbas8pvR0hfeL4/9tNLiqws2kMal8wDeuytpy0qEzFLvlFRTa9YG0GYXthz5MxlA/VX5fnxfPcc7SGW2dTu1JFYKig/SapnDnqJCo/n/YlJLrjfguPWQjK; Domain=.cloud.ibm.com; Path=/; Expires=Thu, 17 Apr 2025 16:29:43 GMT; Max-Age=7200" + │ ], + │ "Strict-Transport-Security": [ + │ "max-age=31536000; includeSubDomains" + │ ], + │ "Transaction-Id": [ + │ "OXRxZ2M-8c573b755d4f4a28bb60756766ea1c64" + │ ], + │ "X-Content-Type-Options": [ + │ "nosniff" + │ ], + │ "X-Correlation-Id": [ + │ "OXRxZ2M-8c573b755d4f4a28bb60756766ea1c64" + │ ], + │ "X-Proxy-Upstream-Service-Time": [ + │ "127" + │ ], + │ "X-Request-Id": [ + │ "81085e6c-1d77-4916-84c5-e4574956e456" + │ ] + │ }, + │ "Result": { + │ "errors": [ + │ { + │ "code": "invalid_state", + │ "details": "Unable to process this request as Template with ID 'ProfileTemplate-8b16cb82-b9b4-434a-b678-12c82033e9a7' and version '1' is in a committed state.", + │ "message": "Template in committed state.", + │ "message_code": "BXNIM0908E" + │ } + │ ], + │ "status_code": 422, + │ "trace": "OXRxZ2M-8c573b755d4f4a28bb60756766ea1c64" + │ }, + │ "RawResult": null + │ } + │ + │ + │ with module.trusted_profile_template.ibm_iam_trusted_profile_template.trusted_profile_template_instance, + │ on .terraform/modules/trusted_profile_template/modules/trusted-profile-template/main.tf line 26, in resource "ibm_iam_trusted_profile_template" "trusted_profile_template_instance": + │ 26: resource "ibm_iam_trusted_profile_template" "trusted_profile_template_instance" { + ``` diff --git a/examples/enterprise/main.tf b/examples/enterprise/main.tf new file mode 100644 index 0000000..49a441e --- /dev/null +++ b/examples/enterprise/main.tf @@ -0,0 +1,216 @@ +######################################################################################################################## +# Resource group +######################################################################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + resource_group_name = var.resource_group == null ? "${var.prefix}-rg" : null + existing_resource_group_name = var.resource_group +} + +######################################################################################################################## +# SCC Workload Protection +######################################################################################################################## + +# Create SCC Workload Protection instance +module "scc_wp" { + source = "../.." + name = var.prefix + region = var.region + resource_group_id = module.resource_group.resource_group_id + resource_tags = var.resource_tags + access_tags = var.access_tags + scc_wp_service_plan = "graduated-tier" +} + +# Create Trusted profile for SCC Workload Protection instance +module "trusted_profile_scc_wp" { + source = "terraform-ibm-modules/trusted-profile/ibm" + version = "2.1.0" + trusted_profile_name = "${var.prefix}-scc-wp-profile" + trusted_profile_description = "Trusted Profile for SCC-WP to access App Config and enterprise" + + trusted_profile_identity = { + identifier = module.scc_wp.crn + identity_type = "crn" + type = "crn" + } + + trusted_profile_policies = [ + { + roles = ["Viewer", "Service Configuration Reader", "Manager"] + resources = [{ + service = "apprapp" + }] + description = "App Config access" + }, + { + roles = ["Viewer", "Usage Report Viewer"] + resources = [{ + service = "enterprise" + }] + description = "Enterprise access" + } + ] + + trusted_profile_links = [{ + cr_type = "VSI" + links = [{ + crn = module.scc_wp.crn + }] + }] +} + +######################################################################################################################## +# App Config +######################################################################################################################## + +# Create new App Config instance +module "app_config" { + source = "terraform-ibm-modules/app-configuration/ibm" + version = "1.3.0" + region = var.region + resource_group_id = module.resource_group.resource_group_id + app_config_name = "${var.prefix}-app-config" + app_config_tags = var.resource_tags +} + +# Create trusted profile for App Config instance +module "trusted_profile_app_config_general" { + source = "terraform-ibm-modules/trusted-profile/ibm" + version = "2.1.0" + trusted_profile_name = "${var.prefix}-app-config-general-profile" + trusted_profile_description = "Trusted Profile for App Config general permissions" + + trusted_profile_identity = { + identifier = module.app_config.app_config_crn + identity_type = "crn" + type = "crn" + } + + trusted_profile_policies = [ + { + roles = ["Viewer", "Service Configuration Reader"] + account_management = true + description = "All Account Management Services" + }, + { + roles = ["Viewer", "Service Configuration Reader", "Reader"] + resource_attributes = [{ + name = "serviceType" + value = "service" + operator = "stringEquals" + }] + description = "All Identity and Access enabled services" + } + ] + + trusted_profile_links = [{ + cr_type = "VSI" + links = [{ + crn = module.app_config.app_config_crn + }] + }] +} + +# Creates the custom role inline +# This role, "Template Assignment Reader", is used in the trusted profile +# to grant permission to read IAM template assignments. It is required +# by the App Config enterprise-level trusted profile to manage IAM templates. +resource "ibm_iam_custom_role" "template_assignment_reader" { + name = "TemplateAssignmentReader" + service = "iam-identity" + display_name = "Template Assignment Reader" + description = "Custom role to allow reading template assignments" + actions = ["iam-identity.profile-assignment.read"] +} + +# Trusted Profile for App Config enterprise-level permissions +module "trusted_profile_app_config_enterprise" { + source = "terraform-ibm-modules/trusted-profile/ibm" + version = "2.1.0" + trusted_profile_name = "app-config-enterprise-profile" + trusted_profile_description = "Trusted Profile for App Config to manage IAM templates" + + trusted_profile_identity = { + identifier = module.app_config.app_config_crn + identity_type = "crn" + type = "crn" + } + + trusted_profile_policies = [ + { + roles = ["Viewer", "Template Assignment Reader"] + resource_attributes = [{ + name = "service_group_id" + value = "IAM" + operator = "stringEquals" + }] + description = "IAM access with custom role" + }, + { + roles = ["Viewer"] + resources = [{ + service = "enterprise" + }] + description = "Enterprise access" + } + ] + + trusted_profile_links = [{ + cr_type = "VSI" + links = [{ + crn = module.app_config.app_config_crn + }] + }] +} + +# Enable the config aggregator +resource "ibm_config_aggregator_settings" "scc_wp_aggregator" { + instance_id = module.app_config.app_config_guid + region = var.region + resource_collection_enabled = true + resource_collection_regions = ["all"] + trusted_profile_id = module.trusted_profile_app_config_general.profile_id + + additional_scope { + type = "Enterprise" + enterprise_id = var.enterprise_id + + profile_template { + id = module.trusted_profile_template.trusted_profile_template_id + trusted_profile_id = module.trusted_profile_app_config_enterprise.profile_id + } + } +} + +######################################################################################################################## +# Trusted profile template +######################################################################################################################## + +module "trusted_profile_template" { + source = "terraform-ibm-modules/trusted-profile/ibm//modules/trusted-profile-template" + version = "2.1.0" + template_name = "Trusted Profile Template for SCC-WP-${var.prefix}" + template_description = "IAM trusted profile template to onboard accounts for CSPM" + profile_name = "Trusted Profile for IBM Cloud CSPM in SCC-WP" + profile_description = "Template profile used to onboard child accounts" + identity_crn = module.app_config.app_config_crn + onboard_all_account_groups = true + + policy_templates = [ + { + name = "identity-access" + description = "Policy template for identity services" + roles = ["Viewer", "Reader"] + service = "service" + }, + { + name = "platform-access" + description = "Policy template for platform services" + roles = ["Viewer", "Service Configuration Reader"] + service = "platform_service" + } + ] +} diff --git a/examples/enterprise/outputs.tf b/examples/enterprise/outputs.tf new file mode 100644 index 0000000..f1820fa --- /dev/null +++ b/examples/enterprise/outputs.tf @@ -0,0 +1,24 @@ +output "scc_wp_crn" { + description = "CRN of the SCC Workload Protection instance" + value = module.scc_wp.crn +} + +output "trusted_profile_template_id" { + description = "Trusted profile template ID" + value = module.trusted_profile_template.trusted_profile_template_id +} + +output "trusted_profile_enterprise_id" { + description = "Trusted profile enterprise ID" + value = module.trusted_profile_app_config_enterprise.profile_id +} + +output "app_config_guid" { + description = "App Config guid" + value = module.app_config.app_config_guid +} + +output "app_config_crn" { + description = "App Config CRN" + value = module.app_config.app_config_crn +} diff --git a/examples/enterprise/provider.tf b/examples/enterprise/provider.tf new file mode 100644 index 0000000..75b9612 --- /dev/null +++ b/examples/enterprise/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + region = var.region + ibmcloud_api_key = var.ibmcloud_api_key +} diff --git a/examples/enterprise/variables.tf b/examples/enterprise/variables.tf new file mode 100644 index 0000000..e4a077c --- /dev/null +++ b/examples/enterprise/variables.tf @@ -0,0 +1,39 @@ +variable "enterprise_id" { + type = string + description = "The Enterprise ID used to scope the Config Aggregator or IAM templates." +} + +variable "region" { + type = string + description = "IBM Cloud region where resources will be deployed." +} + +variable "prefix" { + type = string + description = "Prefix used for naming all provisioned resources." +} + +variable "resource_group" { + type = string + default = null + description = "Name of an existing resource group to use. If null, a new one will be created using the prefix." +} + +variable "resource_tags" { + type = list(string) + default = [] + description = "List of tags to apply to resources for tracking and organization." +} + +variable "access_tags" { + type = list(string) + default = [] + description = "List of access tags to apply to resources for IAM policy scoping." +} + + +variable "ibmcloud_api_key" { + type = string + description = "IBM Cloud API key used for authentication." + sensitive = true +} diff --git a/examples/enterprise/version.tf b/examples/enterprise/version.tf new file mode 100644 index 0000000..d7da690 --- /dev/null +++ b/examples/enterprise/version.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3.0" + + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.70.0, < 2.0.0" + } + } +}