From 11a64da824b23cd1e770d24862298ac276fdf227 Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Tue, 11 Mar 2025 19:19:03 +0000 Subject: [PATCH 01/11] temp --- ibm_catalog.json | 479 ++++++++++++++++++ solutions/fully-configurable/DA-cbr_rules.md | 54 ++ solutions/fully-configurable/README.md | 109 ++++ .../catalogValidationValues.json.template | 6 + .../fully-configurable/custom_integrations.md | 35 ++ solutions/fully-configurable/main.tf | 323 ++++++++++++ solutions/fully-configurable/outputs.tf | 57 +++ solutions/fully-configurable/provider.tf | 30 ++ .../fully-configurable/scopes_attachments.md | 102 ++++ solutions/fully-configurable/variables.tf | 389 ++++++++++++++ solutions/fully-configurable/version.tf | 14 + 11 files changed, 1598 insertions(+) create mode 100644 ibm_catalog.json create mode 100644 solutions/fully-configurable/DA-cbr_rules.md create mode 100644 solutions/fully-configurable/README.md create mode 100644 solutions/fully-configurable/catalogValidationValues.json.template create mode 100644 solutions/fully-configurable/custom_integrations.md create mode 100644 solutions/fully-configurable/main.tf create mode 100644 solutions/fully-configurable/outputs.tf create mode 100644 solutions/fully-configurable/provider.tf create mode 100644 solutions/fully-configurable/scopes_attachments.md create mode 100644 solutions/fully-configurable/variables.tf create mode 100644 solutions/fully-configurable/version.tf diff --git a/ibm_catalog.json b/ibm_catalog.json new file mode 100644 index 0000000..ad5b6d6 --- /dev/null +++ b/ibm_catalog.json @@ -0,0 +1,479 @@ +{ + "products": [ + { + "name": "deploy-arch-ibm-scc", + "label": "Cloud automation for Security and Compliance Center", + "product_kind": "solution", + "tags": [ + "ibm_created", + "target_terraform", + "terraform", + "solution", + "security" + ], + "keywords": [ + "SCC", + "security", + "compliance", + "workload-protection", + "IaC", + "infrastructure as code", + "terraform", + "solution" + ], + "short_description": "Creates and configures IBM Security and Compliance Center resources", + "long_description": "This architecture supports creating and configuring IBM Security and Compliance Center resources.", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/blob/main/solutions/instances/README.md", + "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc-da/main/images/scc-icon.svg", + "provider_name": "IBM", + "features": [ + { + "title": "Security and Compliance Center", + "description": "Creates and configures a Security and Compliance Center instance." + }, + { + "title": "Object Storage bucket for Security and Compliance Center", + "description": "Creates and configures a KMS-encrypted Object Storage bucket required for the Security and Compliance Center instance." + }, + { + "title": "Security and Compliance Center Workload Protection", + "description": "Creates and configures a Security and Compliance Center Workload Protection instance." + } + ], + "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues). Please note this product is not supported via the IBM Cloud Support Center.", + "flavors": [ + { + "label": "Fully configurable", + "name": "fully-configurable", + "install_type": "fullstack", + "working_directory": "solutions/fully-configurable", + "compliance": { + "authority": "scc-v3", + "profiles": [ + { + "profile_name": "IBM Cloud Framework for Financial Services", + "profile_version": "1.7.0" + } + ] + }, + "configuration": [ + { + "key": "ibmcloud_api_key" + }, + { + "key": "prefix", + "required": true, + "description": "Prefix to add to all resources that this solution creates. To not use any prefix value, you can enter the string `__NULL__`." + }, + { + "key": "existing_resource_group_name", + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } + }, + { + "key": "resource_group_name", + "required": true + }, + { + "key": "scc_region", + "required": true, + "options": [ + { + "displayname": "Dallas (us-south)", + "value": "us-south" + }, + { + "displayname": "Frankfurt (eu-de)", + "value": "eu-de" + }, + { + "displayname": "Madrid (eu-es)", + "value": "eu-es" + }, + { + "displayname": "Toronto (ca-tor)", + "value": "ca-tor" + } + ] + }, + { + "key": "existing_kms_instance_crn", + "required": true + }, + { + "key": "provider_visibility", + "options": [ + { + "displayname": "private", + "value": "private" + }, + { + "displayname": "public", + "value": "public" + }, + { + "displayname": "public-and-private", + "value": "public-and-private" + } + ] + }, + { + "key": "scc_instance_name" + }, + { + "key": "scc_instance_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_service_plan", + "options": [ + { + "displayname": "Standard", + "value": "security-compliance-center-standard-plan" + }, + { + "displayname": "Trial", + "value": "security-compliance-center-trial-plan" + } + ] + }, + { + "key": "existing_scc_instance_crn" + }, + { + "key": "cos_instance_name" + }, + { + "key": "cos_instance_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "cos_instance_access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_cos_bucket_name" + }, + { + "key": "scc_cos_bucket_region", + "options": [ + { + "displayname": "Same region as SCC instance", + "value": "__NULL__" + }, + { + "displayname": "Dallas (us-south)", + "value": "us-south" + }, + { + "displayname": "Sydney (au-syd)", + "value": "au-syd" + }, + { + "displayname": "Sao Paolo (br-sao)", + "value": "br-sao" + }, + { + "displayname": "Toronto (ca-tor)", + "value": "ca-tor" + }, + { + "displayname": "Frankfurt (eu-de)", + "value": "eu-de" + }, + { + "displayname": "London (eu-gb)", + "value": "eu-gb" + }, + { + "displayname": "Madrid (eu-es)", + "value": "eu-es" + }, + { + "displayname": "Osaka (jp-osa)", + "value": "jp-osa" + }, + { + "displayname": "Tokyo (jp-tok)", + "value": "jp-tok" + }, + { + "displayname": "Washington DC (us-east)", + "value": "us-east" + } + ] + }, + { + "key": "add_bucket_name_suffix" + }, + { + "key": "scc_cos_bucket_access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_cos_bucket_class", + "options": [ + { + "displayname": "Cold", + "value": "cold" + }, + { + "displayname": "Onerate active", + "value": "onerate_active" + }, + { + "displayname": "Smart", + "value": "smart" + }, + { + "displayname": "Standard", + "value": "standard" + }, + { + "displayname": "Vault", + "value": "vault" + } + ] + }, + { + "key": "existing_scc_cos_bucket_name" + }, + { + "key": "management_endpoint_type_for_bucket", + "options": [ + { + "displayname": "Direct", + "value": "direct" + }, + { + "displayname": "Private", + "value": "private" + }, + { + "displayname": "Public", + "value": "public" + } + ] + }, + { + "key": "existing_cos_instance_crn" + }, + { + "key": "existing_monitoring_crn" + }, + { + "key": "skip_scc_cos_iam_auth_policy" + }, + { + "key": "existing_scc_cos_kms_key_crn" + }, + { + "key": "ibmcloud_kms_api_key" + }, + { + "key": "kms_endpoint_type", + "options": [ + { + "displayname": "Public", + "value": "public" + }, + { + "displayname": "Private", + "value": "private" + } + ] + }, + { + "key": "skip_cos_kms_iam_auth_policy" + }, + { + "key": "scc_cos_key_ring_name" + }, + { + "key": "scc_cos_key_name" + }, + { + "key": "profile_attachments" + }, + { + "key": "resource_groups_scope" + }, + { + "key": "attachment_schedule", + "options": [ + { + "displayname": "Daily", + "value": "daily" + }, + { + "displayname": "Weekly", + "value": "every_7_days" + }, + { + "displayname": "Monthly", + "value": "every_30_days" + }, + { + "displayname": "Never", + "value": "none" + } + ] + }, + { + "key": "provision_scc_workload_protection" + }, + { + "key": "scc_workload_protection_instance_name" + }, + { + "key": "scc_workload_protection_service_plan", + "options": [ + { + "displayname": "Free trial", + "value": "free-trial" + }, + { + "displayname": "Graduated tier", + "value": "graduated-tier" + } + ] + }, + { + "key": "scc_workload_protection_instance_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_workload_protection_resource_key_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_workload_protection_access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "skip_scc_workload_protection_iam_auth_policy" + }, + { + "key": "existing_event_notifications_crn" + }, + { + "key": "event_notifications_source_name" + }, + { + "key": "event_notifications_source_description" + }, + { + "key": "scc_event_notifications_email_list" + }, + { + "key": "scc_event_notifications_from_email" + }, + { + "key": "scc_event_notifications_reply_to_email" + }, + { + "key": "scc_instance_cbr_rules" + } + ], + "iam_permissions": [ + { + "service_name": "compliance", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Editor" + ] + }, + { + "service_name": "cloud-object-storage", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager" + ] + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "kms" + } + ], + "architecture": { + "descriptions": "This architecture supports creating and configuring a Security and Compliance Center Workload Protection instance.", + "features": [ + { + "title": "Creates a Security and Compliance Center instance", + "description": "Creates and configures a Security and Compliance Center instance." + }, + { + "title": "Creates an Object Storage bucket", + "description": "Creates and configures a KMS-encrypted Object Storage bucket required for the Security and Compliance Center instance." + }, + { + "title": "Creates a Security and Compliance Center Workload Protection instance", + "description": "Creates and configures a Security and Compliance Center Workload Protection instance." + } + ], + "diagrams": [ + { + "diagram": { + "caption": "Security and Compliance Center", + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc-da/main/reference-architecture/scc.svg", + "type": "image/svg+xml" + }, + "description": "This architecture supports creating and configuring IBM Security and Compliance Center resources" + } + ] + } + } + ] + } + ] +} diff --git a/solutions/fully-configurable/DA-cbr_rules.md b/solutions/fully-configurable/DA-cbr_rules.md new file mode 100644 index 0000000..18456f2 --- /dev/null +++ b/solutions/fully-configurable/DA-cbr_rules.md @@ -0,0 +1,54 @@ +# Configuring Context-Based Restrictions (CBRs) + +The `scc_instance_cbr_rules` input variable allows you to provide a rule for the target service to enforce access restrictions for the service based on the context of access requests. Contexts are criteria that include the network location of access requests, the endpoint type from where the request is sent, etc. + +- Variable name: `scc_instance_cbr_rules`. +- Type: A list of objects. Allows only one object representing a rule for the target service +- Default value: An empty list (`[]`). + +### Options for scc_instance_cbr_rules + + - `description` (required): The description of the rule to create. + - `account_id` (required): The IBM Cloud Account ID + - `rule_contexts` (required): (List) The contexts the rule applies to + - `attributes` (optional): (List) Individual context attributes + - `name` (required): The attribute name. + - `value`(required): The attribute value. + + - `enforcement_mode` (required): The rule enforcement mode can have the following values: + - `enabled` - The restrictions are enforced and reported. This is the default. + - `disabled` - The restrictions are disabled. Nothing is enforced or reported. + - `report` - The restrictions are evaluated and reported, but not enforced. + - `operations` (optional): The operations this rule applies to + - `api_types`(required): (List) The API types this rule applies to. + - `api_type_id`(required): The API type ID + + +### Example Rule For Context-Based Restrictions Configuration + +```hcl +[ + { + "description" : "SCC Instance can be accessed from xyz" + "account_id" : "defc0df06b644a9cabc6e44f55b3880s." + "rule_contexts" : [{ + "attributes" : [ + { + "name" : "endpointType", + "value" : "private" + }, + { + "name" : "networkZoneId" + "value" : "93a51a1debe2674193217209601dde6f" + } + ] + }] + "enforcement_mode" : "enabled" + "operations" : [{ + "api_types" : [{ + "api_type_id" : "crn:v1:bluemix:public:context-based-restrictions::::api-type:" + }] + }] + } +] +``` diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md new file mode 100644 index 0000000..e397f03 --- /dev/null +++ b/solutions/fully-configurable/README.md @@ -0,0 +1,109 @@ +# Security and Compliance Center instances solution + +This solution supports provisioning and configuring the following infrastructure: + +- A resource group, if one is not passed in. +- A Security and Compliance Center instance. +- A Security and Compliance Center Workload Protection instance. +- An IBM Cloud Object Storage instance and KMS-encrypted bucket, which is required to store Security and Compliance Center data. +- Security and Compliance Center profile attachments configured for the instance created by this module. + +:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). + + + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.9.0 | +| [ibm](#requirement\_ibm) | 1.76.1 | +| [time](#requirement\_time) | 0.12.1 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [buckets](#module\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 8.19.8 | +| [existing\_cos\_crn\_parser](#module\_existing\_cos\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_en\_crn\_parser](#module\_existing\_en\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_kms\_crn\_parser](#module\_existing\_kms\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_kms\_key\_crn\_parser](#module\_existing\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_scc\_crn\_parser](#module\_existing\_scc\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 4.21.2 | +| [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.1.6 | +| [scc](#module\_scc) | terraform-ibm-modules/scc/ibm | 2.0.1 | +| [scc\_attachment](#module\_scc\_attachment) | terraform-ibm-modules/scc/ibm//modules/attachment | 2.0.1 | + +### Resources + +| Name | Type | +|------|------| +| [ibm_en_subscription_email.email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/en_subscription_email) | resource | +| [ibm_en_topic.en_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/en_topic) | resource | +| [ibm_iam_authorization_policy.cos_kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/iam_authorization_policy) | resource | +| [ibm_scc_scope.scc_scopes](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/scc_scope) | resource | +| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | +| [time_sleep.wait_for_scc](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | +| [ibm_en_destinations.en_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/data-sources/en_destinations) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [add\_bucket\_name\_suffix](#input\_add\_bucket\_name\_suffix) | Whether to add a generated 4-character suffix to the created Security and Compliance Center Object Storage bucket name. Applies only if not specifying an existing bucket. Set to `false` not to add the suffix to the bucket name in the `scc_cos_bucket_name` variable. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `true` | no | +| [attachments](#input\_attachments) | A list of attachments to create. A value must be passed for 'scope\_ids' (to use pre-existing scopes) and/or 'scope\_key\_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
list(object({
profile_name = string
profile_version = string
attachment_name = string
attachment_description = string
attachment_schedule = string
scope_key_references = optional(list(string), [])
scope_ids = optional(list(string), [])
notifications = object({
enabled = optional(bool, true)
failed_control_ids = optional(list(string), [])
threshold_limit = optional(number, 10)
})
}))
| `[]` | no | +| [custom\_integrations](#input\_custom\_integrations) | A list of custom provider integrations to associate with the Security and Compliance Center instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/custom_integrations.md). |
list(object({
attributes = optional(map(string), {})
provider_name = string
integration_name = string
}))
| `[]` | no | +| [event\_notifications\_source\_description](#input\_event\_notifications\_source\_description) | Optional description to give for the Event Notifications integration source. Only used if a value is passed for `event_notifications_instance_crn`. | `string` | `null` | no | +| [event\_notifications\_source\_name](#input\_event\_notifications\_source\_name) | The source name to use for the Event Notifications integration. Required if a value is passed for `event_notifications_instance_crn`. This name must be unique per SCC instance that is integrated with the Event Notifications instance. | `string` | `"compliance"` | no | +| [existing\_cos\_instance\_crn](#input\_existing\_cos\_instance\_crn) | The CRN of an existing Object Storage instance. Not required if passing an existing SCC instance using the `existing_scc_instance_crn` input. | `string` | `null` | no | +| [existing\_event\_notifications\_crn](#input\_existing\_event\_notifications\_crn) | The CRN of an Event Notification instance. Used to integrate with Security and Compliance Center. | `string` | `null` | no | +| [existing\_kms\_instance\_crn](#input\_existing\_kms\_instance\_crn) | The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). Used to create a new KMS key unless an existing key is passed using the `existing_scc_cos_kms_key_crn` input. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. A value should not be passed passing existing SCC instance using the `existing_scc_instance_crn` input. | `string` | `null` | no | +| [existing\_kms\_key\_crn](#input\_existing\_kms\_key\_crn) | The CRN of an existing KMS key to use to encrypt the Security and Compliance Center Object Storage bucket. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key, or for the `existing_scc_cos_bucket_name` variable to use an existing bucket. | `string` | `null` | no | +| [existing\_monitoring\_crn](#input\_existing\_monitoring\_crn) | The CRN of an IBM Cloud Monitoring instance to to send Security and Compliance Object Storage bucket metrics to. If no value passed, metrics are sent to the instance associated to the container's location unless otherwise specified in the Metrics Router service configuration. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `null` | no | +| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision resource in. | `string` | n/a | yes | +| [existing\_scc\_instance\_crn](#input\_existing\_scc\_instance\_crn) | The CRN of an existing Security and Compliance Center instance. If not supplied, a new instance will be created. | `string` | `null` | no | +| [existing\_scc\_workload\_protection\_instance\_crn](#input\_existing\_scc\_workload\_protection\_instance\_crn) | The CRN of an existing Workload Protection instance to associate with the Security and Compliance Center instance. | `string` | `null` | no | +| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key used to provision resources. | `string` | n/a | yes | +| [ibmcloud\_kms\_api\_key](#input\_ibmcloud\_kms\_api\_key) | The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud\_api\_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Security and Compliance Centre instance. Leave this input empty if the same account owns both instances. | `string` | `null` | no | +| [kms\_encryption\_enabled\_bucket](#input\_kms\_encryption\_enabled\_bucket) | Set to true to enable KMS encryption on the Object Storage bucket created for the Security and Compliance Center instance. When set to true, a value must be passed for either `existing_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_scc_instance_crn`. | `bool` | `false` | no | +| [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_bucket` is true | `string` | `"private"` | no | +| [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"direct"` | no | +| [prefix](#input\_prefix) | The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes | +| [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints). | `string` | `"private"` | no | +| [scc\_cos\_bucket\_access\_tags](#input\_scc\_cos\_bucket\_access\_tags) | The list of access tags to add to the Security and Compliance Center Object Storage bucket. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | +| [scc\_cos\_bucket\_class](#input\_scc\_cos\_bucket\_class) | The storage class of the newly provisioned Security and Compliance Center Object Storage bucket. Possible values: `standard`, `vault`, `cold`, `smart`, `onerate_active`. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes). Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"smart"` | no | +| [scc\_cos\_bucket\_name](#input\_scc\_cos\_bucket\_name) | The name for the Security and Compliance Center Object Storage bucket. Bucket names must globally unique. If `add_bucket_name_suffix` is true, a 4-character string is added to this name to ensure it's globally unique. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"scc-cos-bucket"` | no | +| [scc\_cos\_bucket\_region](#input\_scc\_cos\_bucket\_region) | The region to create the Object Storage bucket used by SCC. If not provided, the region specified in the `scc_region` input will be used. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `null` | no | +| [scc\_cos\_key\_name](#input\_scc\_cos\_key\_name) | The name for the key created for the Security and Compliance Center Object Storage bucket. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"scc-cos-key"` | no | +| [scc\_cos\_key\_ring\_name](#input\_scc\_cos\_key\_ring\_name) | The name for the key ring created for the Security and Compliance Center Object Storage bucket key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"scc-cos-key-ring"` | no | +| [scc\_event\_notifications\_email\_list](#input\_scc\_event\_notifications\_email\_list) | The list of email addresses to notify when Security and Compliance Center triggers an event. | `list(string)` | `[]` | no | +| [scc\_event\_notifications\_from\_email](#input\_scc\_event\_notifications\_from\_email) | The `from` email address used in any Security and Compliance Center events coming via Event Notifications. | `string` | `"compliancealert@ibm.com"` | no | +| [scc\_event\_notifications\_reply\_to\_email](#input\_scc\_event\_notifications\_reply\_to\_email) | The `reply_to` email address used in any Security and Compliance Center events coming via Event Notifications. | `string` | `"no-reply@ibm.com"` | no | +| [scc\_instance\_access\_tags](#input\_scc\_instance\_access\_tags) | The list of access tags to add to the Security and Compliance Center instance. | `list(string)` | `[]` | no | +| [scc\_instance\_cbr\_rules](#input\_scc\_instance\_cbr\_rules) | (Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/DA-cbr_rules.md). |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [scc\_instance\_name](#input\_scc\_instance\_name) | The name for the Security and Compliance Center instance provisioned by this solution. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"scc"` | no | +| [scc\_instance\_resource\_tags](#input\_scc\_instance\_resource\_tags) | The list of tags to add to the Security and Compliance Center instance. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | +| [scc\_region](#input\_scc\_region) | The region to provision Security and Compliance Center resources in. If passing a value for `existing_scc_instance_crn`, ensure to select the region of the existing instance. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"us-south"` | no | +| [scc\_service\_plan](#input\_scc\_service\_plan) | The pricing plan to use when creating a new Security Compliance Center instance. Possible values: `security-compliance-center-standard-plan`, `security-compliance-center-trial-plan`. | `string` | `"security-compliance-center-standard-plan"` | no | +| [scopes](#input\_scopes) | A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope\_key\_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
map(object({
name = string
description = string
environment = optional(string, "ibm-cloud")
properties = object({
scope_id = string
scope_type = string
})
exclusions = optional(list(object({
scope_id = string
scope_type = string
})))
}))
| `{}` | no | +| [skip\_cos\_kms\_iam\_auth\_policy](#input\_skip\_cos\_kms\_iam\_auth\_policy) | Set to `true` to skip the creation of an IAM authorization policy that permits the Object Storage instance created to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `false` | no | +| [skip\_scc\_cos\_iam\_auth\_policy](#input\_skip\_scc\_cos\_iam\_auth\_policy) | Set to `true` to skip creation of an IAM authorization policy that permits the Security and Compliance Center to write to the Object Storage instance created by this solution. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `false` | no | +| [skip\_scc\_workload\_protection\_iam\_auth\_policy](#input\_skip\_scc\_workload\_protection\_iam\_auth\_policy) | Set to `true` to skip creating an IAM authorization policy that permits the Security and Compliance Center instance to read from the Workload Protection instance. Applies only if a value is passed for `existing_scc_workload_protection_instance_crn`. | `bool` | `false` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [resource\_group\_id](#output\_resource\_group\_id) | Resource group ID | +| [resource\_group\_name](#output\_resource\_group\_name) | Resource group name | +| [scc\_cos\_bucket\_config](#output\_scc\_cos\_bucket\_config) | List of buckets created | +| [scc\_cos\_bucket\_name](#output\_scc\_cos\_bucket\_name) | SCC COS bucket name | +| [scc\_cos\_instance\_crn](#output\_scc\_cos\_instance\_crn) | SCC COS instance CRN | +| [scc\_cos\_kms\_key\_crn](#output\_scc\_cos\_kms\_key\_crn) | SCC COS KMS Key CRN | +| [scc\_crn](#output\_scc\_crn) | SCC instance CRN | +| [scc\_guid](#output\_scc\_guid) | SCC instance guid | +| [scc\_id](#output\_scc\_id) | SCC instance ID | +| [scc\_name](#output\_scc\_name) | SCC instance name | + diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template new file mode 100644 index 0000000..bf6e9d9 --- /dev/null +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -0,0 +1,6 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "prefix": $PREFIX, + "existing_resource_group_name": "geretain-test-resources", + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN +} diff --git a/solutions/fully-configurable/custom_integrations.md b/solutions/fully-configurable/custom_integrations.md new file mode 100644 index 0000000..aa4e79e --- /dev/null +++ b/solutions/fully-configurable/custom_integrations.md @@ -0,0 +1,35 @@ +# Configuring custom integrations + +Custom provider integrations can be configured for the Security and Compliance Center instance using the `custom_integrations` input. + +:information_source: If you wan't to integrate with an SCC Workload Protection instance, simply use the `existing_scc_workload_protection_instance_crn` input instead. + +## Options for custom_integrations +The `custom_integrations` input a list type input which supporting configuring multiple integrations. Each entry in the list is a map object with the following options: + +- `attributes` (optional, default = `{}`): an optional map of string attributes +- `provider_name` (required): The unique provider name +- `integration_name` (required): The name to give the integration + +- The following example shows how to create an integration with the Caveonix provider: + + ``` + [ + { + provider_name = "Caveonix" + integration_name = "caveonix-integration" + } + ] + ``` + +- The following example shows how to create an integration with a provider that requires attributes: + + ``` + [ + { + provider_name = "Sample" + integration_name = "sample-integration" + attributes = {"description": "this is a sample"} + } + ] + ``` diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf new file mode 100644 index 0000000..b02cc05 --- /dev/null +++ b/solutions/fully-configurable/main.tf @@ -0,0 +1,323 @@ +###################################################################################################################### +# Resource Group +###################################################################################################################### + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + existing_resource_group_name = var.existing_resource_group_name +} + +####################################################################################################################### +# KMS Key +####################################################################################################################### + +module "existing_kms_crn_parser" { + count = var.existing_kms_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_kms_instance_crn +} + +module "existing_kms_key_crn_parser" { + count = var.kms_encryption_enabled_bucket ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_kms_key_crn != null ? var.existing_kms_key_crn : module.kms[0].keys[format("%s.%s", local.scc_cos_key_ring_name, local.scc_cos_key_name)].crn +} + +locals { + prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null + kms_region = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].region : null : null + existing_kms_guid = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_instance : null : null + kms_service_name = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_name : null : null + kms_account_id = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].account_id : null : null + kms_key_id = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket && length(module.existing_kms_key_crn_parser) > 0 ? module.existing_kms_key_crn_parser[0].resource : null + scc_cos_key_ring_name = try("${local.prefix}-${var.scc_cos_key_ring_name}", var.scc_cos_key_ring_name) + scc_cos_key_name = try("${local.prefix}-${var.scc_cos_key_name}", var.scc_cos_key_name) + scc_cos_bucket_region = var.scc_cos_bucket_region != null && var.scc_cos_bucket_region != "" ? var.scc_cos_bucket_region : var.scc_region + scc_instance_name = try("${local.prefix}-${var.scc_instance_name}", var.scc_instance_name) + # Bucket name to be passed to the COS module to create a bucket + created_scc_cos_bucket_name = try("${local.prefix}-${var.scc_cos_bucket_name}", var.scc_cos_bucket_name) + # Final COS bucket name after being created by COS module (as it might have suffix added to it) + scc_cos_bucket_name = module.buckets[0].buckets[local.created_scc_cos_bucket_name].bucket_name + create_cross_account_auth_policy = var.existing_scc_instance_crn == null ? !var.skip_cos_kms_iam_auth_policy && var.ibmcloud_kms_api_key == null ? false : (module.scc.account_id != module.existing_kms_crn_parser[0].account_id) : false +} + +# Create IAM Authorization Policy to allow COS to access KMS for the encryption key, if cross account KMS is passed in +resource "ibm_iam_authorization_policy" "cos_kms_policy" { + count = local.create_cross_account_auth_policy ? 1 : 0 + provider = ibm.kms + source_service_account = module.scc.account_id + source_service_name = "cloud-object-storage" + source_resource_instance_id = local.cos_instance_guid + roles = ["Reader"] + description = "Allow the COS instance ${local.cos_instance_guid} to read the ${local.kms_service_name} key ${local.kms_key_id} from the instance ${local.existing_kms_guid}" + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = local.kms_service_name + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = local.kms_account_id + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = local.existing_kms_guid + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "key" + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = local.kms_key_id + } + # Scope of policy now includes the key, so ensure to create new policy before + # destroying old one to prevent any disruption to every day services. + lifecycle { + create_before_destroy = true + } +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_authorization_policy" { + depends_on = [ibm_iam_authorization_policy.cos_kms_policy] + count = local.create_cross_account_auth_policy ? 1 : 0 + + create_duration = "30s" +} + +# KMS root key for SCC COS bucket +module "kms" { + providers = { + ibm = ibm.kms + } + count = var.kms_encryption_enabled_bucket && var.existing_kms_key_crn == null ? 1 : 0 + source = "terraform-ibm-modules/kms-all-inclusive/ibm" + version = "4.21.2" + create_key_protect_instance = false + region = local.kms_region + existing_kms_instance_crn = var.existing_kms_instance_crn + key_ring_endpoint_type = var.kms_endpoint_type + key_endpoint_type = var.kms_endpoint_type + keys = [ + { + key_ring_name = local.scc_cos_key_ring_name + existing_key_ring = false + keys = [ + { + key_name = local.scc_cos_key_name + standard_key = false + rotation_interval_month = 3 + dual_auth_delete_enabled = false + force_delete = false # TBC + } + ] + } + ] +} + +####################################################################################################################### +# COS +####################################################################################################################### + +module "existing_cos_crn_parser" { + count = var.existing_cos_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_cos_instance_crn +} + +locals { + scc_cos_kms_key_crn = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_key_crn != null ? var.existing_kms_key_crn : module.kms[0].keys[format("%s.%s", local.scc_cos_key_ring_name, local.scc_cos_key_name)].crn : null + cos_instance_guid = var.existing_scc_instance_crn == null ? var.existing_cos_instance_crn != null ? module.existing_cos_crn_parser[0].service_instance : null : null + bucket_config = [{ + access_tags = var.scc_cos_bucket_access_tags + add_bucket_name_suffix = var.add_bucket_name_suffix + bucket_name = local.created_scc_cos_bucket_name + kms_encryption_enabled = var.kms_encryption_enabled_bucket + kms_guid = local.existing_kms_guid + kms_key_crn = local.scc_cos_kms_key_crn + skip_iam_authorization_policy = local.create_cross_account_auth_policy || var.skip_cos_kms_iam_auth_policy + management_endpoint_type = var.management_endpoint_type_for_bucket + storage_class = var.scc_cos_bucket_class + resource_instance_id = var.existing_cos_instance_crn + region_location = local.scc_cos_bucket_region + force_delete = false # TBC + activity_tracking = { + read_data_events = true + write_data_events = true + management_events = true + } + metrics_monitoring = { + usage_metrics_enabled = true + request_metrics_enabled = true + metrics_monitoring_crn = var.existing_monitoring_crn + } + }] +} + +# Create bucket +module "buckets" { + providers = { + ibm = ibm.cos + } + count = var.existing_scc_instance_crn == null ? 1 : 0 + depends_on = [time_sleep.wait_for_authorization_policy[0]] + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "8.19.8" + bucket_configs = local.bucket_config +} + +####################################################################################################################### +# SCC Instance +####################################################################################################################### + +module "existing_scc_crn_parser" { + count = var.existing_scc_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_scc_instance_crn +} + +locals { + scc_instance_region = var.existing_scc_instance_crn == null ? var.scc_region : module.existing_scc_crn_parser[0].region +} + +module "scc" { + source = "terraform-ibm-modules/scc/ibm" + existing_scc_instance_crn = var.existing_scc_instance_crn + version = "2.0.1" + resource_group_id = module.resource_group.resource_group_id + region = var.scc_region + instance_name = local.scc_instance_name + plan = var.scc_service_plan + cos_bucket = local.scc_cos_bucket_name + cos_instance_crn = var.existing_cos_instance_crn + enable_event_notifications_integration = var.existing_event_notifications_crn == null ? false : true + en_instance_crn = var.existing_event_notifications_crn + en_source_name = var.event_notifications_source_name + en_source_description = var.event_notifications_source_description + skip_cos_iam_authorization_policy = var.skip_scc_cos_iam_auth_policy + resource_tags = var.scc_instance_resource_tags + attach_wp_to_scc_instance = var.existing_scc_workload_protection_instance_crn != null ? true : false + wp_instance_crn = var.existing_scc_workload_protection_instance_crn + skip_scc_wp_auth_policy = var.skip_scc_workload_protection_iam_auth_policy + cbr_rules = var.scc_instance_cbr_rules + custom_integrations = var.custom_integrations + access_tags = var.scc_instance_access_tags +} + +####################################################################################################################### +# SCC scopes +####################################################################################################################### + +resource "ibm_scc_scope" "scc_scopes" { + for_each = var.scopes + description = each.value.description + environment = each.value.environment + instance_id = module.scc.guid + name = each.value.name + properties = each.value.properties + + dynamic "exclusions" { + for_each = each.value.exclusions + content { + scope_id = exclusions.value.scope_id + scope_type = exclusions.value.scope_type + } + } +} + +####################################################################################################################### +# SCC attachments +####################################################################################################################### + +module "scc_attachment" { + + for_each = { + for index, attachment in var.attachments: + attachment.attachment_name => attachment + } + + source = "terraform-ibm-modules/scc/ibm//modules/attachment" + version = "2.0.1" + profile_name = each.value.profile_name + profile_version = each.value.profile_version + scc_instance_id = module.scc.guid + attachment_name = each.value.attachment_name + attachment_description = each.value.attachment_description + attachment_schedule = each.value.attachment_schedule + # lookup the scope ID created using 'scope_key_references' value + # concat the 'scope_key_references' computed IDs with the IDs listed in the 'scope_ids' attribute + scope_ids = concat([for s in each.value.scope_key_references : ibm_scc_scope.scc_scopes[s].id], each.value.scope_ids) +} + +####################################################################################################################### +# SCC Event Notifications Configuration +####################################################################################################################### + +module "existing_en_crn_parser" { + count = var.existing_event_notifications_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_event_notifications_crn +} + +locals { + existing_en_guid = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].service_instance : null + existing_en_region = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].region : null +} + +data "ibm_en_destinations" "en_destinations" { + provider = ibm.en + count = var.existing_event_notifications_crn != null ? 1 : 0 + instance_guid = local.existing_en_guid +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5533. +resource "time_sleep" "wait_for_scc" { + count = var.existing_event_notifications_crn != null && var.existing_scc_instance_crn == null ? 1 : 0 + depends_on = [module.scc] + + create_duration = "60s" +} + +resource "ibm_en_topic" "en_topic" { + provider = ibm.en + count = var.existing_event_notifications_crn != null && var.existing_scc_instance_crn == null ? 1 : 0 + depends_on = [time_sleep.wait_for_scc] + instance_guid = local.existing_en_guid + name = "Topic for SCC instance ${module.scc.guid}" + description = "Topic for SCC events routing" + sources { + id = module.scc.crn + rules { + enabled = true + event_type_filter = "$.*" + } + } +} + +resource "ibm_en_subscription_email" "email_subscription" { + provider = ibm.en + count = var.existing_event_notifications_crn != null && var.existing_scc_instance_crn == null && length(var.scc_event_notifications_email_list) > 0 ? 1 : 0 + instance_guid = local.existing_en_guid + name = "Subscription email for SCC instance ${module.scc.guid}" + description = "Subscription for Security and Compliance Center Events" + destination_id = [for s in toset(data.ibm_en_destinations.en_destinations[count.index].destinations) : s.id if s.type == "smtp_ibm"][0] + topic_id = ibm_en_topic.en_topic[count.index].topic_id + attributes { + add_notification_payload = true + reply_to_mail = var.scc_event_notifications_reply_to_email + reply_to_name = "SCC Event Notifications Bot" + from_name = var.scc_event_notifications_from_email + invited = var.scc_event_notifications_email_list + } +} diff --git a/solutions/fully-configurable/outputs.tf b/solutions/fully-configurable/outputs.tf new file mode 100644 index 0000000..20c5316 --- /dev/null +++ b/solutions/fully-configurable/outputs.tf @@ -0,0 +1,57 @@ +######################################################################################################################## +# Outputs +######################################################################################################################## + +output "resource_group_name" { + description = "Resource group name" + value = module.resource_group.resource_group_name +} + +output "resource_group_id" { + description = "Resource group ID" + value = module.resource_group.resource_group_id +} + +output "scc_id" { + description = "SCC instance ID" + value = module.scc.id +} + +output "scc_guid" { + description = "SCC instance guid" + value = module.scc.guid +} + +output "scc_crn" { + description = "SCC instance CRN" + value = module.scc.crn +} + +output "scc_name" { + description = "SCC instance name" + value = module.scc.name +} + +######################################################################################################################## +# SCC COS +######################################################################################################################## + +output "scc_cos_kms_key_crn" { + description = "SCC COS KMS Key CRN" + value = local.scc_cos_kms_key_crn +} + +output "scc_cos_bucket_name" { + description = "SCC COS bucket name" + value = var.existing_scc_instance_crn == null ? local.scc_cos_bucket_name : null +} + +output "scc_cos_bucket_config" { + description = "List of buckets created" + value = var.existing_scc_instance_crn == null ? module.buckets[0].buckets[local.created_scc_cos_bucket_name] : null +} + +output "scc_cos_instance_crn" { + description = "SCC COS instance CRN" + value = var.existing_cos_instance_crn +} diff --git a/solutions/fully-configurable/provider.tf b/solutions/fully-configurable/provider.tf new file mode 100644 index 0000000..9438293 --- /dev/null +++ b/solutions/fully-configurable/provider.tf @@ -0,0 +1,30 @@ +######################################################################################################################## +# Provider config +######################################################################################################################## + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = local.scc_instance_region + visibility = var.provider_visibility +} + +provider "ibm" { + alias = "kms" + ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key + region = local.kms_region + visibility = var.provider_visibility +} + +provider "ibm" { + alias = "cos" + ibmcloud_api_key = var.ibmcloud_api_key + region = local.scc_cos_bucket_region + visibility = var.provider_visibility +} + +provider "ibm" { + alias = "en" + ibmcloud_api_key = var.ibmcloud_api_key + region = local.existing_en_region + visibility = var.provider_visibility +} diff --git a/solutions/fully-configurable/scopes_attachments.md b/solutions/fully-configurable/scopes_attachments.md new file mode 100644 index 0000000..d0b5da3 --- /dev/null +++ b/solutions/fully-configurable/scopes_attachments.md @@ -0,0 +1,102 @@ +# Creating Scopes and Attachments + +It is possible to create multiple scopes and multiple attachments in a Security and Compliance Centre instance using the `scopes` and `attachments` inputs. + +## Scopes +The `scopes` input can be used to create multiple scopes, which can then be used in 1 or more attachments. The input is an object map type, and each scope must be created using a map key identifier with the following attributes: + +- `name` (required): The name of the scope +- `description` (required): The description of the scope +- `environment` (optional, default = "ibm-cloud"): The scope environment +- `properties` (required): A map of properties containing: + - `scope_type` (required): The type of target the scope will cover. Acceptable values are: `account`, `account.resource_group`, `enterprise.account_group`, `enterprise` + - `scope_id` (required): The ID of the target defined in `scope_type` +- `exclusions` (optional): A list exclusions in the format of a map of strings containing: + - `scope_type` (required): The type of target the exclusion will cover. Acceptable values are: `account`, `account.resource_group`, `enterprise.account_group`, `enterprise` + - `scope_id` (required): The ID of the exclusion target defined in `scope_type` + +- The following example shows how to create a scope for the full account: + ``` + { + full-account = { + name = "Full account" + description = "Scope to scan the whole account" + environment = "ibm-cloud" + properties = { + scope_id = "abac0df06b644a9cabc6e44f55b3880e" + scope_type = "account" + } + } + } + ``` + - The key identifier for above example is `full-account`. This can be referenced when creating attachments using the `scope_key_references` attribute of the [attachments](#attachments) input. + +- The following example shows how to exclude a resource group from the scope: + ``` + { + exclude-group = { + name = "Exclude Default resource group" + description = "Scope to exclude the Default resource group" + environment = "ibm-cloud" + properties = { + scope_id = "abac0df06b644a9cabc6e44f55b3880e" + scope_type = "account" + } + exclusions = [{ + scope_id = "07b6d899988a4631841e3bc7d0307dcf" + scope_type = "account.resource_group" + }] + } + } + ``` + - The key identifier for above example is `exclude-group`. This can be referenced when creating attachments using the `scope_key_references` attribute of the [attachments](#attachments) input. + +## Attachments +The `attachments` input can be used to create multiple attachments using either pre-existing scopes, or scopes that were created with the [scopes](#scopes) input. The input type is a list of objects with the following attributes: + +- `profile_name` (required): The name of an existing profile to use for the attachments creation. +- `profile_version` (required): The version to use of the profile specified in `profile_name`. Supports the string `latest` to use the latest version. +- `attachment_name` (required): The name to give the attachment. +- `attachment_description` (required): The description of the attachment. +- `attachment_schedule` (required): The attachment schedule. Acceptable values are: `daily`, `every_7_days`, `every_30_days`, `none`. +- `scope_key_references` (optional): A list of key identifier strings for scopes that were created using the [attachments](#attachments) input that you want to include in the attachment. To use a pre-existing scope, you can use the `scope_ids` option below. Both inputs cannot be an empty list. +- `scope_ids` (optional): A list of pre-existing scope IDs to include in the attachment. To use a scope that was created with the `scopes input variable, use the `scope_key_references` option above. Both inputs cannot be an empty list. +- `notifications` (optional): A map of notification settings containing: + - `enabled` (optional, default: `true`): true of false to enable or disable notifications + - `failed_control_ids` (optional, default: `[]`): A list of failed control IDs to be notified of + - `threshold_limit` (optional, default: `10`): The threshold limit + +- The following example shows how to create an attachment with a daily schedule using a scope that was created with the first `scopes` example above: + ``` + [{ + profile_name = "SOC 2" + profile_version = "latest" + attachment_name = "SOC 2 full account" + attachment_description = "SOC 2 full account" + attachment_schedule = "daily" + scope_key_references = ["full-account"] + notifications = { + enabled = true + failed_control_ids = ["c51c5094-6f6b-4fee-b0f6-ad51ca68e18a"] + threshold_limit = 10 + } + }] + ``` + +- The following example shows how to create an attachment with a 30 day schedule using a scope IDs that already exist: + ``` + [{ + profile_name = "SOC 2" + profile_version = "latest" + attachment_name = "SOC 2" + attachment_description = "SOC 2" + attachment_schedule = "every_30_days" + scope_ids = ["e59990c6-ddec-49b7-9656-0dcfcdcaa6cf", "e8be9035-6c43-4035-b8a3-37ef63786e5c"] + notifications = { + enabled = true + failed_control_ids = ["c51c5094-6f6b-4fee-b0f6-ad51ca68e18a"] + threshold_limit = 10 + } + }] + ``` + \ No newline at end of file diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf new file mode 100644 index 0000000..c4ccee4 --- /dev/null +++ b/solutions/fully-configurable/variables.tf @@ -0,0 +1,389 @@ +######################################################################################################################## +# Common variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API key used to provision resources." + sensitive = true +} + +variable "existing_resource_group_name" { + type = string + description = "The name of an existing resource group to provision resource in." +} + +variable "prefix" { + type = string + description = "The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To not use any prefix value, you can set this value to `null` or an empty string." + nullable = true + validation { + condition = (var.prefix == null ? true : + alltrue([ + can(regex("^[a-z]{0,1}[-a-z0-9]{0,14}[a-z0-9]{0,1}$", var.prefix)), + length(regexall("^.*--.*", var.prefix)) == 0 + ]) + ) + error_message = "Prefix must begin with a lowercase letter, contain only lowercase letters, numbers, and - characters. Prefixes must end with a lowercase letter or number and be 16 or fewer characters." + } +} + +variable "provider_visibility" { + description = "Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints)." + type = string + default = "private" + + validation { + condition = contains(["public", "private", "public-and-private"], var.provider_visibility) + error_message = "Invalid value for 'provider_visibility'. Allowed values are 'public', 'private', or 'public-and-private'." + } +} + +######################################################################################################################## +# SCC variables +######################################################################################################################## + +variable "scc_instance_name" { + type = string + default = "scc" + description = "The name for the Security and Compliance Center instance provisioned by this solution. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_region" { + type = string + default = "us-south" + description = "The region to provision Security and Compliance Center resources in. If passing a value for `existing_scc_instance_crn`, ensure to select the region of the existing instance. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_service_plan" { + type = string + description = "The pricing plan to use when creating a new Security Compliance Center instance. Possible values: `security-compliance-center-standard-plan`, `security-compliance-center-trial-plan`." + default = "security-compliance-center-standard-plan" + validation { + condition = contains(["security-compliance-center-standard-plan", "security-compliance-center-trial-plan"], var.scc_service_plan) + error_message = "Allowed values for scc_service_plan are \"security-compliance-center-standard-plan\" and \"security-compliance-center-trial-plan\"." + } +} + +variable "scc_instance_resource_tags" { + type = list(string) + description = "The list of tags to add to the Security and Compliance Center instance. Applies only if `existing_scc_instance_crn` is not provided." + default = [] +} + +variable "scc_instance_access_tags" { + type = list(string) + description = "The list of access tags to add to the Security and Compliance Center instance." + default = [] +} + +variable "existing_scc_instance_crn" { + type = string + default = null + description = "The CRN of an existing Security and Compliance Center instance. If not supplied, a new instance will be created." +} + +variable "custom_integrations" { + type = list(object({ + attributes = optional(map(string), {}) + provider_name = string + integration_name = string + })) + description = "A list of custom provider integrations to associate with the Security and Compliance Center instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/custom_integrations.md)." + default = [] + # Since this list is used in a for_each, add nullable = false to prevent error if user passes null + nullable = false +} + +variable "scopes" { + type = map(object({ + name = string + description = string + environment = optional(string, "ibm-cloud") + properties = object({ + scope_id = string + scope_type = string + }) + exclusions = optional(list(object({ + scope_id = string + scope_type = string + }))) + })) + default = {} + nullable = false + description = "A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope_key_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md)." +} + +variable "attachments" { + type = list(object({ + profile_name = string + profile_version = string + attachment_name = string + attachment_description = string + attachment_schedule = string + scope_key_references = optional(list(string), []) + scope_ids = optional(list(string), []) + notifications = object({ + enabled = optional(bool, true) + failed_control_ids = optional(list(string), []) + threshold_limit = optional(number, 10) + }) + })) + default = [] + description = "A list of attachments to create. A value must be passed for 'scope_ids' (to use pre-existing scopes) and/or 'scope_key_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md)." + + validation { + condition = alltrue([for attachments in var.attachments : + length(attachments.scope_ids) > 0 || length(attachments.scope_key_references) > 40 + ]) + error_message = "At least one value needs to be added to the 'scope_ids' or 'scope_key_references' list inputs." + } + # TODO: Add validation to validate values in scope_key_references match the key identifier in the keys(var.scopes) +} + +######################################################################################################################## +# Workload Protection +######################################################################################################################## + +variable "existing_scc_workload_protection_instance_crn" { + type = string + description = "The CRN of an existing Workload Protection instance to associate with the Security and Compliance Center instance." + default = null +} + +variable "skip_scc_workload_protection_iam_auth_policy" { + type = bool + default = false + description = "Set to `true` to skip creating an IAM authorization policy that permits the Security and Compliance Center instance to read from the Workload Protection instance. Applies only if a value is passed for `existing_scc_workload_protection_instance_crn`." +} + +######################################################################################################################## +# KMS variables +######################################################################################################################## + +variable "kms_encryption_enabled_bucket" { + description = "Set to true to enable KMS encryption on the Object Storage bucket created for the Security and Compliance Center instance. When set to true, a value must be passed for either `existing_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_scc_instance_crn`." + type = bool + default = false + + validation { + condition = var.kms_encryption_enabled_bucket ? var.existing_scc_instance_crn == null : true + error_message = "'kms_encryption_enabled_bucket' should be false if passing a value for 'existing_scc_instance_crn' as existing SCC instance will already have a bucket attached." + } + + validation { + condition = var.kms_encryption_enabled_bucket ? ((var.existing_kms_key_crn != null || var.existing_kms_instance_crn != null) ? true : false) : true + error_message = "Either 'existing_kms_key_crn' or 'existing_kms_instance_crn' is required if 'kms_encryption_enabled_bucket' is set to true." + } +} + +variable "existing_kms_instance_crn" { + type = string + default = null + description = "The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). Used to create a new KMS key unless an existing key is passed using the `existing_scc_cos_kms_key_crn` input. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. A value should not be passed passing existing SCC instance using the `existing_scc_instance_crn` input." + + validation { + condition = var.existing_kms_instance_crn != null ? var.existing_scc_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." + } +} + +variable "existing_kms_key_crn" { + type = string + default = null + description = "The CRN of an existing KMS key to use to encrypt the Security and Compliance Center Object Storage bucket. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key, or for the `existing_scc_cos_bucket_name` variable to use an existing bucket." + + validation { + condition = var.existing_kms_key_crn != null ? var.existing_scc_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_key_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." + } + + validation { + condition = var.existing_kms_key_crn != null ? var.existing_kms_instance_crn != null : true + error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing key value using the 'existing_kms_key_crn' input." + } + +} + +variable "kms_endpoint_type" { + type = string + description = "The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_bucket` is true" + default = "private" + validation { + condition = can(regex("public|private", var.kms_endpoint_type)) + error_message = "The kms_endpoint_type value must be 'public' or 'private'." + } +} + +variable "scc_cos_key_ring_name" { + type = string + default = "scc-cos-key-ring" + description = "The name for the key ring created for the Security and Compliance Center Object Storage bucket key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "scc_cos_key_name" { + type = string + default = "scc-cos-key" + description = "The name for the key created for the Security and Compliance Center Object Storage bucket. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "ibmcloud_kms_api_key" { + type = string + description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Security and Compliance Centre instance. Leave this input empty if the same account owns both instances." + sensitive = true + default = null + + validation { + condition = var.ibmcloud_kms_api_key != null ? var.existing_scc_instance_crn == null : true + error_message = "A value should not be passed for 'ibmcloud_kms_api_key' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." + } +} + +######################################################################################################################## +# COS variables +######################################################################################################################## + +variable "existing_cos_instance_crn" { + type = string + nullable = true + default = null + description = "The CRN of an existing Object Storage instance. Not required if passing an existing SCC instance using the `existing_scc_instance_crn` input." + + validation { + condition = var.existing_cos_instance_crn == null ? var.existing_scc_instance_crn != null : true + error_message = "A value must be passed for 'existing_cos_instance_crn' when creating a new instance." + } +} + +variable "scc_cos_bucket_region" { + type = string + default = null + description = "The region to create the Object Storage bucket used by SCC. If not provided, the region specified in the `scc_region` input will be used. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_cos_bucket_name" { + type = string + default = "scc-cos-bucket" + description = "The name for the Security and Compliance Center Object Storage bucket. Bucket names must globally unique. If `add_bucket_name_suffix` is true, a 4-character string is added to this name to ensure it's globally unique. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "add_bucket_name_suffix" { + type = bool + description = "Whether to add a generated 4-character suffix to the created Security and Compliance Center Object Storage bucket name. Applies only if not specifying an existing bucket. Set to `false` not to add the suffix to the bucket name in the `scc_cos_bucket_name` variable. Applies only if `existing_scc_instance_crn` is not provided." + default = true +} + +variable "scc_cos_bucket_access_tags" { + type = list(string) + default = [] + description = "The list of access tags to add to the Security and Compliance Center Object Storage bucket. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_cos_bucket_class" { + type = string + default = "smart" + description = "The storage class of the newly provisioned Security and Compliance Center Object Storage bucket. Possible values: `standard`, `vault`, `cold`, `smart`, `onerate_active`. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes). Applies only if `existing_scc_instance_crn` is not provided." + validation { + condition = contains(["standard", "vault", "cold", "smart", "onerate_active"], var.scc_cos_bucket_class) + error_message = "Allowed values for cos_bucket_class are \"standard\", \"vault\",\"cold\", \"smart\", or \"onerate_active\"." + } +} + +variable "skip_scc_cos_iam_auth_policy" { + type = bool + default = false + description = "Set to `true` to skip creation of an IAM authorization policy that permits the Security and Compliance Center to write to the Object Storage instance created by this solution. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "skip_cos_kms_iam_auth_policy" { + type = bool + description = "Set to `true` to skip the creation of an IAM authorization policy that permits the Object Storage instance created to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. Applies only if `existing_scc_instance_crn` is not provided." + default = false +} + +variable "management_endpoint_type_for_bucket" { + description = "The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided." + type = string + default = "direct" + validation { + condition = contains(["public", "private", "direct"], var.management_endpoint_type_for_bucket) + error_message = "The specified management_endpoint_type_for_bucket is not a valid selection!" + } +} + +variable "existing_monitoring_crn" { + type = string + nullable = true + default = null + description = "The CRN of an IBM Cloud Monitoring instance to to send Security and Compliance Object Storage bucket metrics to. If no value passed, metrics are sent to the instance associated to the container's location unless otherwise specified in the Metrics Router service configuration. Applies only if `existing_scc_instance_crn` is not provided." +} + +######################################################################################################################## +# Event Notifications +######################################################################################################################## + +variable "existing_event_notifications_crn" { + type = string + nullable = true + default = null + description = "The CRN of an Event Notification instance. Used to integrate with Security and Compliance Center." + + validation { + condition = var.existing_event_notifications_crn != null ? var.existing_scc_instance_crn == null : true + error_message = "You cannot pass a value for 'existing_event_notifications_crn' when passing a value for 'existing_scc_instance_crn'. Event Notifications integration can only be configured when creating a new instance." + } +} + +variable "event_notifications_source_name" { + type = string + default = "compliance" + description = "The source name to use for the Event Notifications integration. Required if a value is passed for `event_notifications_instance_crn`. This name must be unique per SCC instance that is integrated with the Event Notifications instance." +} + +variable "event_notifications_source_description" { + type = string + default = null + description = "Optional description to give for the Event Notifications integration source. Only used if a value is passed for `event_notifications_instance_crn`." +} + +variable "scc_event_notifications_from_email" { + type = string + description = "The `from` email address used in any Security and Compliance Center events coming via Event Notifications." + default = "compliancealert@ibm.com" +} + +variable "scc_event_notifications_reply_to_email" { + type = string + description = "The `reply_to` email address used in any Security and Compliance Center events coming via Event Notifications." + default = "no-reply@ibm.com" +} + +variable "scc_event_notifications_email_list" { + type = list(string) + description = "The list of email addresses to notify when Security and Compliance Center triggers an event." + default = [] +} + +############################################################## +# Context-based restriction (CBR) +############################################################## + +variable "scc_instance_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "(Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/DA-cbr_rules.md)." + default = [] +} diff --git a/solutions/fully-configurable/version.tf b/solutions/fully-configurable/version.tf new file mode 100644 index 0000000..3f749ca --- /dev/null +++ b/solutions/fully-configurable/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.9.0" + # Lock DA into an exact provider version - renovate automation will keep it updated + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.76.1" + } + time = { + source = "hashicorp/time" + version = "0.12.1" + } + } +} From 580db58c634d05e0baa0081e72a82169d5dc07d7 Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Tue, 11 Mar 2025 19:24:05 +0000 Subject: [PATCH 02/11] test --- ibm_catalog.json | 6 +++--- solutions/{fully-configurable => standard}/DA-cbr_rules.md | 0 solutions/{fully-configurable => standard}/README.md | 0 .../catalogValidationValues.json.template | 0 .../{fully-configurable => standard}/custom_integrations.md | 0 solutions/{fully-configurable => standard}/main.tf | 0 solutions/{fully-configurable => standard}/outputs.tf | 0 solutions/{fully-configurable => standard}/provider.tf | 0 .../{fully-configurable => standard}/scopes_attachments.md | 0 solutions/{fully-configurable => standard}/variables.tf | 0 solutions/{fully-configurable => standard}/version.tf | 0 11 files changed, 3 insertions(+), 3 deletions(-) rename solutions/{fully-configurable => standard}/DA-cbr_rules.md (100%) rename solutions/{fully-configurable => standard}/README.md (100%) rename solutions/{fully-configurable => standard}/catalogValidationValues.json.template (100%) rename solutions/{fully-configurable => standard}/custom_integrations.md (100%) rename solutions/{fully-configurable => standard}/main.tf (100%) rename solutions/{fully-configurable => standard}/outputs.tf (100%) rename solutions/{fully-configurable => standard}/provider.tf (100%) rename solutions/{fully-configurable => standard}/scopes_attachments.md (100%) rename solutions/{fully-configurable => standard}/variables.tf (100%) rename solutions/{fully-configurable => standard}/version.tf (100%) diff --git a/ibm_catalog.json b/ibm_catalog.json index ad5b6d6..f6d90e6 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -43,10 +43,10 @@ "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues). Please note this product is not supported via the IBM Cloud Support Center.", "flavors": [ { - "label": "Fully configurable", - "name": "fully-configurable", + "label": "Standard", + "name": "standard", "install_type": "fullstack", - "working_directory": "solutions/fully-configurable", + "working_directory": "solutions/standard", "compliance": { "authority": "scc-v3", "profiles": [ diff --git a/solutions/fully-configurable/DA-cbr_rules.md b/solutions/standard/DA-cbr_rules.md similarity index 100% rename from solutions/fully-configurable/DA-cbr_rules.md rename to solutions/standard/DA-cbr_rules.md diff --git a/solutions/fully-configurable/README.md b/solutions/standard/README.md similarity index 100% rename from solutions/fully-configurable/README.md rename to solutions/standard/README.md diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/standard/catalogValidationValues.json.template similarity index 100% rename from solutions/fully-configurable/catalogValidationValues.json.template rename to solutions/standard/catalogValidationValues.json.template diff --git a/solutions/fully-configurable/custom_integrations.md b/solutions/standard/custom_integrations.md similarity index 100% rename from solutions/fully-configurable/custom_integrations.md rename to solutions/standard/custom_integrations.md diff --git a/solutions/fully-configurable/main.tf b/solutions/standard/main.tf similarity index 100% rename from solutions/fully-configurable/main.tf rename to solutions/standard/main.tf diff --git a/solutions/fully-configurable/outputs.tf b/solutions/standard/outputs.tf similarity index 100% rename from solutions/fully-configurable/outputs.tf rename to solutions/standard/outputs.tf diff --git a/solutions/fully-configurable/provider.tf b/solutions/standard/provider.tf similarity index 100% rename from solutions/fully-configurable/provider.tf rename to solutions/standard/provider.tf diff --git a/solutions/fully-configurable/scopes_attachments.md b/solutions/standard/scopes_attachments.md similarity index 100% rename from solutions/fully-configurable/scopes_attachments.md rename to solutions/standard/scopes_attachments.md diff --git a/solutions/fully-configurable/variables.tf b/solutions/standard/variables.tf similarity index 100% rename from solutions/fully-configurable/variables.tf rename to solutions/standard/variables.tf diff --git a/solutions/fully-configurable/version.tf b/solutions/standard/version.tf similarity index 100% rename from solutions/fully-configurable/version.tf rename to solutions/standard/version.tf From 424bd1da42b0bdbbb871a6d547eb38453a85f9ee Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Tue, 11 Mar 2025 19:28:41 +0000 Subject: [PATCH 03/11] test --- ibm_catalog.json | 6 +++--- solutions/{standard => fully-configurable}/DA-cbr_rules.md | 0 solutions/{standard => fully-configurable}/README.md | 0 .../catalogValidationValues.json.template | 0 .../{standard => fully-configurable}/custom_integrations.md | 0 solutions/{standard => fully-configurable}/main.tf | 0 solutions/{standard => fully-configurable}/outputs.tf | 0 solutions/{standard => fully-configurable}/provider.tf | 0 .../{standard => fully-configurable}/scopes_attachments.md | 0 solutions/{standard => fully-configurable}/variables.tf | 0 solutions/{standard => fully-configurable}/version.tf | 0 11 files changed, 3 insertions(+), 3 deletions(-) rename solutions/{standard => fully-configurable}/DA-cbr_rules.md (100%) rename solutions/{standard => fully-configurable}/README.md (100%) rename solutions/{standard => fully-configurable}/catalogValidationValues.json.template (100%) rename solutions/{standard => fully-configurable}/custom_integrations.md (100%) rename solutions/{standard => fully-configurable}/main.tf (100%) rename solutions/{standard => fully-configurable}/outputs.tf (100%) rename solutions/{standard => fully-configurable}/provider.tf (100%) rename solutions/{standard => fully-configurable}/scopes_attachments.md (100%) rename solutions/{standard => fully-configurable}/variables.tf (100%) rename solutions/{standard => fully-configurable}/version.tf (100%) diff --git a/ibm_catalog.json b/ibm_catalog.json index f6d90e6..ad5b6d6 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -43,10 +43,10 @@ "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues). Please note this product is not supported via the IBM Cloud Support Center.", "flavors": [ { - "label": "Standard", - "name": "standard", + "label": "Fully configurable", + "name": "fully-configurable", "install_type": "fullstack", - "working_directory": "solutions/standard", + "working_directory": "solutions/fully-configurable", "compliance": { "authority": "scc-v3", "profiles": [ diff --git a/solutions/standard/DA-cbr_rules.md b/solutions/fully-configurable/DA-cbr_rules.md similarity index 100% rename from solutions/standard/DA-cbr_rules.md rename to solutions/fully-configurable/DA-cbr_rules.md diff --git a/solutions/standard/README.md b/solutions/fully-configurable/README.md similarity index 100% rename from solutions/standard/README.md rename to solutions/fully-configurable/README.md diff --git a/solutions/standard/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template similarity index 100% rename from solutions/standard/catalogValidationValues.json.template rename to solutions/fully-configurable/catalogValidationValues.json.template diff --git a/solutions/standard/custom_integrations.md b/solutions/fully-configurable/custom_integrations.md similarity index 100% rename from solutions/standard/custom_integrations.md rename to solutions/fully-configurable/custom_integrations.md diff --git a/solutions/standard/main.tf b/solutions/fully-configurable/main.tf similarity index 100% rename from solutions/standard/main.tf rename to solutions/fully-configurable/main.tf diff --git a/solutions/standard/outputs.tf b/solutions/fully-configurable/outputs.tf similarity index 100% rename from solutions/standard/outputs.tf rename to solutions/fully-configurable/outputs.tf diff --git a/solutions/standard/provider.tf b/solutions/fully-configurable/provider.tf similarity index 100% rename from solutions/standard/provider.tf rename to solutions/fully-configurable/provider.tf diff --git a/solutions/standard/scopes_attachments.md b/solutions/fully-configurable/scopes_attachments.md similarity index 100% rename from solutions/standard/scopes_attachments.md rename to solutions/fully-configurable/scopes_attachments.md diff --git a/solutions/standard/variables.tf b/solutions/fully-configurable/variables.tf similarity index 100% rename from solutions/standard/variables.tf rename to solutions/fully-configurable/variables.tf diff --git a/solutions/standard/version.tf b/solutions/fully-configurable/version.tf similarity index 100% rename from solutions/standard/version.tf rename to solutions/fully-configurable/version.tf From 477ec5c309fa3d2c8490c7f391af8a4d14fbec69 Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Thu, 13 Mar 2025 12:46:41 +0000 Subject: [PATCH 04/11] latest --- .catalog-onboard-pipeline.yaml | 14 + .github/settings.yml | 2 +- .secrets.baseline | 43 ++- README.md | 2 +- examples/{complete => advanced}/README.md | 2 +- examples/{complete => advanced}/main.tf | 0 examples/{complete => advanced}/outputs.tf | 0 examples/{complete => advanced}/provider.tf | 0 examples/{complete => advanced}/variables.tf | 0 examples/{complete => advanced}/version.tf | 0 ibm_catalog.json | 242 ++++++------ images/scc-icon.svg | 1 + reference-architecture/scc.svg | 4 + solutions/fully-configurable/README.md | 29 +- .../catalogValidationValues.json.template | 3 +- .../fully-configurable/custom_integrations.md | 4 +- solutions/fully-configurable/main.tf | 56 ++- solutions/fully-configurable/outputs.tf | 2 +- .../fully-configurable/scopes_attachments.md | 11 +- solutions/fully-configurable/variables.tf | 69 +++- solutions/security-enforced/README.md | 114 ++++++ .../catalogValidationValues.json.template | 7 + solutions/security-enforced/main.tf | 88 +++++ solutions/security-enforced/outputs.tf | 57 +++ solutions/security-enforced/provider.tf | 30 ++ solutions/security-enforced/variables.tf | 365 ++++++++++++++++++ solutions/security-enforced/version.tf | 14 + tests/go.mod | 2 +- tests/go.sum | 4 +- tests/other_test.go | 38 +- tests/pr_test.go | 297 ++++++++++---- .../existing-resources-test/README.md | 1 + .../resources/existing-resources-test/main.tf | 53 +++ .../existing-resources-test/outputs.tf | 28 ++ .../existing-resources-test/provider.tf | 4 + .../existing-resources-test/variables.tf | 31 ++ .../existing-resources-test/version.tf | 9 + tests/resources/prereq-resources/README.md | 1 + tests/resources/prereq-resources/main.tf | 65 ++++ tests/resources/prereq-resources/outputs.tf | 43 +++ tests/resources/prereq-resources/provider.tf | 4 + tests/resources/prereq-resources/variables.tf | 31 ++ tests/resources/prereq-resources/version.tf | 9 + 43 files changed, 1493 insertions(+), 286 deletions(-) create mode 100644 .catalog-onboard-pipeline.yaml rename examples/{complete => advanced}/README.md (93%) rename examples/{complete => advanced}/main.tf (100%) rename examples/{complete => advanced}/outputs.tf (100%) rename examples/{complete => advanced}/provider.tf (100%) rename examples/{complete => advanced}/variables.tf (100%) rename examples/{complete => advanced}/version.tf (100%) create mode 100644 images/scc-icon.svg create mode 100644 reference-architecture/scc.svg create mode 100644 solutions/security-enforced/README.md create mode 100644 solutions/security-enforced/catalogValidationValues.json.template create mode 100644 solutions/security-enforced/main.tf create mode 100644 solutions/security-enforced/outputs.tf create mode 100644 solutions/security-enforced/provider.tf create mode 100644 solutions/security-enforced/variables.tf create mode 100644 solutions/security-enforced/version.tf create mode 100644 tests/resources/existing-resources-test/README.md create mode 100644 tests/resources/existing-resources-test/main.tf create mode 100644 tests/resources/existing-resources-test/outputs.tf create mode 100644 tests/resources/existing-resources-test/provider.tf create mode 100644 tests/resources/existing-resources-test/variables.tf create mode 100644 tests/resources/existing-resources-test/version.tf create mode 100644 tests/resources/prereq-resources/README.md create mode 100644 tests/resources/prereq-resources/main.tf create mode 100644 tests/resources/prereq-resources/outputs.tf create mode 100644 tests/resources/prereq-resources/provider.tf create mode 100644 tests/resources/prereq-resources/variables.tf create mode 100644 tests/resources/prereq-resources/version.tf diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml new file mode 100644 index 0000000..e40cf05 --- /dev/null +++ b/.catalog-onboard-pipeline.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: v1 +offerings: + - name: deploy-arch-ibm-scc + kind: solution + catalog_id: 7df1e4ca-d54c-4fd0-82ce-3d13247308cd + offering_id: 9423f9bc-1290-4c71-a9ac-01898bfa7ccc + variations: + - name: fully-configurable + mark_ready: true + install_type: fullstack + scc: + instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 + region: us-south diff --git a/.github/settings.yml b/.github/settings.yml index 55f03d0..af6c8ab 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -25,4 +25,4 @@ repository: description: "Configures an IBM Cloud Security and Compliance instance" # 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, supported, stable, scc, security, compliance + topics: terraform, ibm-cloud, terraform-module, core-team, supported, stable, scc, security, compliance, deployable-architecture diff --git a/.secrets.baseline b/.secrets.baseline index df8b961..bcffaec 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-13T06:40:44Z", + "generated_at": "2025-03-13T10:57:22Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -76,7 +76,46 @@ "name": "TwilioKeyDetector" } ], - "results": {}, + "results": { + "solutions/fully-configurable/DA-cbr_rules.md": [ + { + "hashed_secret": "91bd6d8889493222b850338327aa2f54b7ab25d0", + "is_secret": false, + "is_verified": false, + "line_number": 42, + "type": "Hex High Entropy String", + "verified_result": null + } + ], + "solutions/fully-configurable/scopes_attachments.md": [ + { + "hashed_secret": "3b5bf5f75003778663c521c8c35ad277227dd4f5", + "is_secret": false, + "is_verified": false, + "line_number": 42, + "type": "Hex High Entropy String", + "verified_result": null + }, + { + "hashed_secret": "a1dc91d03edccb97baada9b08525963807fb9d37", + "is_secret": false, + "is_verified": false, + "line_number": 46, + "type": "Hex High Entropy String", + "verified_result": null + } + ], + "tests/pr_test.go": [ + { + "hashed_secret": "3b5bf5f75003778663c521c8c35ad277227dd4f5", + "is_secret": false, + "is_verified": false, + "line_number": 43, + "type": "Hex High Entropy String", + "verified_result": null + } + ] + }, "version": "0.13.1+ibm.62.dss", "word_list": { "file": null, diff --git a/README.md b/README.md index af105a3..f254a11 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ This module configures an IBM Cloud Security and Compliance instance. * [Submodules](./modules) * [attachment](./modules/attachment) * [Examples](./examples) + * [Advanced example with CBR rules](./examples/advanced) * [Basic example](./examples/basic) - * [Complete example with CBR rules](./examples/complete) * [Contributing](#contributing) diff --git a/examples/complete/README.md b/examples/advanced/README.md similarity index 93% rename from examples/complete/README.md rename to examples/advanced/README.md index 80afc9b..974debb 100644 --- a/examples/complete/README.md +++ b/examples/advanced/README.md @@ -1,4 +1,4 @@ -# Complete example with CBR rules +# Advanced example with CBR rules A complete example that will provision the following: - A new resource group if one is not passed in. diff --git a/examples/complete/main.tf b/examples/advanced/main.tf similarity index 100% rename from examples/complete/main.tf rename to examples/advanced/main.tf diff --git a/examples/complete/outputs.tf b/examples/advanced/outputs.tf similarity index 100% rename from examples/complete/outputs.tf rename to examples/advanced/outputs.tf diff --git a/examples/complete/provider.tf b/examples/advanced/provider.tf similarity index 100% rename from examples/complete/provider.tf rename to examples/advanced/provider.tf diff --git a/examples/complete/variables.tf b/examples/advanced/variables.tf similarity index 100% rename from examples/complete/variables.tf rename to examples/advanced/variables.tf diff --git a/examples/complete/version.tf b/examples/advanced/version.tf similarity index 100% rename from examples/complete/version.tf rename to examples/advanced/version.tf diff --git a/ibm_catalog.json b/ibm_catalog.json index ad5b6d6..e441a3e 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -23,8 +23,8 @@ ], "short_description": "Creates and configures IBM Security and Compliance Center resources", "long_description": "This architecture supports creating and configuring IBM Security and Compliance Center resources.", - "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/blob/main/solutions/instances/README.md", - "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc-da/main/images/scc-icon.svg", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-scc/blob/main/README.md", + "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc/main/images/scc-icon.svg", "provider_name": "IBM", "features": [ { @@ -33,14 +33,26 @@ }, { "title": "Object Storage bucket for Security and Compliance Center", - "description": "Creates and configures a KMS-encrypted Object Storage bucket required for the Security and Compliance Center instance." + "description": "Creates and configures an Object Storage bucket required for the Security and Compliance Center instance." }, { - "title": "Security and Compliance Center Workload Protection", - "description": "Creates and configures a Security and Compliance Center Workload Protection instance." + "title": "KMS encryption", + "description": "Supports creating a new key, or using an existing one to encrypt the Object Storage bucket." + }, + { + "title": "Scopes and attachments", + "description": "Supports creating scopes and attachments." + }, + { + "title": "Event Notifications", + "description": "Supports integration with Event Notifications, including the creation of destination, topic and email subscription." + }, + { + "title": "Provider integration", + "description": "Supports integration with providers such as Workload Protection." } ], - "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/issues). Please note this product is not supported via the IBM Cloud Support Center.", + "support_details": "This product is in the community registry, as such support is handled through the originated repo. If you experience issues please open an issue in that repository [https://github.com/terraform-ibm-modules/terraform-ibm-scc/issues](https://github.com/terraform-ibm-modules/terraform-ibm-scc/issues). Please note this product is not supported via the IBM Cloud Support Center.", "flavors": [ { "label": "Fully configurable", @@ -67,6 +79,7 @@ }, { "key": "existing_resource_group_name", + "required": true, "custom_config": { "type": "resource_group", "grouping": "deployment", @@ -77,9 +90,23 @@ } }, { - "key": "resource_group_name", + "key": "existing_cos_instance_crn", "required": true }, + { + "key": "scc_service_plan", + "required": true, + "options": [ + { + "displayname": "Standard", + "value": "security-compliance-center-standard-plan" + }, + { + "displayname": "Trial", + "value": "security-compliance-center-trial-plan" + } + ] + }, { "key": "scc_region", "required": true, @@ -102,10 +129,6 @@ } ] }, - { - "key": "existing_kms_instance_crn", - "required": true - }, { "key": "provider_visibility", "options": [ @@ -127,7 +150,7 @@ "key": "scc_instance_name" }, { - "key": "scc_instance_tags", + "key": "scc_instance_resource_tags", "custom_config": { "grouping": "deployment", "original_grouping": "deployment", @@ -137,47 +160,39 @@ } }, { - "key": "scc_service_plan", - "options": [ - { - "displayname": "Standard", - "value": "security-compliance-center-standard-plan" - }, - { - "displayname": "Trial", - "value": "security-compliance-center-trial-plan" + "key": "scc_instance_access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" } - ] + } }, { "key": "existing_scc_instance_crn" }, { - "key": "cos_instance_name" + "key": "scopes" }, { - "key": "cos_instance_tags", - "custom_config": { - "grouping": "deployment", - "original_grouping": "deployment", - "config_constraints": { - "type": "string" - } - } + "key": "attachments" }, { - "key": "cos_instance_access_tags", - "custom_config": { - "grouping": "deployment", - "original_grouping": "deployment", - "config_constraints": { - "type": "string" - } - } + "key": "existing_scc_workload_protection_instance_crn" + }, + { + "key": "skip_scc_workload_protection_iam_auth_policy" + }, + { + "key": "custom_integrations" }, { "key": "scc_cos_bucket_name" }, + { + "key": "kms_encryption_enabled_bucket" + }, { "key": "scc_cos_bucket_region", "options": [ @@ -265,9 +280,6 @@ } ] }, - { - "key": "existing_scc_cos_bucket_name" - }, { "key": "management_endpoint_type_for_bucket", "options": [ @@ -285,9 +297,6 @@ } ] }, - { - "key": "existing_cos_instance_crn" - }, { "key": "existing_monitoring_crn" }, @@ -295,7 +304,10 @@ "key": "skip_scc_cos_iam_auth_policy" }, { - "key": "existing_scc_cos_kms_key_crn" + "key": "existing_kms_instance_crn" + }, + { + "key": "existing_kms_key_crn" }, { "key": "ibmcloud_kms_api_key" @@ -323,83 +335,7 @@ "key": "scc_cos_key_name" }, { - "key": "profile_attachments" - }, - { - "key": "resource_groups_scope" - }, - { - "key": "attachment_schedule", - "options": [ - { - "displayname": "Daily", - "value": "daily" - }, - { - "displayname": "Weekly", - "value": "every_7_days" - }, - { - "displayname": "Monthly", - "value": "every_30_days" - }, - { - "displayname": "Never", - "value": "none" - } - ] - }, - { - "key": "provision_scc_workload_protection" - }, - { - "key": "scc_workload_protection_instance_name" - }, - { - "key": "scc_workload_protection_service_plan", - "options": [ - { - "displayname": "Free trial", - "value": "free-trial" - }, - { - "displayname": "Graduated tier", - "value": "graduated-tier" - } - ] - }, - { - "key": "scc_workload_protection_instance_tags", - "custom_config": { - "grouping": "deployment", - "original_grouping": "deployment", - "config_constraints": { - "type": "string" - } - } - }, - { - "key": "scc_workload_protection_resource_key_tags", - "custom_config": { - "grouping": "deployment", - "original_grouping": "deployment", - "config_constraints": { - "type": "string" - } - } - }, - { - "key": "scc_workload_protection_access_tags", - "custom_config": { - "grouping": "deployment", - "original_grouping": "deployment", - "config_constraints": { - "type": "string" - } - } - }, - { - "key": "skip_scc_workload_protection_iam_auth_policy" + "key": "force_delete_kms_key" }, { "key": "existing_event_notifications_crn" @@ -446,26 +382,70 @@ } ], "architecture": { - "descriptions": "This architecture supports creating and configuring a Security and Compliance Center Workload Protection instance.", + "descriptions": "This architecture supports creating and configuring a Security and Compliance Center instance.", "features": [ { - "title": "Creates a Security and Compliance Center instance", - "description": "Creates and configures a Security and Compliance Center instance." + "title": "SCC instance creation", + "description": "Yes" + }, + { + "title": "Use existing SCC instance", + "description": "Yes" + }, + { + "title": "New resource group creation", + "description": "No" + }, + { + "title": "Use existing resource group", + "description": "Yes" + }, + { + "title": "COS instance creation", + "description": "No" + }, + { + "title": "COS bucket creation", + "description": "Yes" + }, + { + "title": "Enforced KMS encryption", + "description": "No" + }, + { + "title": "KMS instance creation", + "description": "No" + }, + { + "title": "KMS key ring and key creation", + "description": "Yes" + }, + { + "title": "Use existing KMS key", + "description": "Yes" + }, + { + "title": "IAM s2s auth policies creation", + "description": "Yes" + }, + { + "title": "SCC scope creation", + "description": "Yes" }, { - "title": "Creates an Object Storage bucket", - "description": "Creates and configures a KMS-encrypted Object Storage bucket required for the Security and Compliance Center instance." + "title": "SCC attachment creation", + "description": "Yes" }, { - "title": "Creates a Security and Compliance Center Workload Protection instance", - "description": "Creates and configures a Security and Compliance Center Workload Protection instance." + "title": "Event Notifications integration", + "description": "Yes" } ], "diagrams": [ { "diagram": { "caption": "Security and Compliance Center", - "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc-da/main/reference-architecture/scc.svg", + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc/main/reference-architecture/scc.svg", "type": "image/svg+xml" }, "description": "This architecture supports creating and configuring IBM Security and Compliance Center resources" diff --git a/images/scc-icon.svg b/images/scc-icon.svg new file mode 100644 index 0000000..c402fe1 --- /dev/null +++ b/images/scc-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/reference-architecture/scc.svg b/reference-architecture/scc.svg new file mode 100644 index 0000000..83e02b4 --- /dev/null +++ b/reference-architecture/scc.svg @@ -0,0 +1,4 @@ + + + +
IBM Cloud
IBM Cloud
Activity Tracker
service
Activity Tracker...
Existing
Monitoring instance
Existing...
`
Event Notifications integration
Event Notification...
Workload 
Protection 
integration
Workload...
Custom provider
integration
Custom provider...
Region
Region
Existing resource group
Existing resource group
SCC instance
SCC instance
Attchments
Attchments
Scopes
Scopes
Existing KMS instance
Existing KMS insta...
Existing COS instance
Existing COS instance
COS bucket
COS bucket
AT events
AT events
Metrics
Metrics
KMS key
KMS key
Text is not SVG - cannot display
\ No newline at end of file diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md index e397f03..615b90a 100644 --- a/solutions/fully-configurable/README.md +++ b/solutions/fully-configurable/README.md @@ -1,15 +1,19 @@ -# Security and Compliance Center instances solution +# Cloud automation for Security and Compliance Center (Fully configurable) -This solution supports provisioning and configuring the following infrastructure: +## Prerequisites +- An existing resource group +- An existing COS instance +- An existing KMS instance (or key) if you wan't to encrypt the COS bucket created for use with SCC -- A resource group, if one is not passed in. +This solution supports provisioning and configuring the following infrastructure: - A Security and Compliance Center instance. -- A Security and Compliance Center Workload Protection instance. -- An IBM Cloud Object Storage instance and KMS-encrypted bucket, which is required to store Security and Compliance Center data. -- Security and Compliance Center profile attachments configured for the instance created by this module. +- A Cloud Object Storage bucket which is required to store Security and Compliance Center data. +- Security and Compliance Center scopes and attachments. +- Integrations with Workload Protection and other custom providers :exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). +![scc-deployable-architecture](../../reference-architecture/scc.svg) @@ -33,8 +37,8 @@ This solution supports provisioning and configuring the following infrastructure | [existing\_scc\_crn\_parser](#module\_existing\_scc\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | | [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 4.21.2 | | [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.1.6 | -| [scc](#module\_scc) | terraform-ibm-modules/scc/ibm | 2.0.1 | -| [scc\_attachment](#module\_scc\_attachment) | terraform-ibm-modules/scc/ibm//modules/attachment | 2.0.1 | +| [scc](#module\_scc) | ../.. | n/a | +| [scc\_attachment](#module\_scc\_attachment) | ../../modules/attachment | n/a | ### Resources @@ -53,7 +57,7 @@ This solution supports provisioning and configuring the following infrastructure | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [add\_bucket\_name\_suffix](#input\_add\_bucket\_name\_suffix) | Whether to add a generated 4-character suffix to the created Security and Compliance Center Object Storage bucket name. Applies only if not specifying an existing bucket. Set to `false` not to add the suffix to the bucket name in the `scc_cos_bucket_name` variable. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `true` | no | -| [attachments](#input\_attachments) | A list of attachments to create. A value must be passed for 'scope\_ids' (to use pre-existing scopes) and/or 'scope\_key\_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
list(object({
profile_name = string
profile_version = string
attachment_name = string
attachment_description = string
attachment_schedule = string
scope_key_references = optional(list(string), [])
scope_ids = optional(list(string), [])
notifications = object({
enabled = optional(bool, true)
failed_control_ids = optional(list(string), [])
threshold_limit = optional(number, 10)
})
}))
| `[]` | no | +| [attachments](#input\_attachments) | A list of attachments to create. A value must be passed for 'scope\_ids' (to use pre-existing scopes) and/or 'scope\_key\_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
list(object({
profile_name = string
profile_version = string
attachment_name = string
attachment_description = string
attachment_schedule = string
scope_key_references = optional(list(string), [])
scope_ids = optional(list(string), [])
notifications = object({
enabled = optional(bool, true)
failed_control_ids = optional(list(string), [])
threshold_limit = optional(number, 10)
})
}))
| `[]` | no | | [custom\_integrations](#input\_custom\_integrations) | A list of custom provider integrations to associate with the Security and Compliance Center instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/custom_integrations.md). |
list(object({
attributes = optional(map(string), {})
provider_name = string
integration_name = string
}))
| `[]` | no | | [event\_notifications\_source\_description](#input\_event\_notifications\_source\_description) | Optional description to give for the Event Notifications integration source. Only used if a value is passed for `event_notifications_instance_crn`. | `string` | `null` | no | | [event\_notifications\_source\_name](#input\_event\_notifications\_source\_name) | The source name to use for the Event Notifications integration. Required if a value is passed for `event_notifications_instance_crn`. This name must be unique per SCC instance that is integrated with the Event Notifications instance. | `string` | `"compliance"` | no | @@ -62,14 +66,15 @@ This solution supports provisioning and configuring the following infrastructure | [existing\_kms\_instance\_crn](#input\_existing\_kms\_instance\_crn) | The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). Used to create a new KMS key unless an existing key is passed using the `existing_scc_cos_kms_key_crn` input. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. A value should not be passed passing existing SCC instance using the `existing_scc_instance_crn` input. | `string` | `null` | no | | [existing\_kms\_key\_crn](#input\_existing\_kms\_key\_crn) | The CRN of an existing KMS key to use to encrypt the Security and Compliance Center Object Storage bucket. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key, or for the `existing_scc_cos_bucket_name` variable to use an existing bucket. | `string` | `null` | no | | [existing\_monitoring\_crn](#input\_existing\_monitoring\_crn) | The CRN of an IBM Cloud Monitoring instance to to send Security and Compliance Object Storage bucket metrics to. If no value passed, metrics are sent to the instance associated to the container's location unless otherwise specified in the Metrics Router service configuration. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `null` | no | -| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision resource in. | `string` | n/a | yes | +| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision resource in. | `string` | `"Default"` | no | | [existing\_scc\_instance\_crn](#input\_existing\_scc\_instance\_crn) | The CRN of an existing Security and Compliance Center instance. If not supplied, a new instance will be created. | `string` | `null` | no | | [existing\_scc\_workload\_protection\_instance\_crn](#input\_existing\_scc\_workload\_protection\_instance\_crn) | The CRN of an existing Workload Protection instance to associate with the Security and Compliance Center instance. | `string` | `null` | no | +| [force\_delete\_kms\_key](#input\_force\_delete\_kms\_key) | If creating a new KMS key, toggle whether is should be force deleted or not on undeploy. | `bool` | `false` | no | | [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key used to provision resources. | `string` | n/a | yes | | [ibmcloud\_kms\_api\_key](#input\_ibmcloud\_kms\_api\_key) | The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud\_api\_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Security and Compliance Centre instance. Leave this input empty if the same account owns both instances. | `string` | `null` | no | | [kms\_encryption\_enabled\_bucket](#input\_kms\_encryption\_enabled\_bucket) | Set to true to enable KMS encryption on the Object Storage bucket created for the Security and Compliance Center instance. When set to true, a value must be passed for either `existing_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_scc_instance_crn`. | `bool` | `false` | no | | [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_bucket` is true | `string` | `"private"` | no | -| [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"direct"` | no | +| [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"private"` | no | | [prefix](#input\_prefix) | The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes | | [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints). | `string` | `"private"` | no | | [scc\_cos\_bucket\_access\_tags](#input\_scc\_cos\_bucket\_access\_tags) | The list of access tags to add to the Security and Compliance Center Object Storage bucket. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | @@ -87,7 +92,7 @@ This solution supports provisioning and configuring the following infrastructure | [scc\_instance\_resource\_tags](#input\_scc\_instance\_resource\_tags) | The list of tags to add to the Security and Compliance Center instance. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | | [scc\_region](#input\_scc\_region) | The region to provision Security and Compliance Center resources in. If passing a value for `existing_scc_instance_crn`, ensure to select the region of the existing instance. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"us-south"` | no | | [scc\_service\_plan](#input\_scc\_service\_plan) | The pricing plan to use when creating a new Security Compliance Center instance. Possible values: `security-compliance-center-standard-plan`, `security-compliance-center-trial-plan`. | `string` | `"security-compliance-center-standard-plan"` | no | -| [scopes](#input\_scopes) | A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope\_key\_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
map(object({
name = string
description = string
environment = optional(string, "ibm-cloud")
properties = object({
scope_id = string
scope_type = string
})
exclusions = optional(list(object({
scope_id = string
scope_type = string
})))
}))
| `{}` | no | +| [scopes](#input\_scopes) | A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope\_key\_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
map(object({
name = string
description = string
environment = optional(string, "ibm-cloud")
properties = object({
scope_id = string
scope_type = string
})
exclusions = optional(list(object({
scope_id = string
scope_type = string
})), [])
}))
| `{}` | no | | [skip\_cos\_kms\_iam\_auth\_policy](#input\_skip\_cos\_kms\_iam\_auth\_policy) | Set to `true` to skip the creation of an IAM authorization policy that permits the Object Storage instance created to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `false` | no | | [skip\_scc\_cos\_iam\_auth\_policy](#input\_skip\_scc\_cos\_iam\_auth\_policy) | Set to `true` to skip creation of an IAM authorization policy that permits the Security and Compliance Center to write to the Object Storage instance created by this solution. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `false` | no | | [skip\_scc\_workload\_protection\_iam\_auth\_policy](#input\_skip\_scc\_workload\_protection\_iam\_auth\_policy) | Set to `true` to skip creating an IAM authorization policy that permits the Security and Compliance Center instance to read from the Workload Protection instance. Applies only if a value is passed for `existing_scc_workload_protection_instance_crn`. | `bool` | `false` | no | diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template index bf6e9d9..cc38ce8 100644 --- a/solutions/fully-configurable/catalogValidationValues.json.template +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -2,5 +2,6 @@ "ibmcloud_api_key": $VALIDATION_APIKEY, "prefix": $PREFIX, "existing_resource_group_name": "geretain-test-resources", - "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "existing_cos_instance_crn": $COS_INSTANCE_CRN } diff --git a/solutions/fully-configurable/custom_integrations.md b/solutions/fully-configurable/custom_integrations.md index aa4e79e..dd7bf27 100644 --- a/solutions/fully-configurable/custom_integrations.md +++ b/solutions/fully-configurable/custom_integrations.md @@ -2,7 +2,7 @@ Custom provider integrations can be configured for the Security and Compliance Center instance using the `custom_integrations` input. -:information_source: If you wan't to integrate with an SCC Workload Protection instance, simply use the `existing_scc_workload_protection_instance_crn` input instead. +:information_source: If you wan't to integrate with an SCC Workload Protection instance, simply use the `existing_scc_workload_protection_instance_crn` input instead. ## Options for custom_integrations The `custom_integrations` input a list type input which supporting configuring multiple integrations. Each entry in the list is a map object with the following options: @@ -29,7 +29,7 @@ The `custom_integrations` input a list type input which supporting configuring m { provider_name = "Sample" integration_name = "sample-integration" - attributes = {"description": "this is a sample"} + attributes = {"description": "this is a sample"} } ] ``` diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index b02cc05..458dcf5 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -20,27 +20,27 @@ module "existing_kms_crn_parser" { } module "existing_kms_key_crn_parser" { - count = var.kms_encryption_enabled_bucket ? 1 : 0 + count = var.existing_kms_key_crn != null ? 1 : 0 source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" version = "1.1.0" - crn = var.existing_kms_key_crn != null ? var.existing_kms_key_crn : module.kms[0].keys[format("%s.%s", local.scc_cos_key_ring_name, local.scc_cos_key_name)].crn + crn = var.existing_kms_key_crn } locals { - prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null - kms_region = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].region : null : null - existing_kms_guid = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_instance : null : null - kms_service_name = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_name : null : null - kms_account_id = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket ? var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].account_id : null : null - kms_key_id = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket && length(module.existing_kms_key_crn_parser) > 0 ? module.existing_kms_key_crn_parser[0].resource : null - scc_cos_key_ring_name = try("${local.prefix}-${var.scc_cos_key_ring_name}", var.scc_cos_key_ring_name) - scc_cos_key_name = try("${local.prefix}-${var.scc_cos_key_name}", var.scc_cos_key_name) - scc_cos_bucket_region = var.scc_cos_bucket_region != null && var.scc_cos_bucket_region != "" ? var.scc_cos_bucket_region : var.scc_region - scc_instance_name = try("${local.prefix}-${var.scc_instance_name}", var.scc_instance_name) + prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null + kms_region = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].region : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].region : null + existing_kms_guid = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_instance : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].service_instance : null + kms_service_name = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_name : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].service_name : null + kms_account_id = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].account_id : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].account_id : null + kms_key_id = var.existing_kms_instance_crn != null ? module.kms[0].keys[format("%s.%s", local.scc_cos_key_ring_name, local.scc_cos_key_name)].key_id : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].resource : null + scc_cos_key_ring_name = try("${local.prefix}-${var.scc_cos_key_ring_name}", var.scc_cos_key_ring_name) + scc_cos_key_name = try("${local.prefix}-${var.scc_cos_key_name}", var.scc_cos_key_name) + scc_cos_bucket_region = var.scc_cos_bucket_region != null && var.scc_cos_bucket_region != "" ? var.scc_cos_bucket_region : var.scc_region + scc_instance_name = try("${local.prefix}-${var.scc_instance_name}", var.scc_instance_name) # Bucket name to be passed to the COS module to create a bucket created_scc_cos_bucket_name = try("${local.prefix}-${var.scc_cos_bucket_name}", var.scc_cos_bucket_name) # Final COS bucket name after being created by COS module (as it might have suffix added to it) - scc_cos_bucket_name = module.buckets[0].buckets[local.created_scc_cos_bucket_name].bucket_name + scc_cos_bucket_name = var.existing_scc_instance_crn == null ? module.buckets[0].buckets[local.created_scc_cos_bucket_name].bucket_name : null create_cross_account_auth_policy = var.existing_scc_instance_crn == null ? !var.skip_cos_kms_iam_auth_policy && var.ibmcloud_kms_api_key == null ? false : (module.scc.account_id != module.existing_kms_crn_parser[0].account_id) : false } @@ -98,7 +98,7 @@ module "kms" { providers = { ibm = ibm.kms } - count = var.kms_encryption_enabled_bucket && var.existing_kms_key_crn == null ? 1 : 0 + count = var.existing_scc_instance_crn == null && var.kms_encryption_enabled_bucket && var.existing_kms_key_crn == null ? 1 : 0 source = "terraform-ibm-modules/kms-all-inclusive/ibm" version = "4.21.2" create_key_protect_instance = false @@ -116,7 +116,7 @@ module "kms" { standard_key = false rotation_interval_month = 3 dual_auth_delete_enabled = false - force_delete = false # TBC + force_delete = var.force_delete_kms_key } ] } @@ -128,7 +128,7 @@ module "kms" { ####################################################################################################################### module "existing_cos_crn_parser" { - count = var.existing_cos_instance_crn != null ? 1 : 0 + count = var.existing_scc_instance_crn == null && var.existing_cos_instance_crn != null ? 1 : 0 source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" version = "1.1.0" crn = var.existing_cos_instance_crn @@ -149,7 +149,7 @@ locals { storage_class = var.scc_cos_bucket_class resource_instance_id = var.existing_cos_instance_crn region_location = local.scc_cos_bucket_region - force_delete = false # TBC + 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 @@ -187,13 +187,12 @@ module "existing_scc_crn_parser" { } locals { - scc_instance_region = var.existing_scc_instance_crn == null ? var.scc_region : module.existing_scc_crn_parser[0].region + scc_instance_region = var.existing_scc_instance_crn == null ? var.scc_region : module.existing_scc_crn_parser[0].region } module "scc" { - source = "terraform-ibm-modules/scc/ibm" + source = "../.." existing_scc_instance_crn = var.existing_scc_instance_crn - version = "2.0.1" resource_group_id = module.resource_group.resource_group_id region = var.scc_region instance_name = local.scc_instance_name @@ -225,7 +224,7 @@ resource "ibm_scc_scope" "scc_scopes" { instance_id = module.scc.guid name = each.value.name properties = each.value.properties - + dynamic "exclusions" { for_each = each.value.exclusions content { @@ -241,13 +240,12 @@ resource "ibm_scc_scope" "scc_scopes" { module "scc_attachment" { - for_each = { - for index, attachment in var.attachments: + for_each = { + for index, attachment in var.attachments : attachment.attachment_name => attachment } - source = "terraform-ibm-modules/scc/ibm//modules/attachment" - version = "2.0.1" + source = "../../modules/attachment" profile_name = each.value.profile_name profile_version = each.value.profile_version scc_instance_id = module.scc.guid @@ -256,7 +254,7 @@ module "scc_attachment" { attachment_schedule = each.value.attachment_schedule # lookup the scope ID created using 'scope_key_references' value # concat the 'scope_key_references' computed IDs with the IDs listed in the 'scope_ids' attribute - scope_ids = concat([for s in each.value.scope_key_references : ibm_scc_scope.scc_scopes[s].id], each.value.scope_ids) + scope_ids = concat([for s in each.value.scope_key_references : ibm_scc_scope.scc_scopes[s].scope_id], each.value.scope_ids) } ####################################################################################################################### @@ -271,8 +269,8 @@ module "existing_en_crn_parser" { } locals { - existing_en_guid = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].service_instance : null - existing_en_region = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].region : null + existing_en_guid = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].service_instance : null + existing_en_region = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].region : null } data "ibm_en_destinations" "en_destinations" { @@ -283,7 +281,7 @@ data "ibm_en_destinations" "en_destinations" { # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5533. resource "time_sleep" "wait_for_scc" { - count = var.existing_event_notifications_crn != null && var.existing_scc_instance_crn == null ? 1 : 0 + count = var.existing_event_notifications_crn != null && var.existing_scc_instance_crn == null ? 1 : 0 depends_on = [module.scc] create_duration = "60s" diff --git a/solutions/fully-configurable/outputs.tf b/solutions/fully-configurable/outputs.tf index 20c5316..abf5798 100644 --- a/solutions/fully-configurable/outputs.tf +++ b/solutions/fully-configurable/outputs.tf @@ -38,7 +38,7 @@ output "scc_name" { output "scc_cos_kms_key_crn" { description = "SCC COS KMS Key CRN" - value = local.scc_cos_kms_key_crn + value = local.scc_cos_kms_key_crn } output "scc_cos_bucket_name" { diff --git a/solutions/fully-configurable/scopes_attachments.md b/solutions/fully-configurable/scopes_attachments.md index d0b5da3..0d60b75 100644 --- a/solutions/fully-configurable/scopes_attachments.md +++ b/solutions/fully-configurable/scopes_attachments.md @@ -18,7 +18,7 @@ The `scopes` input can be used to create multiple scopes, which can then be used - The following example shows how to create a scope for the full account: ``` { - full-account = { + all = { name = "Full account" description = "Scope to scan the whole account" environment = "ibm-cloud" @@ -29,12 +29,12 @@ The `scopes` input can be used to create multiple scopes, which can then be used } } ``` - - The key identifier for above example is `full-account`. This can be referenced when creating attachments using the `scope_key_references` attribute of the [attachments](#attachments) input. + - The key identifier for above example is `all`. This can be referenced when creating attachments using the `scope_key_references` attribute of the [attachments](#attachments) input. - The following example shows how to exclude a resource group from the scope: ``` { - exclude-group = { + exclude = { name = "Exclude Default resource group" description = "Scope to exclude the Default resource group" environment = "ibm-cloud" @@ -49,7 +49,7 @@ The `scopes` input can be used to create multiple scopes, which can then be used } } ``` - - The key identifier for above example is `exclude-group`. This can be referenced when creating attachments using the `scope_key_references` attribute of the [attachments](#attachments) input. + - The key identifier for above example is `exclude`. This can be referenced when creating attachments using the `scope_key_references` attribute of the [attachments](#attachments) input. ## Attachments The `attachments` input can be used to create multiple attachments using either pre-existing scopes, or scopes that were created with the [scopes](#scopes) input. The input type is a list of objects with the following attributes: @@ -74,7 +74,7 @@ The `attachments` input can be used to create multiple attachments using either attachment_name = "SOC 2 full account" attachment_description = "SOC 2 full account" attachment_schedule = "daily" - scope_key_references = ["full-account"] + scope_key_references = ["all"] notifications = { enabled = true failed_control_ids = ["c51c5094-6f6b-4fee-b0f6-ad51ca68e18a"] @@ -99,4 +99,3 @@ The `attachments` input can be used to create multiple attachments using either } }] ``` - \ No newline at end of file diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index c4ccee4..a70fee0 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -11,6 +11,7 @@ variable "ibmcloud_api_key" { variable "existing_resource_group_name" { type = string description = "The name of an existing resource group to provision resource in." + default = "Default" } variable "prefix" { @@ -97,7 +98,7 @@ variable "custom_integrations" { variable "scopes" { type = map(object({ - name = string + name = string description = string environment = optional(string, "ibm-cloud") properties = object({ @@ -107,34 +108,34 @@ variable "scopes" { exclusions = optional(list(object({ scope_id = string scope_type = string - }))) + })), []) })) - default = {} - nullable = false + default = {} + nullable = false description = "A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope_key_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md)." } variable "attachments" { type = list(object({ - profile_name = string - profile_version = string - attachment_name = string + profile_name = string + profile_version = string + attachment_name = string attachment_description = string - attachment_schedule = string - scope_key_references = optional(list(string), []) - scope_ids = optional(list(string), []) + attachment_schedule = string + scope_key_references = optional(list(string), []) + scope_ids = optional(list(string), []) notifications = object({ - enabled = optional(bool, true) + enabled = optional(bool, true) failed_control_ids = optional(list(string), []) - threshold_limit = optional(number, 10) + threshold_limit = optional(number, 10) }) })) - default = [] + default = [] description = "A list of attachments to create. A value must be passed for 'scope_ids' (to use pre-existing scopes) and/or 'scope_key_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md)." validation { condition = alltrue([for attachments in var.attachments : - length(attachments.scope_ids) > 0 || length(attachments.scope_key_references) > 40 + length(attachments.scope_ids) > 0 || length(attachments.scope_key_references) > 0 ]) error_message = "At least one value needs to be added to the 'scope_ids' or 'scope_key_references' list inputs." } @@ -171,6 +172,16 @@ variable "kms_encryption_enabled_bucket" { error_message = "'kms_encryption_enabled_bucket' should be false if passing a value for 'existing_scc_instance_crn' as existing SCC instance will already have a bucket attached." } + validation { + condition = var.existing_kms_instance_crn != null ? var.kms_encryption_enabled_bucket : true + error_message = "If passing a value for 'existing_kms_instance_crn', you should set 'kms_encryption_enabled_bucket' to true." + } + + validation { + condition = var.existing_kms_key_crn != null ? var.kms_encryption_enabled_bucket : true + error_message = "If passing a value for 'existing_kms_key_crn', you should set 'kms_encryption_enabled_bucket' to true." + } + validation { condition = var.kms_encryption_enabled_bucket ? ((var.existing_kms_key_crn != null || var.existing_kms_instance_crn != null) ? true : false) : true error_message = "Either 'existing_kms_key_crn' or 'existing_kms_instance_crn' is required if 'kms_encryption_enabled_bucket' is set to true." @@ -182,24 +193,46 @@ variable "existing_kms_instance_crn" { default = null description = "The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). Used to create a new KMS key unless an existing key is passed using the `existing_scc_cos_kms_key_crn` input. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. A value should not be passed passing existing SCC instance using the `existing_scc_instance_crn` input." + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.existing_kms_instance_crn)), + var.existing_kms_instance_crn == null, + ]) + error_message = "The provided KMS instance CRN in the input 'existing_kms_instance_crn' in not valid." + } + validation { condition = var.existing_kms_instance_crn != null ? var.existing_scc_instance_crn == null : true error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." } } +variable "force_delete_kms_key" { + type = bool + default = false + description = "If creating a new KMS key, toggle whether is should be force deleted or not on undeploy." +} + variable "existing_kms_key_crn" { type = string default = null description = "The CRN of an existing KMS key to use to encrypt the Security and Compliance Center Object Storage bucket. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key, or for the `existing_scc_cos_bucket_name` variable to use an existing bucket." - + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}:key:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.existing_kms_key_crn)), + var.existing_kms_key_crn == null, + ]) + error_message = "The provided KMS key CRN in the input 'existing_kms_key_crn' in not valid." + } + validation { condition = var.existing_kms_key_crn != null ? var.existing_scc_instance_crn == null : true error_message = "A value should not be passed for 'existing_kms_key_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." } - + validation { - condition = var.existing_kms_key_crn != null ? var.existing_kms_instance_crn != null : true + condition = var.existing_kms_key_crn != null ? var.existing_kms_instance_crn == null : true error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing key value using the 'existing_kms_key_crn' input." } @@ -304,7 +337,7 @@ variable "skip_cos_kms_iam_auth_policy" { variable "management_endpoint_type_for_bucket" { description = "The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided." type = string - default = "direct" + default = "private" validation { condition = contains(["public", "private", "direct"], var.management_endpoint_type_for_bucket) error_message = "The specified management_endpoint_type_for_bucket is not a valid selection!" diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md new file mode 100644 index 0000000..07f4544 --- /dev/null +++ b/solutions/security-enforced/README.md @@ -0,0 +1,114 @@ +# Cloud automation for Security and Compliance Center (Security-enforced) + +## Prerequisites +- An existing resource group +- An existing COS instance +- An existing KMS instance (or key) to encrypt the COS bucket created for use with SCC + +This solution supports provisioning and configuring the following infrastructure: +- A Security and Compliance Center instance. +- A Cloud Object Storage bucket which is required to store Security and Compliance Center data. +- Security and Compliance Center scopes and attachments. +- Integrations with Workload Protection and other custom providers + +:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). + +![scc-deployable-architecture](../../reference-architecture/scc.svg) + + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.9.0 | +| [ibm](#requirement\_ibm) | 1.76.1 | +| [time](#requirement\_time) | 0.12.1 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [buckets](#module\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 8.19.8 | +| [existing\_cos\_crn\_parser](#module\_existing\_cos\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_en\_crn\_parser](#module\_existing\_en\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_kms\_crn\_parser](#module\_existing\_kms\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_kms\_key\_crn\_parser](#module\_existing\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_scc\_crn\_parser](#module\_existing\_scc\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 4.21.2 | +| [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.1.6 | +| [scc](#module\_scc) | ../.. | n/a | +| [scc\_attachment](#module\_scc\_attachment) | ../../modules/attachment | n/a | + +### Resources + +| Name | Type | +|------|------| +| [ibm_en_subscription_email.email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/en_subscription_email) | resource | +| [ibm_en_topic.en_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/en_topic) | resource | +| [ibm_iam_authorization_policy.cos_kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/iam_authorization_policy) | resource | +| [ibm_scc_scope.scc_scopes](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/scc_scope) | resource | +| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | +| [time_sleep.wait_for_scc](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | +| [ibm_en_destinations.en_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/data-sources/en_destinations) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [add\_bucket\_name\_suffix](#input\_add\_bucket\_name\_suffix) | Whether to add a generated 4-character suffix to the created Security and Compliance Center Object Storage bucket name. Applies only if not specifying an existing bucket. Set to `false` not to add the suffix to the bucket name in the `scc_cos_bucket_name` variable. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `true` | no | +| [attachments](#input\_attachments) | A list of attachments to create. A value must be passed for 'scope\_ids' (to use pre-existing scopes) and/or 'scope\_key\_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
list(object({
profile_name = string
profile_version = string
attachment_name = string
attachment_description = string
attachment_schedule = string
scope_key_references = optional(list(string), [])
scope_ids = optional(list(string), [])
notifications = object({
enabled = optional(bool, true)
failed_control_ids = optional(list(string), [])
threshold_limit = optional(number, 10)
})
}))
| `[]` | no | +| [custom\_integrations](#input\_custom\_integrations) | A list of custom provider integrations to associate with the Security and Compliance Center instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/custom_integrations.md). |
list(object({
attributes = optional(map(string), {})
provider_name = string
integration_name = string
}))
| `[]` | no | +| [event\_notifications\_source\_description](#input\_event\_notifications\_source\_description) | Optional description to give for the Event Notifications integration source. Only used if a value is passed for `event_notifications_instance_crn`. | `string` | `null` | no | +| [event\_notifications\_source\_name](#input\_event\_notifications\_source\_name) | The source name to use for the Event Notifications integration. Required if a value is passed for `event_notifications_instance_crn`. This name must be unique per SCC instance that is integrated with the Event Notifications instance. | `string` | `"compliance"` | no | +| [existing\_cos\_instance\_crn](#input\_existing\_cos\_instance\_crn) | The CRN of an existing Object Storage instance. Not required if passing an existing SCC instance using the `existing_scc_instance_crn` input. | `string` | `null` | no | +| [existing\_event\_notifications\_crn](#input\_existing\_event\_notifications\_crn) | The CRN of an Event Notification instance. Used to integrate with Security and Compliance Center. | `string` | `null` | no | +| [existing\_kms\_instance\_crn](#input\_existing\_kms\_instance\_crn) | The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). Used to create a new KMS key unless an existing key is passed using the `existing_scc_cos_kms_key_crn` input. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. A value should not be passed passing existing SCC instance using the `existing_scc_instance_crn` input. | `string` | `null` | no | +| [existing\_kms\_key\_crn](#input\_existing\_kms\_key\_crn) | The CRN of an existing KMS key to use to encrypt the Security and Compliance Center Object Storage bucket. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key, or for the `existing_scc_cos_bucket_name` variable to use an existing bucket. | `string` | `null` | no | +| [existing\_monitoring\_crn](#input\_existing\_monitoring\_crn) | The CRN of an IBM Cloud Monitoring instance to to send Security and Compliance Object Storage bucket metrics to. If no value passed, metrics are sent to the instance associated to the container's location unless otherwise specified in the Metrics Router service configuration. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `null` | no | +| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision resource in. | `string` | `"Default"` | no | +| [existing\_scc\_instance\_crn](#input\_existing\_scc\_instance\_crn) | The CRN of an existing Security and Compliance Center instance. If not supplied, a new instance will be created. | `string` | `null` | no | +| [existing\_scc\_workload\_protection\_instance\_crn](#input\_existing\_scc\_workload\_protection\_instance\_crn) | The CRN of an existing Workload Protection instance to associate with the Security and Compliance Center instance. | `string` | `null` | no | +| [force\_delete\_kms\_key](#input\_force\_delete\_kms\_key) | If creating a new KMS key, toggle whether is should be force deleted or not on undeploy. | `bool` | `false` | no | +| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key used to provision resources. | `string` | n/a | yes | +| [ibmcloud\_kms\_api\_key](#input\_ibmcloud\_kms\_api\_key) | The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud\_api\_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Security and Compliance Centre instance. Leave this input empty if the same account owns both instances. | `string` | `null` | no | +| [kms\_encryption\_enabled\_bucket](#input\_kms\_encryption\_enabled\_bucket) | Set to true to enable KMS encryption on the Object Storage bucket created for the Security and Compliance Center instance. When set to true, a value must be passed for either `existing_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_scc_instance_crn`. | `bool` | `false` | no | +| [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_bucket` is true | `string` | `"private"` | no | +| [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"private"` | no | +| [prefix](#input\_prefix) | The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes | +| [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints). | `string` | `"private"` | no | +| [scc\_cos\_bucket\_access\_tags](#input\_scc\_cos\_bucket\_access\_tags) | The list of access tags to add to the Security and Compliance Center Object Storage bucket. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | +| [scc\_cos\_bucket\_class](#input\_scc\_cos\_bucket\_class) | The storage class of the newly provisioned Security and Compliance Center Object Storage bucket. Possible values: `standard`, `vault`, `cold`, `smart`, `onerate_active`. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes). Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"smart"` | no | +| [scc\_cos\_bucket\_name](#input\_scc\_cos\_bucket\_name) | The name for the Security and Compliance Center Object Storage bucket. Bucket names must globally unique. If `add_bucket_name_suffix` is true, a 4-character string is added to this name to ensure it's globally unique. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"scc-cos-bucket"` | no | +| [scc\_cos\_bucket\_region](#input\_scc\_cos\_bucket\_region) | The region to create the Object Storage bucket used by SCC. If not provided, the region specified in the `scc_region` input will be used. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `null` | no | +| [scc\_cos\_key\_name](#input\_scc\_cos\_key\_name) | The name for the key created for the Security and Compliance Center Object Storage bucket. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"scc-cos-key"` | no | +| [scc\_cos\_key\_ring\_name](#input\_scc\_cos\_key\_ring\_name) | The name for the key ring created for the Security and Compliance Center Object Storage bucket key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"scc-cos-key-ring"` | no | +| [scc\_event\_notifications\_email\_list](#input\_scc\_event\_notifications\_email\_list) | The list of email addresses to notify when Security and Compliance Center triggers an event. | `list(string)` | `[]` | no | +| [scc\_event\_notifications\_from\_email](#input\_scc\_event\_notifications\_from\_email) | The `from` email address used in any Security and Compliance Center events coming via Event Notifications. | `string` | `"compliancealert@ibm.com"` | no | +| [scc\_event\_notifications\_reply\_to\_email](#input\_scc\_event\_notifications\_reply\_to\_email) | The `reply_to` email address used in any Security and Compliance Center events coming via Event Notifications. | `string` | `"no-reply@ibm.com"` | no | +| [scc\_instance\_access\_tags](#input\_scc\_instance\_access\_tags) | The list of access tags to add to the Security and Compliance Center instance. | `list(string)` | `[]` | no | +| [scc\_instance\_cbr\_rules](#input\_scc\_instance\_cbr\_rules) | (Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/DA-cbr_rules.md). |
list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | +| [scc\_instance\_name](#input\_scc\_instance\_name) | The name for the Security and Compliance Center instance provisioned by this solution. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"scc"` | no | +| [scc\_instance\_resource\_tags](#input\_scc\_instance\_resource\_tags) | The list of tags to add to the Security and Compliance Center instance. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | +| [scc\_region](#input\_scc\_region) | The region to provision Security and Compliance Center resources in. If passing a value for `existing_scc_instance_crn`, ensure to select the region of the existing instance. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"us-south"` | no | +| [scc\_service\_plan](#input\_scc\_service\_plan) | The pricing plan to use when creating a new Security Compliance Center instance. Possible values: `security-compliance-center-standard-plan`, `security-compliance-center-trial-plan`. | `string` | `"security-compliance-center-standard-plan"` | no | +| [scopes](#input\_scopes) | A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope\_key\_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md). |
map(object({
name = string
description = string
environment = optional(string, "ibm-cloud")
properties = object({
scope_id = string
scope_type = string
})
exclusions = optional(list(object({
scope_id = string
scope_type = string
})), [])
}))
| `{}` | no | +| [skip\_cos\_kms\_iam\_auth\_policy](#input\_skip\_cos\_kms\_iam\_auth\_policy) | Set to `true` to skip the creation of an IAM authorization policy that permits the Object Storage instance created to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `false` | no | +| [skip\_scc\_cos\_iam\_auth\_policy](#input\_skip\_scc\_cos\_iam\_auth\_policy) | Set to `true` to skip creation of an IAM authorization policy that permits the Security and Compliance Center to write to the Object Storage instance created by this solution. Applies only if `existing_scc_instance_crn` is not provided. | `bool` | `false` | no | +| [skip\_scc\_workload\_protection\_iam\_auth\_policy](#input\_skip\_scc\_workload\_protection\_iam\_auth\_policy) | Set to `true` to skip creating an IAM authorization policy that permits the Security and Compliance Center instance to read from the Workload Protection instance. Applies only if a value is passed for `existing_scc_workload_protection_instance_crn`. | `bool` | `false` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [resource\_group\_id](#output\_resource\_group\_id) | Resource group ID | +| [resource\_group\_name](#output\_resource\_group\_name) | Resource group name | +| [scc\_cos\_bucket\_config](#output\_scc\_cos\_bucket\_config) | List of buckets created | +| [scc\_cos\_bucket\_name](#output\_scc\_cos\_bucket\_name) | SCC COS bucket name | +| [scc\_cos\_instance\_crn](#output\_scc\_cos\_instance\_crn) | SCC COS instance CRN | +| [scc\_cos\_kms\_key\_crn](#output\_scc\_cos\_kms\_key\_crn) | SCC COS KMS Key CRN | +| [scc\_crn](#output\_scc\_crn) | SCC instance CRN | +| [scc\_guid](#output\_scc\_guid) | SCC instance guid | +| [scc\_id](#output\_scc\_id) | SCC instance ID | +| [scc\_name](#output\_scc\_name) | SCC instance name | + diff --git a/solutions/security-enforced/catalogValidationValues.json.template b/solutions/security-enforced/catalogValidationValues.json.template new file mode 100644 index 0000000..cc38ce8 --- /dev/null +++ b/solutions/security-enforced/catalogValidationValues.json.template @@ -0,0 +1,7 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "prefix": $PREFIX, + "existing_resource_group_name": "geretain-test-resources", + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "existing_cos_instance_crn": $COS_INSTANCE_CRN +} diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf new file mode 100644 index 0000000..f167818 --- /dev/null +++ b/solutions/security-enforced/main.tf @@ -0,0 +1,88 @@ +####################################################################################################################### +# Parse regions from CRNs to use in provider config +####################################################################################################################### + +module "existing_scc_crn_parser" { + count = var.existing_scc_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_scc_instance_crn +} + +module "existing_kms_crn_parser" { + count = var.existing_kms_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_kms_instance_crn +} + +module "existing_kms_key_crn_parser" { + count = var.existing_kms_key_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_kms_key_crn +} + +module "existing_en_crn_parser" { + count = var.existing_event_notifications_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_event_notifications_crn +} + +locals { + provider_visibility = "private" + scc_instance_region = var.existing_scc_instance_crn == null ? var.scc_region : module.existing_scc_crn_parser[0].region + kms_region = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].region : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].region : + scc_cos_bucket_region = var.scc_cos_bucket_region != null && var.scc_cos_bucket_region != "" ? var.scc_cos_bucket_region : var.scc_region + existing_en_region = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].region : null +} + +####################################################################################################################### +# Wrapper around fully-configurable variation +####################################################################################################################### + +module "scc_da" { + source = "../fully-configurable" + ibmcloud_api_key = var.ibmcloud_api_key + existing_resource_group_name = var.existing_resource_group_name + prefix = var.prefix + provider_visibility = local.provider_visibility + scc_instance_name = var.scc_instance_name + scc_region = var.scc_region + scc_service_plan = var.scc_service_plan + scc_instance_resource_tags = var.scc_instance_resource_tags + scc_instance_access_tags = var.scc_instance_access_tags + existing_scc_instance_crn = var.existing_scc_instance_crn + custom_integrations = var.custom_integrations + scopes= var.scopes + attachments = var.attachments + existing_scc_workload_protection_instance_crn = var.existing_scc_workload_protection_instance_crn + skip_scc_workload_protection_iam_auth_policy = var.skip_scc_workload_protection_iam_auth_policy + kms_encryption_enabled_bucket = true + existing_kms_instance_crn = var.existing_kms_instance_crn + force_delete_kms_key = var.force_delete_kms_key + existing_kms_key_crn = var.existing_kms_key_crn + kms_endpoint_type = "private" + scc_cos_key_ring_name = var.scc_cos_key_ring_name + scc_cos_key_name = var.scc_cos_key_name + ibmcloud_kms_api_key = var.ibmcloud_kms_api_key + existing_cos_instance_crn = var.existing_cos_instance_crn + scc_cos_bucket_region = var.scc_cos_bucket_region + scc_cos_bucket_name = var.scc_cos_bucket_name + add_bucket_name_suffix = var.add_bucket_name_suffix + scc_cos_bucket_access_tags = var.scc_cos_bucket_access_tags + scc_cos_bucket_class = var.scc_cos_bucket_class + skip_scc_cos_iam_auth_policy = var.skip_scc_cos_iam_auth_policy + skip_cos_kms_iam_auth_policy = var.skip_cos_kms_iam_auth_policy + management_endpoint_type_for_bucket = "private" + existing_monitoring_crn = var.existing_monitoring_crn + existing_event_notifications_crn = var.existing_event_notifications_crn + event_notifications_source_name = var.event_notifications_source_name + event_notifications_source_description = var.event_notifications_source_description + scc_event_notifications_from_email = var.scc_event_notifications_from_email + scc_event_notifications_reply_to_email = var.scc_event_notifications_reply_to_email + scc_event_notifications_email_list = var.scc_event_notifications_email_list + scc_instance_cbr_rules = var.scc_instance_cbr_rules +} + diff --git a/solutions/security-enforced/outputs.tf b/solutions/security-enforced/outputs.tf new file mode 100644 index 0000000..09cdd24 --- /dev/null +++ b/solutions/security-enforced/outputs.tf @@ -0,0 +1,57 @@ +######################################################################################################################## +# Outputs +######################################################################################################################## + +output "resource_group_name" { + description = "Resource group name" + value = module.scc_da.resource_group_name +} + +output "resource_group_id" { + description = "Resource group ID" + value = module.scc_da.resource_group_id +} + +output "scc_id" { + description = "SCC instance ID" + value = module.scc_da.scc_id +} + +output "scc_guid" { + description = "SCC instance guid" + value = module.scc_da.scc_guid +} + +output "scc_crn" { + description = "SCC instance CRN" + value = module.scc_da.scc_crn +} + +output "scc_name" { + description = "SCC instance name" + value = module.scc_da.scc_name +} + +######################################################################################################################## +# SCC COS +######################################################################################################################## + +output "scc_cos_kms_key_crn" { + description = "SCC COS KMS Key CRN" + value = module.scc_da.scc_cos_kms_key_crn +} + +output "scc_cos_bucket_name" { + description = "SCC COS bucket name" + value = module.scc_da.scc_cos_bucket_name +} + +output "scc_cos_bucket_config" { + description = "List of buckets created" + value = module.scc_da.scc_cos_bucket_config +} + +output "scc_cos_instance_crn" { + description = "SCC COS instance CRN" + value = module.scc_da.scc_cos_instance_crn +} diff --git a/solutions/security-enforced/provider.tf b/solutions/security-enforced/provider.tf new file mode 100644 index 0000000..abd3cb4 --- /dev/null +++ b/solutions/security-enforced/provider.tf @@ -0,0 +1,30 @@ +######################################################################################################################## +# Provider config +######################################################################################################################## + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = local.scc_instance_region + visibility = local.provider_visibility +} + +provider "ibm" { + alias = "kms" + ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key + region = local.kms_region + visibility = local.provider_visibility +} + +provider "ibm" { + alias = "cos" + ibmcloud_api_key = var.ibmcloud_api_key + region = local.scc_cos_bucket_region + visibility = local.provider_visibility +} + +provider "ibm" { + alias = "en" + ibmcloud_api_key = var.ibmcloud_api_key + region = local.existing_en_region + visibility = local.provider_visibility +} diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf new file mode 100644 index 0000000..10bc806 --- /dev/null +++ b/solutions/security-enforced/variables.tf @@ -0,0 +1,365 @@ +######################################################################################################################## +# Common variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API key used to provision resources." + sensitive = true +} + +variable "existing_resource_group_name" { + type = string + description = "The name of an existing resource group to provision resource in." + default = "Default" +} + +variable "prefix" { + type = string + description = "The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To not use any prefix value, you can set this value to `null` or an empty string." + nullable = true + validation { + condition = (var.prefix == null ? true : + alltrue([ + can(regex("^[a-z]{0,1}[-a-z0-9]{0,14}[a-z0-9]{0,1}$", var.prefix)), + length(regexall("^.*--.*", var.prefix)) == 0 + ]) + ) + error_message = "Prefix must begin with a lowercase letter, contain only lowercase letters, numbers, and - characters. Prefixes must end with a lowercase letter or number and be 16 or fewer characters." + } +} + +######################################################################################################################## +# SCC variables +######################################################################################################################## + +variable "scc_instance_name" { + type = string + default = "scc" + description = "The name for the Security and Compliance Center instance provisioned by this solution. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_region" { + type = string + default = "us-south" + description = "The region to provision Security and Compliance Center resources in. If passing a value for `existing_scc_instance_crn`, ensure to select the region of the existing instance. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_service_plan" { + type = string + description = "The pricing plan to use when creating a new Security Compliance Center instance. Possible values: `security-compliance-center-standard-plan`, `security-compliance-center-trial-plan`." + default = "security-compliance-center-standard-plan" + validation { + condition = contains(["security-compliance-center-standard-plan", "security-compliance-center-trial-plan"], var.scc_service_plan) + error_message = "Allowed values for scc_service_plan are \"security-compliance-center-standard-plan\" and \"security-compliance-center-trial-plan\"." + } +} + +variable "scc_instance_resource_tags" { + type = list(string) + description = "The list of tags to add to the Security and Compliance Center instance. Applies only if `existing_scc_instance_crn` is not provided." + default = [] +} + +variable "scc_instance_access_tags" { + type = list(string) + description = "The list of access tags to add to the Security and Compliance Center instance." + default = [] +} + +variable "existing_scc_instance_crn" { + type = string + default = null + description = "The CRN of an existing Security and Compliance Center instance. If not supplied, a new instance will be created." +} + +variable "custom_integrations" { + type = list(object({ + attributes = optional(map(string), {}) + provider_name = string + integration_name = string + })) + description = "A list of custom provider integrations to associate with the Security and Compliance Center instance. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/custom_integrations.md)." + default = [] + # Since this list is used in a for_each, add nullable = false to prevent error if user passes null + nullable = false +} + +variable "scopes" { + type = map(object({ + name = string + description = string + environment = optional(string, "ibm-cloud") + properties = object({ + scope_id = string + scope_type = string + }) + exclusions = optional(list(object({ + scope_id = string + scope_type = string + })), []) + })) + default = {} + nullable = false + description = "A key map of scopes to create. The key name of each scope can be referenced in the attachments input using the 'scope_key_references' attribute. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md)." +} + +variable "attachments" { + type = list(object({ + profile_name = string + profile_version = string + attachment_name = string + attachment_description = string + attachment_schedule = string + scope_key_references = optional(list(string), []) + scope_ids = optional(list(string), []) + notifications = object({ + enabled = optional(bool, true) + failed_control_ids = optional(list(string), []) + threshold_limit = optional(number, 10) + }) + })) + default = [] + description = "A list of attachments to create. A value must be passed for 'scope_ids' (to use pre-existing scopes) and/or 'scope_key_references' (to use scopes created in the 'scopes' input). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/scopes_attachments.md)." + + validation { + condition = alltrue([for attachments in var.attachments : + length(attachments.scope_ids) > 0 || length(attachments.scope_key_references) > 0 + ]) + error_message = "At least one value needs to be added to the 'scope_ids' or 'scope_key_references' list inputs." + } + # TODO: Add validation to validate values in scope_key_references match the key identifier in the keys(var.scopes) +} + +######################################################################################################################## +# Workload Protection +######################################################################################################################## + +variable "existing_scc_workload_protection_instance_crn" { + type = string + description = "The CRN of an existing Workload Protection instance to associate with the Security and Compliance Center instance." + default = null +} + +variable "skip_scc_workload_protection_iam_auth_policy" { + type = bool + default = false + description = "Set to `true` to skip creating an IAM authorization policy that permits the Security and Compliance Center instance to read from the Workload Protection instance. Applies only if a value is passed for `existing_scc_workload_protection_instance_crn`." +} + +######################################################################################################################## +# KMS variables +######################################################################################################################## + +variable "existing_kms_instance_crn" { + type = string + default = null + description = "The CRN of an existing KMS instance (Hyper Protect Crypto Services or Key Protect). Used to create a new KMS key unless an existing key is passed using the `existing_scc_cos_kms_key_crn` input. If the KMS instance is in different account you must also provide a value for `ibmcloud_kms_api_key`. A value should not be passed passing existing SCC instance using the `existing_scc_instance_crn` input." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}::$", var.existing_kms_instance_crn)), + var.existing_kms_instance_crn == null, + ]) + error_message = "The provided KMS instance CRN in the input 'existing_kms_instance_crn' in not valid." + } + + validation { + condition = var.existing_kms_instance_crn != null ? var.existing_scc_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." + } +} + +variable "force_delete_kms_key" { + type = bool + default = false + description = "If creating a new KMS key, toggle whether is should be force deleted or not on undeploy." +} + +variable "existing_kms_key_crn" { + type = string + default = null + description = "The CRN of an existing KMS key to use to encrypt the Security and Compliance Center Object Storage bucket. If no value is set for this variable, specify a value for either the `existing_kms_instance_crn` variable to create a key ring and key, or for the `existing_scc_cos_bucket_name` variable to use an existing bucket." + + validation { + condition = anytrue([ + can(regex("^crn:(.*:){3}(kms|hs-crypto):(.*:){2}[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}:key:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", var.existing_kms_key_crn)), + var.existing_kms_key_crn == null, + ]) + error_message = "The provided KMS key CRN in the input 'existing_kms_key_crn' in not valid." + } + + validation { + condition = var.existing_kms_key_crn != null ? var.existing_scc_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_key_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." + } + + validation { + condition = var.existing_kms_key_crn != null ? var.existing_kms_instance_crn == null : true + error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing key value using the 'existing_kms_key_crn' input." + } + +} + +variable "scc_cos_key_ring_name" { + type = string + default = "scc-cos-key-ring" + description = "The name for the key ring created for the Security and Compliance Center Object Storage bucket key. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "scc_cos_key_name" { + type = string + default = "scc-cos-key" + description = "The name for the key created for the Security and Compliance Center Object Storage bucket. Applies only if not specifying an existing key. If a prefix input variable is specified, the prefix is added to the name in the `-` format." +} + +variable "ibmcloud_kms_api_key" { + type = string + description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Security and Compliance Centre instance. Leave this input empty if the same account owns both instances." + sensitive = true + default = null + + validation { + condition = var.ibmcloud_kms_api_key != null ? var.existing_scc_instance_crn == null : true + error_message = "A value should not be passed for 'ibmcloud_kms_api_key' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." + } +} + +######################################################################################################################## +# COS variables +######################################################################################################################## + +variable "existing_cos_instance_crn" { + type = string + nullable = true + default = null + description = "The CRN of an existing Object Storage instance. Not required if passing an existing SCC instance using the `existing_scc_instance_crn` input." + + validation { + condition = var.existing_cos_instance_crn == null ? var.existing_scc_instance_crn != null : true + error_message = "A value must be passed for 'existing_cos_instance_crn' when creating a new instance." + } +} + +variable "scc_cos_bucket_region" { + type = string + default = null + description = "The region to create the Object Storage bucket used by SCC. If not provided, the region specified in the `scc_region` input will be used. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_cos_bucket_name" { + type = string + default = "scc-cos-bucket" + description = "The name for the Security and Compliance Center Object Storage bucket. Bucket names must globally unique. If `add_bucket_name_suffix` is true, a 4-character string is added to this name to ensure it's globally unique. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "add_bucket_name_suffix" { + type = bool + description = "Whether to add a generated 4-character suffix to the created Security and Compliance Center Object Storage bucket name. Applies only if not specifying an existing bucket. Set to `false` not to add the suffix to the bucket name in the `scc_cos_bucket_name` variable. Applies only if `existing_scc_instance_crn` is not provided." + default = true +} + +variable "scc_cos_bucket_access_tags" { + type = list(string) + default = [] + description = "The list of access tags to add to the Security and Compliance Center Object Storage bucket. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "scc_cos_bucket_class" { + type = string + default = "smart" + description = "The storage class of the newly provisioned Security and Compliance Center Object Storage bucket. Possible values: `standard`, `vault`, `cold`, `smart`, `onerate_active`. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes). Applies only if `existing_scc_instance_crn` is not provided." + validation { + condition = contains(["standard", "vault", "cold", "smart", "onerate_active"], var.scc_cos_bucket_class) + error_message = "Allowed values for cos_bucket_class are \"standard\", \"vault\",\"cold\", \"smart\", or \"onerate_active\"." + } +} + +variable "skip_scc_cos_iam_auth_policy" { + type = bool + default = false + description = "Set to `true` to skip creation of an IAM authorization policy that permits the Security and Compliance Center to write to the Object Storage instance created by this solution. Applies only if `existing_scc_instance_crn` is not provided." +} + +variable "skip_cos_kms_iam_auth_policy" { + type = bool + description = "Set to `true` to skip the creation of an IAM authorization policy that permits the Object Storage instance created to read the encryption key from the KMS instance. If set to false, pass in a value for the KMS instance in the `existing_kms_instance_crn` variable. If a value is specified for `ibmcloud_kms_api_key`, the policy is created in the KMS account. Applies only if `existing_scc_instance_crn` is not provided." + default = false +} + +variable "existing_monitoring_crn" { + type = string + nullable = true + default = null + description = "The CRN of an IBM Cloud Monitoring instance to to send Security and Compliance Object Storage bucket metrics to. If no value passed, metrics are sent to the instance associated to the container's location unless otherwise specified in the Metrics Router service configuration. Applies only if `existing_scc_instance_crn` is not provided." +} + +######################################################################################################################## +# Event Notifications +######################################################################################################################## + +variable "existing_event_notifications_crn" { + type = string + nullable = true + default = null + description = "The CRN of an Event Notification instance. Used to integrate with Security and Compliance Center." + + validation { + condition = var.existing_event_notifications_crn != null ? var.existing_scc_instance_crn == null : true + error_message = "You cannot pass a value for 'existing_event_notifications_crn' when passing a value for 'existing_scc_instance_crn'. Event Notifications integration can only be configured when creating a new instance." + } +} + +variable "event_notifications_source_name" { + type = string + default = "compliance" + description = "The source name to use for the Event Notifications integration. Required if a value is passed for `event_notifications_instance_crn`. This name must be unique per SCC instance that is integrated with the Event Notifications instance." +} + +variable "event_notifications_source_description" { + type = string + default = null + description = "Optional description to give for the Event Notifications integration source. Only used if a value is passed for `event_notifications_instance_crn`." +} + +variable "scc_event_notifications_from_email" { + type = string + description = "The `from` email address used in any Security and Compliance Center events coming via Event Notifications." + default = "compliancealert@ibm.com" +} + +variable "scc_event_notifications_reply_to_email" { + type = string + description = "The `reply_to` email address used in any Security and Compliance Center events coming via Event Notifications." + default = "no-reply@ibm.com" +} + +variable "scc_event_notifications_email_list" { + type = list(string) + description = "The list of email addresses to notify when Security and Compliance Center triggers an event." + default = [] +} + +############################################################## +# Context-based restriction (CBR) +############################################################## + +variable "scc_instance_cbr_rules" { + type = list(object({ + description = string + account_id = string + rule_contexts = list(object({ + attributes = optional(list(object({ + name = string + value = string + }))) })) + enforcement_mode = string + operations = optional(list(object({ + api_types = list(object({ + api_type_id = string + })) + }))) + })) + description = "(Optional, list) List of context-based restrictions rules to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-scc-da/tree/main/solutions/fully-configurable/DA-cbr_rules.md)." + default = [] +} diff --git a/solutions/security-enforced/version.tf b/solutions/security-enforced/version.tf new file mode 100644 index 0000000..3f749ca --- /dev/null +++ b/solutions/security-enforced/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.9.0" + # Lock DA into an exact provider version - renovate automation will keep it updated + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.76.1" + } + time = { + source = "hashicorp/time" + version = "0.12.1" + } + } +} diff --git a/tests/go.mod b/tests/go.mod index c7d944a..27a6f40 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -7,7 +7,7 @@ toolchain go1.24.1 require ( github.com/gruntwork-io/terratest v0.48.2 github.com/stretchr/testify v1.10.0 - github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.46.4 + github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.46.5 ) require ( diff --git a/tests/go.sum b/tests/go.sum index 03fa26b..61ea069 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -295,8 +295,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.46.4 h1:TAgMlJ8DUWLVsmLK96TGRd5z4OLYfVapymDk7ZjuZFQ= -github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.46.4/go.mod h1:ipDwW41ga+aPO/46HXJ9oNhcSrQsbMaPLiBHUBo1Viw= +github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.46.5 h1:6WDDFRfY/l+KyVPa+Aq/LiXv7lGhFMtvlwSsEWvJYjo= +github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.46.5/go.mod h1:ipDwW41ga+aPO/46HXJ9oNhcSrQsbMaPLiBHUBo1Viw= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmccombs/hcl2json v0.6.4 h1:/FWnzS9JCuyZ4MNwrG4vMrFrzRgsWEOVi+1AyYUVLGw= github.com/tmccombs/hcl2json v0.6.4/go.mod h1:+ppKlIW3H5nsAsZddXPy2iMyvld3SHxyjswOZhavRDk= diff --git a/tests/other_test.go b/tests/other_test.go index c84f79f..8892ce1 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -1,15 +1,49 @@ package test import ( + "math/rand" "testing" "github.com/stretchr/testify/assert" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" ) -func TestRunCompleteExample(t *testing.T) { +const basicExampleDir = "examples/basic" +const advancedExampleDir = "examples/advanced" + +func TestRunBasicExample(t *testing.T) { + t.Parallel() + + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: basicExampleDir, + Prefix: "scc-bsc", + ResourceGroup: resourceGroup, + Region: validRegions[rand.Intn(len(validRegions))], + TerraformVars: map[string]interface{}{ + "access_tags": permanentResources["accessTags"], + }, + }) + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} + +func TestRunAdvancedExample(t *testing.T) { t.Parallel() - options := setupCompleteExampleOptions(t, "scc-cmp", completeExampleDir) + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: advancedExampleDir, + Prefix: "scc-adv", + Region: validRegions[rand.Intn(len(validRegions))], + /* + To prevent clashes, comment out the 'ResourceGroup' input in the tests to create a unique resource group, + as only one instance of Event Notification (Lite) is allowed per resource group. + */ + //ResourceGroup: resourceGroup, + }) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") diff --git a/tests/pr_test.go b/tests/pr_test.go index 4104fa8..b7b685b 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -1,4 +1,4 @@ -// Tests in this file are run in the PR pipeline and the continuous testing pipeline +// Tests in this file are run in the PR pipeline package test import ( @@ -13,20 +13,36 @@ import ( "github.com/gruntwork-io/terratest/modules/logger" "github.com/gruntwork-io/terratest/modules/random" "github.com/gruntwork-io/terratest/modules/terraform" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/common" - "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testschematic" ) -const resourceGroup = "geretain-test-resources" // Use existing resource group -const basicExampleDir = "examples/basic" -const completeExampleDir = "examples/complete" +const resourceGroup = "geretain-test-resources" +const fullyConfigFlavorDir = "solutions/fully-configurable" + +// Define a struct with fields that match the structure of the YAML data const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" +// Combined list of supported SCC and EN regions +var validRegions = []string{ + "us-south", + "eu-de", + "us-es", +} + var permanentResources map[string]interface{} +// Common variables re-used across tests +var preReqDir = "./resources/prereq-resources" +var customIntegrations = []map[string]interface{}{{"provider_name": "Caveonix", "integration_name": "caveonix-integration"}} +var scopeKey = "all" + +// NOTE: Currently scope is hard coded to GoldenEye Dev account +var scopes = map[string]interface{}{scopeKey: map[string]interface{}{"name": "Full account", "description": "Created by SCC DA test", "environment": "ibm-cloud", "properties": map[string]interface{}{"scope_id": "abac0df06b644a9cabc6e44f55b3880e", "scope_type": "account"}}} +var attachments = []map[string]interface{}{{"profile_name": "SOC 2", "profile_version": "latest", "attachment_name": "SOC 2", "attachment_description": "Created by SCC DA test", "attachment_schedule": "none", "scope_key_references": []string{scopeKey}, "notifications": map[string]interface{}{"enabled": "false"}}} + func TestMain(m *testing.M) { // Read the YAML file contents var err error @@ -38,81 +54,199 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func setupBasicExampleOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { - options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ - Testing: t, - TerraformDir: dir, - Prefix: prefix, - ResourceGroup: resourceGroup, - BestRegionYAMLPath: "../common-dev-assets/common-go-assets/cloudinfo-region-scc-prefs.yaml", - TerraformVars: map[string]interface{}{ - "access_tags": permanentResources["accessTags"], +func TestFullyConfigurable(t *testing.T) { + t.Parallel() + + var region = validRegions[rand.Intn(len(validRegions))] + + // ------------------------------------------------------------------------------------ + // Provision COS, Sysdig, WP and EN first + // ------------------------------------------------------------------------------------ + + prefix := fmt.Sprintf("scc-da-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := preReqDir + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) + tags := common.GetTagsFromTravis() + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir, + Vars: map[string]interface{}{ + "prefix": prefix, + "region": region, + "resource_tags": tags, }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, }) - return options -} -func setupCompleteExampleOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { - // Use a region that is supported for both Event Notifications and SCC - validRegions := []string{ - "us-south", - "eu-de", - "eu-es", + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of pre-req resources failed in TestFullyConfigurable test") + } else { + // ------------------------------------------------------------------------------------ + // Deploy DA + // ------------------------------------------------------------------------------------ + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: prefix, + TarIncludePatterns: []string{ + fullyConfigFlavorDir + "/*.tf", + }, + TemplateFolder: fullyConfigFlavorDir, + Tags: []string{"scc-da-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, + {Name: "scc_region", Value: terraform.Output(t, existingTerraformOptions, "region"), DataType: "string"}, + {Name: "scc_instance_resource_tags", Value: options.Tags, DataType: "list(string)"}, + {Name: "scc_instance_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "scc_cos_bucket_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "prefix", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_cos_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "cos_crn"), DataType: "string"}, + {Name: "existing_scc_workload_protection_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "wp_crn"), DataType: "string"}, + {Name: "existing_event_notifications_crn", Value: terraform.Output(t, existingTerraformOptions, "en_crn"), DataType: "string"}, + {Name: "event_notifications_source_name", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_monitoring_crn", Value: terraform.Output(t, existingTerraformOptions, "monitoring_crn"), DataType: "string"}, + {Name: "custom_integrations", Value: customIntegrations, DataType: "list(object)"}, + {Name: "scopes", Value: scopes, DataType: "map(object)"}, + {Name: "attachments", Value: attachments, DataType: "list(object)"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (prereq resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (prereq resources)") } - options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ - Testing: t, - TerraformDir: dir, - Prefix: prefix, - Region: validRegions[rand.Intn(len(validRegions))], - /* - To prevent clashes, comment out the 'ResourceGroup' input in the tests to create a unique resource group, - as only one instance of Event Notification (Lite) is allowed per resource group. - */ - //ResourceGroup: resourceGroup, - }) - return options } -func TestRunBasicExample(t *testing.T) { +func TestUpgradeFullyConfigurable(t *testing.T) { t.Parallel() - options := setupBasicExampleOptions(t, "scc", basicExampleDir) + var region = validRegions[rand.Intn(len(validRegions))] - output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") -} + // ------------------------------------------------------------------------------------ + // Provision COS, Sysdig, WP and EN first + // ------------------------------------------------------------------------------------ -func TestRunCompleteExampleUpgrade(t *testing.T) { - t.Parallel() + prefix := fmt.Sprintf("scc-da-upg-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := preReqDir + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) + tags := common.GetTagsFromTravis() - options := setupCompleteExampleOptions(t, "scc-upg", completeExampleDir) + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") - output, err := options.RunTestUpgrade() - if !options.UpgradeTestSkipped { - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir, + Vars: map[string]interface{}{ + "prefix": prefix, + "region": region, + "resource_tags": tags, + }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, + }) + + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of pre-req resources failed in TestFullyConfigurableUpgrade test") + } else { + // ------------------------------------------------------------------------------------ + // Deploy DA + // ------------------------------------------------------------------------------------ + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: prefix, + TarIncludePatterns: []string{ + "*.tf", + fullyConfigFlavorDir + "/*.tf", + }, + TemplateFolder: fullyConfigFlavorDir, + Tags: []string{"scc-da-upg-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, + {Name: "scc_region", Value: terraform.Output(t, existingTerraformOptions, "region"), DataType: "string"}, + {Name: "scc_instance_resource_tags", Value: options.Tags, DataType: "list(string)"}, + {Name: "scc_instance_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "scc_cos_bucket_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "prefix", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_cos_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "cos_crn"), DataType: "string"}, + {Name: "existing_scc_workload_protection_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "wp_crn"), DataType: "string"}, + {Name: "existing_event_notifications_crn", Value: terraform.Output(t, existingTerraformOptions, "en_crn"), DataType: "string"}, + {Name: "event_notifications_source_name", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_monitoring_crn", Value: terraform.Output(t, existingTerraformOptions, "monitoring_crn"), DataType: "string"}, + {Name: "custom_integrations", Value: customIntegrations, DataType: "list(object)"}, + {Name: "scopes", Value: scopes, DataType: "map(object)"}, + {Name: "attachments", Value: attachments, DataType: "list(object)"}, + } + + err := options.RunSchematicUpgradeTest() + if !options.UpgradeTestSkipped { + assert.Nil(t, err, "This should not have errored") + } + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (prereq resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (prereq resources)") } } -// A test to pass existing SCC instances to complete example -func TestRunExistingResourcesInstances(t *testing.T) { +// A test to pass existing resources to the Fully configurable DA variation +func TestExistingResourcesFullyConfigurable(t *testing.T) { t.Parallel() - // ------------------------------------------------------------------------------------ - // Provision SCC instance and configure COS setting + // Provision SCC, and WP first // ------------------------------------------------------------------------------------ - prefix := fmt.Sprintf("scc-existing-%s", strings.ToLower(random.UniqueId())) - realTerraformDir := ".." + prefix := fmt.Sprintf("scc-exist-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := "./resources/existing-resources-test" tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) tags := common.GetTagsFromTravis() - validRegions := []string{ - "us-south", - "eu-de", - "eu-es", - } - region := validRegions[rand.Intn(len(validRegions))] + region := "us-south" // Verify ibmcloud_api_key variable is set checkVariable := "TF_VAR_ibmcloud_api_key" @@ -122,7 +256,7 @@ func TestRunExistingResourcesInstances(t *testing.T) { logger.Log(t, "Tempdir: ", tempTerraformDir) existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ - TerraformDir: tempTerraformDir + "/tests/existing-resources", + TerraformDir: tempTerraformDir, Vars: map[string]interface{}{ "prefix": prefix, "region": region, @@ -140,26 +274,37 @@ func TestRunExistingResourcesInstances(t *testing.T) { } else { // ------------------------------------------------------------------------------------ - // Deploy complete example using existing SCC instance + // Deploy DA passing existing SCC instance and WP instance // ------------------------------------------------------------------------------------ - - options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ - Testing: t, - TerraformDir: completeExampleDir, - // Do not hard fail the test if the implicit destroy steps fail to allow a full destroy of resource to occur - ImplicitRequired: false, - Region: region, - TerraformVars: map[string]interface{}{ - "region": region, - "resource_group": terraform.Output(t, existingTerraformOptions, "resource_group_name"), - "existing_scc_instance_crn": terraform.Output(t, existingTerraformOptions, "crn"), - "prefix": terraform.Output(t, existingTerraformOptions, "prefix"), + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: prefix, + TarIncludePatterns: []string{ + "*.tf", + fullyConfigFlavorDir + "/*.tf", }, + TemplateFolder: fullyConfigFlavorDir, + Tags: []string{"scc-da-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, }) - output, err := options.RunTestConsistency() + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, + {Name: "scc_region", Value: terraform.Output(t, existingTerraformOptions, "region"), DataType: "string"}, + {Name: "scc_instance_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "prefix", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_scc_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "scc_crn"), DataType: "string"}, + {Name: "existing_scc_workload_protection_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "wp_crn"), DataType: "string"}, + {Name: "custom_integrations", Value: customIntegrations, DataType: "list(object)"}, + {Name: "scopes", Value: scopes, DataType: "map(object)"}, + {Name: "attachments", Value: attachments, DataType: "list(object)"}, + } + + err := options.RunSchematicTest() assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") } diff --git a/tests/resources/existing-resources-test/README.md b/tests/resources/existing-resources-test/README.md new file mode 100644 index 0000000..4bb3621 --- /dev/null +++ b/tests/resources/existing-resources-test/README.md @@ -0,0 +1 @@ +The terraform code in this directory is used by the existing resource test in tests/pr_test.go diff --git a/tests/resources/existing-resources-test/main.tf b/tests/resources/existing-resources-test/main.tf new file mode 100644 index 0000000..e0712e0 --- /dev/null +++ b/tests/resources/existing-resources-test/main.tf @@ -0,0 +1,53 @@ +############################################################################## +# Resource Group +############################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +############################################################################## +# COS +############################################################################## + +module "cos" { + source = "terraform-ibm-modules/cos/ibm" + version = "8.20.1" + cos_instance_name = "${var.prefix}-cos" + kms_encryption_enabled = false + retention_enabled = false + resource_group_id = module.resource_group.resource_group_id + bucket_name = "${var.prefix}-scc" +} + +############################################################################## +# SCC +############################################################################## + +module "scc" { + source = "terraform-ibm-modules/scc/ibm" + version = "2.0.1" + instance_name = var.prefix + region = var.region + resource_group_id = module.resource_group.resource_group_id + resource_tags = var.resource_tags + cos_bucket = module.cos.bucket_name + cos_instance_crn = module.cos.cos_instance_id +} + +############################################################################## +# Workload Protection +############################################################################## + +module "scc_wp" { + source = "terraform-ibm-modules/scc-workload-protection/ibm" + version = "1.4.3" + name = var.prefix + region = var.region + resource_group_id = module.resource_group.resource_group_id + resource_tags = var.resource_tags +} diff --git a/tests/resources/existing-resources-test/outputs.tf b/tests/resources/existing-resources-test/outputs.tf new file mode 100644 index 0000000..f8f72a4 --- /dev/null +++ b/tests/resources/existing-resources-test/outputs.tf @@ -0,0 +1,28 @@ +############################################################################## +# Outputs +############################################################################## + +output "resource_group_name" { + description = "Resource group name" + value = module.resource_group.resource_group_name +} + +output "prefix" { + value = var.prefix + description = "Prefix" +} + +output "region" { + value = var.region + description = "region" +} + +output "scc_crn" { + description = "Workload Protection CRN" + value = module.scc.crn +} + +output "wp_crn" { + description = "Workload Protection CRN" + value = module.scc_wp.crn +} diff --git a/tests/resources/existing-resources-test/provider.tf b/tests/resources/existing-resources-test/provider.tf new file mode 100644 index 0000000..df45ef5 --- /dev/null +++ b/tests/resources/existing-resources-test/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/tests/resources/existing-resources-test/variables.tf b/tests/resources/existing-resources-test/variables.tf new file mode 100644 index 0000000..441068e --- /dev/null +++ b/tests/resources/existing-resources-test/variables.tf @@ -0,0 +1,31 @@ +############################################################################## +# Input variables +############################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources" +} + +variable "resource_group" { + type = string + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + default = null +} + +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} diff --git a/tests/resources/existing-resources-test/version.tf b/tests/resources/existing-resources-test/version.tf new file mode 100644 index 0000000..7db4be4 --- /dev/null +++ b/tests/resources/existing-resources-test/version.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.9.0" + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.76.0" + } + } +} diff --git a/tests/resources/prereq-resources/README.md b/tests/resources/prereq-resources/README.md new file mode 100644 index 0000000..c731915 --- /dev/null +++ b/tests/resources/prereq-resources/README.md @@ -0,0 +1 @@ +The terraform code in this directory is used by the DA tests in tests/pr_test.go diff --git a/tests/resources/prereq-resources/main.tf b/tests/resources/prereq-resources/main.tf new file mode 100644 index 0000000..8986c2e --- /dev/null +++ b/tests/resources/prereq-resources/main.tf @@ -0,0 +1,65 @@ +############################################################################## +# Resource Group +############################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +############################################################################## +# Create Cloud Object Storage instance and a bucket +############################################################################## + +module "cos" { + source = "terraform-ibm-modules/cos/ibm" + version = "8.19.5" + resource_group_id = module.resource_group.resource_group_id + cos_instance_name = "${var.prefix}-cos" + cos_tags = var.resource_tags + create_cos_bucket = false +} + +############################################################################## +# Workload Protection +############################################################################## + +module "scc_wp" { + source = "terraform-ibm-modules/scc-workload-protection/ibm" + version = "1.4.3" + name = var.prefix + region = var.region + resource_group_id = module.resource_group.resource_group_id + resource_tags = var.resource_tags +} + +############################################################################## +# Cloud Monitoring +############################################################################## + +module "cloud_monitoring" { + source = "terraform-ibm-modules/observability-instances/ibm//modules/cloud_monitoring" + version = "3.4.3" + resource_group_id = module.resource_group.resource_group_id + region = var.region + instance_name = "${var.prefix}-mon" + enable_platform_metrics = false + tags = var.resource_tags +} + +############################################################################## +# EN +############################################################################## + +module "event_notifications" { + source = "terraform-ibm-modules/event-notifications/ibm" + version = "1.18.8" + resource_group_id = module.resource_group.resource_group_id + name = "${var.prefix}-en" + tags = var.resource_tags + plan = "lite" + region = var.region +} diff --git a/tests/resources/prereq-resources/outputs.tf b/tests/resources/prereq-resources/outputs.tf new file mode 100644 index 0000000..043f09d --- /dev/null +++ b/tests/resources/prereq-resources/outputs.tf @@ -0,0 +1,43 @@ +############################################################################## +# Outputs +############################################################################## + +output "resource_group_name" { + description = "Resource group name" + value = module.resource_group.resource_group_name +} + +output "prefix" { + value = var.prefix + description = "Prefix" +} + +output "region" { + value = var.region + description = "region" +} + +output "cos_crn" { + description = "COS CRN" + value = module.cos.cos_instance_crn +} + +output "bucket_name" { + description = "Bucket name" + value = module.cos.bucket_name +} + +output "monitoring_crn" { + value = module.cloud_monitoring.crn + description = "Monitoring CRN" +} + +output "en_crn" { + description = "Event Notification CRN" + value = module.event_notifications.crn +} + +output "wp_crn" { + description = "Workload Protection CRN" + value = module.scc_wp.crn +} diff --git a/tests/resources/prereq-resources/provider.tf b/tests/resources/prereq-resources/provider.tf new file mode 100644 index 0000000..df45ef5 --- /dev/null +++ b/tests/resources/prereq-resources/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/tests/resources/prereq-resources/variables.tf b/tests/resources/prereq-resources/variables.tf new file mode 100644 index 0000000..441068e --- /dev/null +++ b/tests/resources/prereq-resources/variables.tf @@ -0,0 +1,31 @@ +############################################################################## +# Input variables +############################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources" +} + +variable "resource_group" { + type = string + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + default = null +} + +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} diff --git a/tests/resources/prereq-resources/version.tf b/tests/resources/prereq-resources/version.tf new file mode 100644 index 0000000..7db4be4 --- /dev/null +++ b/tests/resources/prereq-resources/version.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.9.0" + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.76.0" + } + } +} From 0b70708b90e599283e4bce2722cd5401e6eb306e Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Thu, 13 Mar 2025 15:57:13 +0000 Subject: [PATCH 05/11] latest --- .catalog-onboard-pipeline.yaml | 6 + .secrets.baseline | 4 +- cra-config.yaml | 9 +- cra-tf-validate-ignore-rules.json | 9 +- ibm_catalog.json | 353 ++++++++++++++++++ .../catalogValidationValues.json.template | 1 + solutions/security-enforced/README.md | 27 +- solutions/security-enforced/main.tf | 121 ++---- solutions/security-enforced/provider.tf | 31 +- solutions/security-enforced/version.tf | 8 - tests/pr_test.go | 141 ++++++- .../resources/existing-resources-test/main.tf | 6 +- tests/resources/prereq-resources/main.tf | 12 +- 13 files changed, 562 insertions(+), 166 deletions(-) diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml index e40cf05..c464f24 100644 --- a/.catalog-onboard-pipeline.yaml +++ b/.catalog-onboard-pipeline.yaml @@ -12,3 +12,9 @@ offerings: scc: instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 region: us-south + - name: security-enforced + mark_ready: true + install_type: fullstack + scc: + instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 + region: us-south diff --git a/.secrets.baseline b/.secrets.baseline index bcffaec..2fa675f 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2025-03-13T10:57:22Z", + "generated_at": "2025-03-13T14:35:20Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -110,7 +110,7 @@ "hashed_secret": "3b5bf5f75003778663c521c8c35ad277227dd4f5", "is_secret": false, "is_verified": false, - "line_number": 43, + "line_number": 44, "type": "Hex High Entropy String", "verified_result": null } diff --git a/cra-config.yaml b/cra-config.yaml index 926f80d..2bcee72 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,6 +1,13 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "examples/basic" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - CRA_TARGET: "solutions/fully-configurable" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). + CRA_ENVIRONMENT_VARIABLES: + TF_VAR_prefix: "test" + TF_VAR_existing_resource_group_name: "Default" + TF_VAR_kms_encryption_enabled_bucket: true, + TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" + TF_VAR_existing_cos_instance_crn: "crn:v1:bluemix:public:cloud-object-storage:global:a/abac0df06b644a9cabc6e44f55b3880e:855ed836-05ce-4f39-98fa-508774f29323::" + TF_VAR_provider_visibility: "public" diff --git a/cra-tf-validate-ignore-rules.json b/cra-tf-validate-ignore-rules.json index a34dedd..adbff6e 100644 --- a/cra-tf-validate-ignore-rules.json +++ b/cra-tf-validate-ignore-rules.json @@ -1,10 +1,3 @@ { - "scc_rules": [ - { - "scc_rule_id": "rule-c97259ee-336d-4c5f-b436-1868107a9558", - "description": "Check whether Cloud Object Storage is enabled with customer-managed encryption and Keep Your Own Key (KYOK)", - "ignore_reason": "This rule is not relevant to the module itself, just the COS resource that is used in the example that is scanned", - "is_valid": false - } - ] + "scc_rules": [] } diff --git a/ibm_catalog.json b/ibm_catalog.json index e441a3e..e8e6591 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -452,6 +452,359 @@ } ] } + }, + { + "label": "Security-enforced", + "name": "security-enforced", + "install_type": "fullstack", + "working_directory": "solutions/security-enforced", + "compliance": { + "authority": "scc-v3", + "profiles": [ + { + "profile_name": "IBM Cloud Framework for Financial Services", + "profile_version": "1.7.0" + } + ] + }, + "configuration": [ + { + "key": "ibmcloud_api_key" + }, + { + "key": "prefix", + "required": true, + "description": "Prefix to add to all resources that this solution creates. To not use any prefix value, you can enter the string `__NULL__`." + }, + { + "key": "existing_resource_group_name", + "required": true, + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } + }, + { + "key": "existing_cos_instance_crn", + "required": true + }, + { + "key": "scc_service_plan", + "required": true, + "options": [ + { + "displayname": "Standard", + "value": "security-compliance-center-standard-plan" + }, + { + "displayname": "Trial", + "value": "security-compliance-center-trial-plan" + } + ] + }, + { + "key": "scc_region", + "required": true, + "options": [ + { + "displayname": "Dallas (us-south)", + "value": "us-south" + }, + { + "displayname": "Frankfurt (eu-de)", + "value": "eu-de" + }, + { + "displayname": "Madrid (eu-es)", + "value": "eu-es" + }, + { + "displayname": "Toronto (ca-tor)", + "value": "ca-tor" + } + ] + }, + { + "key": "scc_instance_name" + }, + { + "key": "scc_instance_resource_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_instance_access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "existing_scc_instance_crn" + }, + { + "key": "scopes" + }, + { + "key": "attachments" + }, + { + "key": "existing_scc_workload_protection_instance_crn" + }, + { + "key": "skip_scc_workload_protection_iam_auth_policy" + }, + { + "key": "custom_integrations" + }, + { + "key": "scc_cos_bucket_name" + }, + { + "key": "scc_cos_bucket_region", + "options": [ + { + "displayname": "Same region as SCC instance", + "value": "__NULL__" + }, + { + "displayname": "Dallas (us-south)", + "value": "us-south" + }, + { + "displayname": "Sydney (au-syd)", + "value": "au-syd" + }, + { + "displayname": "Sao Paolo (br-sao)", + "value": "br-sao" + }, + { + "displayname": "Toronto (ca-tor)", + "value": "ca-tor" + }, + { + "displayname": "Frankfurt (eu-de)", + "value": "eu-de" + }, + { + "displayname": "London (eu-gb)", + "value": "eu-gb" + }, + { + "displayname": "Madrid (eu-es)", + "value": "eu-es" + }, + { + "displayname": "Osaka (jp-osa)", + "value": "jp-osa" + }, + { + "displayname": "Tokyo (jp-tok)", + "value": "jp-tok" + }, + { + "displayname": "Washington DC (us-east)", + "value": "us-east" + } + ] + }, + { + "key": "add_bucket_name_suffix" + }, + { + "key": "scc_cos_bucket_access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "scc_cos_bucket_class", + "options": [ + { + "displayname": "Cold", + "value": "cold" + }, + { + "displayname": "Onerate active", + "value": "onerate_active" + }, + { + "displayname": "Smart", + "value": "smart" + }, + { + "displayname": "Standard", + "value": "standard" + }, + { + "displayname": "Vault", + "value": "vault" + } + ] + }, + { + "key": "existing_monitoring_crn" + }, + { + "key": "skip_scc_cos_iam_auth_policy" + }, + { + "key": "existing_kms_instance_crn" + }, + { + "key": "existing_kms_key_crn" + }, + { + "key": "ibmcloud_kms_api_key" + }, + { + "key": "skip_cos_kms_iam_auth_policy" + }, + { + "key": "scc_cos_key_ring_name" + }, + { + "key": "scc_cos_key_name" + }, + { + "key": "force_delete_kms_key" + }, + { + "key": "existing_event_notifications_crn" + }, + { + "key": "event_notifications_source_name" + }, + { + "key": "event_notifications_source_description" + }, + { + "key": "scc_event_notifications_email_list" + }, + { + "key": "scc_event_notifications_from_email" + }, + { + "key": "scc_event_notifications_reply_to_email" + }, + { + "key": "scc_instance_cbr_rules" + } + ], + "iam_permissions": [ + { + "service_name": "compliance", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Editor" + ] + }, + { + "service_name": "cloud-object-storage", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager" + ] + }, + { + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Editor" + ], + "service_name": "kms" + } + ], + "architecture": { + "descriptions": "This architecture supports creating and configuring a Security and Compliance Center instance.", + "features": [ + { + "title": "SCC instance creation", + "description": "Yes" + }, + { + "title": "Use existing SCC instance", + "description": "Yes" + }, + { + "title": "New resource group creation", + "description": "No" + }, + { + "title": "Use existing resource group", + "description": "Yes" + }, + { + "title": "COS instance creation", + "description": "No" + }, + { + "title": "COS bucket creation", + "description": "Yes" + }, + { + "title": "Enforced private-only endpoint communication", + "description": "Yes" + }, + { + "title": "Enforced KMS encryption", + "description": "Yes" + }, + { + "title": "KMS instance creation", + "description": "No" + }, + { + "title": "KMS key ring and key creation", + "description": "Yes" + }, + { + "title": "Use existing KMS key", + "description": "Yes" + }, + { + "title": "IAM s2s auth policies creation", + "description": "Yes" + }, + { + "title": "SCC scope creation", + "description": "Yes" + }, + { + "title": "SCC attachment creation", + "description": "Yes" + }, + { + "title": "Event Notifications integration", + "description": "Yes" + } + ], + "diagrams": [ + { + "diagram": { + "caption": "Security and Compliance Center", + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-scc/main/reference-architecture/scc.svg", + "type": "image/svg+xml" + }, + "description": "This architecture supports creating and configuring IBM Security and Compliance Center resources" + } + ] + } } ] } diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template index cc38ce8..252ec00 100644 --- a/solutions/fully-configurable/catalogValidationValues.json.template +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -2,6 +2,7 @@ "ibmcloud_api_key": $VALIDATION_APIKEY, "prefix": $PREFIX, "existing_resource_group_name": "geretain-test-resources", + "kms_encryption_enabled_bucket": true, "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, "existing_cos_instance_crn": $COS_INSTANCE_CRN } diff --git a/solutions/security-enforced/README.md b/solutions/security-enforced/README.md index 07f4544..54efc77 100644 --- a/solutions/security-enforced/README.md +++ b/solutions/security-enforced/README.md @@ -22,35 +22,16 @@ This solution supports provisioning and configuring the following infrastructure | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.9.0 | -| [ibm](#requirement\_ibm) | 1.76.1 | -| [time](#requirement\_time) | 0.12.1 | ### Modules | Name | Source | Version | |------|--------|---------| -| [buckets](#module\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 8.19.8 | -| [existing\_cos\_crn\_parser](#module\_existing\_cos\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | -| [existing\_en\_crn\_parser](#module\_existing\_en\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | -| [existing\_kms\_crn\_parser](#module\_existing\_kms\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | -| [existing\_kms\_key\_crn\_parser](#module\_existing\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | -| [existing\_scc\_crn\_parser](#module\_existing\_scc\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | -| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 4.21.2 | -| [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.1.6 | -| [scc](#module\_scc) | ../.. | n/a | -| [scc\_attachment](#module\_scc\_attachment) | ../../modules/attachment | n/a | +| [scc\_da](#module\_scc\_da) | ../fully-configurable | n/a | ### Resources -| Name | Type | -|------|------| -| [ibm_en_subscription_email.email_subscription](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/en_subscription_email) | resource | -| [ibm_en_topic.en_topic](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/en_topic) | resource | -| [ibm_iam_authorization_policy.cos_kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/iam_authorization_policy) | resource | -| [ibm_scc_scope.scc_scopes](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/scc_scope) | resource | -| [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | -| [time_sleep.wait_for_scc](https://registry.terraform.io/providers/hashicorp/time/0.12.1/docs/resources/sleep) | resource | -| [ibm_en_destinations.en_destinations](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/data-sources/en_destinations) | data source | +No resources. ### Inputs @@ -72,11 +53,7 @@ This solution supports provisioning and configuring the following infrastructure | [force\_delete\_kms\_key](#input\_force\_delete\_kms\_key) | If creating a new KMS key, toggle whether is should be force deleted or not on undeploy. | `bool` | `false` | no | | [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key used to provision resources. | `string` | n/a | yes | | [ibmcloud\_kms\_api\_key](#input\_ibmcloud\_kms\_api\_key) | The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud\_api\_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Security and Compliance Centre instance. Leave this input empty if the same account owns both instances. | `string` | `null` | no | -| [kms\_encryption\_enabled\_bucket](#input\_kms\_encryption\_enabled\_bucket) | Set to true to enable KMS encryption on the Object Storage bucket created for the Security and Compliance Center instance. When set to true, a value must be passed for either `existing_kms_key_crn` or `existing_kms_instance_crn` (to create a new key). Can not be set to true if passing a value for `existing_scc_instance_crn`. | `bool` | `false` | no | -| [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The endpoint for communicating with the KMS instance. Possible values: `public`, `private`. Applies only if `kms_encryption_enabled_bucket` is true | `string` | `"private"` | no | -| [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM Terraform provider to use to manage Object Storage buckets. Possible values: `public`, `private`m `direct`. If you specify `private`, enable virtual routing and forwarding in your account, and the Terraform runtime must have access to the the IBM Cloud private network. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"private"` | no | | [prefix](#input\_prefix) | The prefix to add to all resources that this solution creates (e.g `prod`, `test`, `dev`). To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes | -| [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints). | `string` | `"private"` | no | | [scc\_cos\_bucket\_access\_tags](#input\_scc\_cos\_bucket\_access\_tags) | The list of access tags to add to the Security and Compliance Center Object Storage bucket. Applies only if `existing_scc_instance_crn` is not provided. | `list(string)` | `[]` | no | | [scc\_cos\_bucket\_class](#input\_scc\_cos\_bucket\_class) | The storage class of the newly provisioned Security and Compliance Center Object Storage bucket. Possible values: `standard`, `vault`, `cold`, `smart`, `onerate_active`. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-classes). Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"smart"` | no | | [scc\_cos\_bucket\_name](#input\_scc\_cos\_bucket\_name) | The name for the Security and Compliance Center Object Storage bucket. Bucket names must globally unique. If `add_bucket_name_suffix` is true, a 4-character string is added to this name to ensure it's globally unique. If a prefix input variable is specified, the prefix is added to the name in the `-` format. Applies only if `existing_scc_instance_crn` is not provided. | `string` | `"scc-cos-bucket"` | no | diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf index f167818..2c6c978 100644 --- a/solutions/security-enforced/main.tf +++ b/solutions/security-enforced/main.tf @@ -1,88 +1,47 @@ -####################################################################################################################### -# Parse regions from CRNs to use in provider config -####################################################################################################################### - -module "existing_scc_crn_parser" { - count = var.existing_scc_instance_crn != null ? 1 : 0 - source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.1.0" - crn = var.existing_scc_instance_crn -} - -module "existing_kms_crn_parser" { - count = var.existing_kms_instance_crn != null ? 1 : 0 - source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.1.0" - crn = var.existing_kms_instance_crn -} - -module "existing_kms_key_crn_parser" { - count = var.existing_kms_key_crn != null ? 1 : 0 - source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.1.0" - crn = var.existing_kms_key_crn -} - -module "existing_en_crn_parser" { - count = var.existing_event_notifications_crn != null ? 1 : 0 - source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" - version = "1.1.0" - crn = var.existing_event_notifications_crn -} - -locals { - provider_visibility = "private" - scc_instance_region = var.existing_scc_instance_crn == null ? var.scc_region : module.existing_scc_crn_parser[0].region - kms_region = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].region : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].region : - scc_cos_bucket_region = var.scc_cos_bucket_region != null && var.scc_cos_bucket_region != "" ? var.scc_cos_bucket_region : var.scc_region - existing_en_region = var.existing_event_notifications_crn != null ? module.existing_en_crn_parser[0].region : null -} - ####################################################################################################################### # Wrapper around fully-configurable variation ####################################################################################################################### module "scc_da" { - source = "../fully-configurable" - ibmcloud_api_key = var.ibmcloud_api_key - existing_resource_group_name = var.existing_resource_group_name - prefix = var.prefix - provider_visibility = local.provider_visibility - scc_instance_name = var.scc_instance_name - scc_region = var.scc_region - scc_service_plan = var.scc_service_plan - scc_instance_resource_tags = var.scc_instance_resource_tags - scc_instance_access_tags = var.scc_instance_access_tags - existing_scc_instance_crn = var.existing_scc_instance_crn - custom_integrations = var.custom_integrations - scopes= var.scopes - attachments = var.attachments + source = "../fully-configurable" + ibmcloud_api_key = var.ibmcloud_api_key + existing_resource_group_name = var.existing_resource_group_name + prefix = var.prefix + provider_visibility = "private" + scc_instance_name = var.scc_instance_name + scc_region = var.scc_region + scc_service_plan = var.scc_service_plan + scc_instance_resource_tags = var.scc_instance_resource_tags + scc_instance_access_tags = var.scc_instance_access_tags + existing_scc_instance_crn = var.existing_scc_instance_crn + custom_integrations = var.custom_integrations + scopes = var.scopes + attachments = var.attachments existing_scc_workload_protection_instance_crn = var.existing_scc_workload_protection_instance_crn - skip_scc_workload_protection_iam_auth_policy = var.skip_scc_workload_protection_iam_auth_policy - kms_encryption_enabled_bucket = true - existing_kms_instance_crn = var.existing_kms_instance_crn - force_delete_kms_key = var.force_delete_kms_key - existing_kms_key_crn = var.existing_kms_key_crn - kms_endpoint_type = "private" - scc_cos_key_ring_name = var.scc_cos_key_ring_name - scc_cos_key_name = var.scc_cos_key_name - ibmcloud_kms_api_key = var.ibmcloud_kms_api_key - existing_cos_instance_crn = var.existing_cos_instance_crn - scc_cos_bucket_region = var.scc_cos_bucket_region - scc_cos_bucket_name = var.scc_cos_bucket_name - add_bucket_name_suffix = var.add_bucket_name_suffix - scc_cos_bucket_access_tags = var.scc_cos_bucket_access_tags - scc_cos_bucket_class = var.scc_cos_bucket_class - skip_scc_cos_iam_auth_policy = var.skip_scc_cos_iam_auth_policy - skip_cos_kms_iam_auth_policy = var.skip_cos_kms_iam_auth_policy - management_endpoint_type_for_bucket = "private" - existing_monitoring_crn = var.existing_monitoring_crn - existing_event_notifications_crn = var.existing_event_notifications_crn - event_notifications_source_name = var.event_notifications_source_name - event_notifications_source_description = var.event_notifications_source_description - scc_event_notifications_from_email = var.scc_event_notifications_from_email - scc_event_notifications_reply_to_email = var.scc_event_notifications_reply_to_email - scc_event_notifications_email_list = var.scc_event_notifications_email_list - scc_instance_cbr_rules = var.scc_instance_cbr_rules + skip_scc_workload_protection_iam_auth_policy = var.skip_scc_workload_protection_iam_auth_policy + kms_encryption_enabled_bucket = true + existing_kms_instance_crn = var.existing_kms_instance_crn + force_delete_kms_key = var.force_delete_kms_key + existing_kms_key_crn = var.existing_kms_key_crn + kms_endpoint_type = "private" + scc_cos_key_ring_name = var.scc_cos_key_ring_name + scc_cos_key_name = var.scc_cos_key_name + ibmcloud_kms_api_key = var.ibmcloud_kms_api_key + existing_cos_instance_crn = var.existing_cos_instance_crn + scc_cos_bucket_region = var.scc_cos_bucket_region + scc_cos_bucket_name = var.scc_cos_bucket_name + add_bucket_name_suffix = var.add_bucket_name_suffix + scc_cos_bucket_access_tags = var.scc_cos_bucket_access_tags + scc_cos_bucket_class = var.scc_cos_bucket_class + skip_scc_cos_iam_auth_policy = var.skip_scc_cos_iam_auth_policy + skip_cos_kms_iam_auth_policy = var.skip_cos_kms_iam_auth_policy + management_endpoint_type_for_bucket = "private" + existing_monitoring_crn = var.existing_monitoring_crn + existing_event_notifications_crn = var.existing_event_notifications_crn + event_notifications_source_name = var.event_notifications_source_name + event_notifications_source_description = var.event_notifications_source_description + scc_event_notifications_from_email = var.scc_event_notifications_from_email + scc_event_notifications_reply_to_email = var.scc_event_notifications_reply_to_email + scc_event_notifications_email_list = var.scc_event_notifications_email_list + scc_instance_cbr_rules = var.scc_instance_cbr_rules } - diff --git a/solutions/security-enforced/provider.tf b/solutions/security-enforced/provider.tf index abd3cb4..4c6add2 100644 --- a/solutions/security-enforced/provider.tf +++ b/solutions/security-enforced/provider.tf @@ -1,30 +1 @@ -######################################################################################################################## -# Provider config -######################################################################################################################## - -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = local.scc_instance_region - visibility = local.provider_visibility -} - -provider "ibm" { - alias = "kms" - ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key - region = local.kms_region - visibility = local.provider_visibility -} - -provider "ibm" { - alias = "cos" - ibmcloud_api_key = var.ibmcloud_api_key - region = local.scc_cos_bucket_region - visibility = local.provider_visibility -} - -provider "ibm" { - alias = "en" - ibmcloud_api_key = var.ibmcloud_api_key - region = local.existing_en_region - visibility = local.provider_visibility -} +# Explicit provider config not required here as provider config in fully-configurable is used diff --git a/solutions/security-enforced/version.tf b/solutions/security-enforced/version.tf index 3f749ca..70b38b5 100644 --- a/solutions/security-enforced/version.tf +++ b/solutions/security-enforced/version.tf @@ -2,13 +2,5 @@ terraform { required_version = ">= 1.9.0" # Lock DA into an exact provider version - renovate automation will keep it updated required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = "1.76.1" - } - time = { - source = "hashicorp/time" - version = "0.12.1" - } } } diff --git a/tests/pr_test.go b/tests/pr_test.go index b7b685b..0f933e0 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -21,6 +21,7 @@ import ( const resourceGroup = "geretain-test-resources" const fullyConfigFlavorDir = "solutions/fully-configurable" +const secEnforcedDir = "solutions/security-enforced" // Define a struct with fields that match the structure of the YAML data const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" @@ -29,7 +30,7 @@ const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-res var validRegions = []string{ "us-south", "eu-de", - "us-es", + "eu-es", } var permanentResources map[string]interface{} @@ -54,6 +55,7 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +// Test the fully-configurable DA with defaults (no KMS encryption on bucket) func TestFullyConfigurable(t *testing.T) { t.Parallel() @@ -100,6 +102,8 @@ func TestFullyConfigurable(t *testing.T) { Region: region, Prefix: prefix, TarIncludePatterns: []string{ + "*.tf", + "modules/*/*.tf", fullyConfigFlavorDir + "/*.tf", }, TemplateFolder: fullyConfigFlavorDir, @@ -143,7 +147,138 @@ func TestFullyConfigurable(t *testing.T) { } } -func TestUpgradeFullyConfigurable(t *testing.T) { +// Test the fully-configurable DA using existing KMS key +func TestExistingKeyFullyConfigurable(t *testing.T) { + t.Parallel() + + var region = validRegions[rand.Intn(len(validRegions))] + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: "scc-da-exist-key", + TarIncludePatterns: []string{ + "*.tf", + "modules/*/*.tf", + fullyConfigFlavorDir + "/*.tf", + }, + TemplateFolder: fullyConfigFlavorDir, + Tags: []string{"scc-da-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, + {Name: "scc_region", Value: options.Region, DataType: "string"}, + {Name: "scc_instance_resource_tags", Value: options.Tags, DataType: "list(string)"}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + {Name: "existing_cos_instance_crn", Value: permanentResources["general_test_storage_cos_instance_crn"], DataType: "string"}, + {Name: "existing_cos_instance_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, + {Name: "kms_encryption_enabled_bucket", Value: true, DataType: "bool"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") +} + +// Test the security-enforced DA with defaults (pass KMS instance details and create new key) +func TestSecurityEnforced(t *testing.T) { + t.Parallel() + + var region = validRegions[rand.Intn(len(validRegions))] + + // ------------------------------------------------------------------------------------ + // Provision COS, Sysdig, WP and EN first + // ------------------------------------------------------------------------------------ + + prefix := fmt.Sprintf("scc-da-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := preReqDir + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) + tags := common.GetTagsFromTravis() + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir, + Vars: map[string]interface{}{ + "prefix": prefix, + "region": region, + "resource_tags": tags, + }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, + }) + + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of pre-req resources failed in TestFullyConfigurable test") + } else { + // ------------------------------------------------------------------------------------ + // Deploy DA + // ------------------------------------------------------------------------------------ + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: prefix, + TarIncludePatterns: []string{ + "*.tf", + "modules/*/*.tf", + fullyConfigFlavorDir + "/*.tf", + secEnforcedDir + "/*.tf", + }, + TemplateFolder: secEnforcedDir, + Tags: []string{"scc-da-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: terraform.Output(t, existingTerraformOptions, "resource_group_name"), DataType: "string"}, + {Name: "scc_region", Value: terraform.Output(t, existingTerraformOptions, "region"), DataType: "string"}, + {Name: "scc_instance_resource_tags", Value: options.Tags, DataType: "list(string)"}, + {Name: "scc_instance_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, + {Name: "scc_cos_bucket_access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "prefix", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_cos_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "cos_crn"), DataType: "string"}, + {Name: "existing_scc_workload_protection_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "wp_crn"), DataType: "string"}, + {Name: "existing_event_notifications_crn", Value: terraform.Output(t, existingTerraformOptions, "en_crn"), DataType: "string"}, + {Name: "event_notifications_source_name", Value: terraform.Output(t, existingTerraformOptions, "prefix"), DataType: "string"}, + {Name: "existing_monitoring_crn", Value: terraform.Output(t, existingTerraformOptions, "monitoring_crn"), DataType: "string"}, + {Name: "custom_integrations", Value: customIntegrations, DataType: "list(object)"}, + {Name: "scopes", Value: scopes, DataType: "map(object)"}, + {Name: "attachments", Value: attachments, DataType: "list(object)"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (prereq resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (prereq resources)") + } +} + +// Run upgrade test on security-enforced variation +func TestUpgradeSecurityEnforced(t *testing.T) { t.Parallel() var region = validRegions[rand.Intn(len(validRegions))] @@ -190,6 +325,7 @@ func TestUpgradeFullyConfigurable(t *testing.T) { Prefix: prefix, TarIncludePatterns: []string{ "*.tf", + "modules/*/*.tf", fullyConfigFlavorDir + "/*.tf", }, TemplateFolder: fullyConfigFlavorDir, @@ -282,6 +418,7 @@ func TestExistingResourcesFullyConfigurable(t *testing.T) { Prefix: prefix, TarIncludePatterns: []string{ "*.tf", + "modules/*/*.tf", fullyConfigFlavorDir + "/*.tf", }, TemplateFolder: fullyConfigFlavorDir, diff --git a/tests/resources/existing-resources-test/main.tf b/tests/resources/existing-resources-test/main.tf index e0712e0..4e3f291 100644 --- a/tests/resources/existing-resources-test/main.tf +++ b/tests/resources/existing-resources-test/main.tf @@ -31,12 +31,12 @@ module "cos" { module "scc" { source = "terraform-ibm-modules/scc/ibm" version = "2.0.1" - instance_name = var.prefix + instance_name = var.prefix region = var.region resource_group_id = module.resource_group.resource_group_id resource_tags = var.resource_tags - cos_bucket = module.cos.bucket_name - cos_instance_crn = module.cos.cos_instance_id + cos_bucket = module.cos.bucket_name + cos_instance_crn = module.cos.cos_instance_id } ############################################################################## diff --git a/tests/resources/prereq-resources/main.tf b/tests/resources/prereq-resources/main.tf index 8986c2e..02ff9fa 100644 --- a/tests/resources/prereq-resources/main.tf +++ b/tests/resources/prereq-resources/main.tf @@ -15,12 +15,12 @@ module "resource_group" { ############################################################################## module "cos" { - source = "terraform-ibm-modules/cos/ibm" - version = "8.19.5" - resource_group_id = module.resource_group.resource_group_id - cos_instance_name = "${var.prefix}-cos" - cos_tags = var.resource_tags - create_cos_bucket = false + source = "terraform-ibm-modules/cos/ibm" + version = "8.19.5" + resource_group_id = module.resource_group.resource_group_id + cos_instance_name = "${var.prefix}-cos" + cos_tags = var.resource_tags + create_cos_bucket = false } ############################################################################## From e0f58cd5f8622f1a3785894ddba3aee555ee3a1c Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Fri, 14 Mar 2025 08:51:18 +0000 Subject: [PATCH 06/11] fix typo in cra config --- cra-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cra-config.yaml b/cra-config.yaml index 2bcee72..4a3a117 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -7,7 +7,7 @@ CRA_TARGETS: CRA_ENVIRONMENT_VARIABLES: TF_VAR_prefix: "test" TF_VAR_existing_resource_group_name: "Default" - TF_VAR_kms_encryption_enabled_bucket: true, + TF_VAR_kms_encryption_enabled_bucket: true TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" TF_VAR_existing_cos_instance_crn: "crn:v1:bluemix:public:cloud-object-storage:global:a/abac0df06b644a9cabc6e44f55b3880e:855ed836-05ce-4f39-98fa-508774f29323::" TF_VAR_provider_visibility: "public" From 8fd55d54d9873afdb484beb5e6835d4bf984e03d Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Fri, 14 Mar 2025 09:21:37 +0000 Subject: [PATCH 07/11] add extra valiation + update diagram --- reference-architecture/scc.svg | 2 +- solutions/security-enforced/variables.tf | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/reference-architecture/scc.svg b/reference-architecture/scc.svg index 83e02b4..9a1a852 100644 --- a/reference-architecture/scc.svg +++ b/reference-architecture/scc.svg @@ -1,4 +1,4 @@ -
IBM Cloud
IBM Cloud
Activity Tracker
service
Activity Tracker...
Existing
Monitoring instance
Existing...
`
Event Notifications integration
Event Notification...
Workload 
Protection 
integration
Workload...
Custom provider
integration
Custom provider...
Region
Region
Existing resource group
Existing resource group
SCC instance
SCC instance
Attchments
Attchments
Scopes
Scopes
Existing KMS instance
Existing KMS insta...
Existing COS instance
Existing COS instance
COS bucket
COS bucket
AT events
AT events
Metrics
Metrics
KMS key
KMS key
Text is not SVG - cannot display
\ No newline at end of file +
IBM Cloud
Activity Tracker
service
Existing
Monitoring instance
`
Event Notifications integration
Workload 
Protection 
integration
Custom provider
integration
Region
Existing resource group
SCC instance
Attchments
Scopes
Existing KMS instance
Existing COS instance
COS bucket
AT events
Metrics
KMS key
\ No newline at end of file diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf index 10bc806..89a50d5 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -168,6 +168,11 @@ variable "existing_kms_instance_crn" { condition = var.existing_kms_instance_crn != null ? var.existing_scc_instance_crn == null : true error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing SCC instance using the 'existing_scc_instance_crn' input." } + + validation { + condition = var.existing_kms_instance_crn == null ? var.existing_kms_instance_crn != null : true + error_message = "A value must be passed for either 'existing_kms_instance_crn' (to create a new key) or 'existing_kms_key_crn' (to use existing key) to encrypt the COS bucket." + } } variable "force_delete_kms_key" { @@ -199,6 +204,10 @@ variable "existing_kms_key_crn" { error_message = "A value should not be passed for 'existing_kms_instance_crn' when passing an existing key value using the 'existing_kms_key_crn' input." } + validation { + condition = var.existing_kms_key_crn == null ? var.existing_kms_instance_crn != null : true + error_message = "A value must be passed for either 'existing_kms_instance_crn' (to create a new key) or 'existing_kms_key_crn' (to use existing key) to encrypt the COS bucket." + } } variable "scc_cos_key_ring_name" { From f3ce17776f86f5df6507a495cdd10e9cd1f24417 Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Fri, 14 Mar 2025 09:31:20 +0000 Subject: [PATCH 08/11] fix the existing key test --- tests/pr_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index 0f933e0..41447b5 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -175,7 +175,7 @@ func TestExistingKeyFullyConfigurable(t *testing.T) { {Name: "scc_instance_resource_tags", Value: options.Tags, DataType: "list(string)"}, {Name: "prefix", Value: options.Prefix, DataType: "string"}, {Name: "existing_cos_instance_crn", Value: permanentResources["general_test_storage_cos_instance_crn"], DataType: "string"}, - {Name: "existing_cos_instance_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, + {Name: "existing_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, {Name: "kms_encryption_enabled_bucket", Value: true, DataType: "bool"}, } From 1cb8a77b735bb271aca36f79bcd8da558e4e5fc3 Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Fri, 14 Mar 2025 11:47:08 +0000 Subject: [PATCH 09/11] SKIP UPGRADE TEST --- tests/pr_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index 41447b5..6d4a729 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -156,7 +156,7 @@ func TestExistingKeyFullyConfigurable(t *testing.T) { options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ Testing: t, Region: region, - Prefix: "scc-da-exist-key", + Prefix: "scc-key", TarIncludePatterns: []string{ "*.tf", "modules/*/*.tf", From e9daf70a248bdc4baf317c037f2acc02a014a571 Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Tue, 18 Mar 2025 10:38:49 +0000 Subject: [PATCH 10/11] rebase submodule --- common-dev-assets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-dev-assets b/common-dev-assets index a2d7627..2f8bedb 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit a2d762758724de82bde73e879b4be7fea51ebf95 +Subproject commit 2f8bedb6f5e623405e41553b0491c0306a027023 From 47988cc0518754c334d2541a4ebb261a0db25bcc Mon Sep 17 00:00:00 2001 From: ocofaigh Date: Wed, 19 Mar 2025 13:23:54 +0000 Subject: [PATCH 11/11] refactro prefix logic - remove try --- solutions/fully-configurable/main.tf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index 458dcf5..10c6b43 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -27,18 +27,18 @@ module "existing_kms_key_crn_parser" { } locals { - prefix = var.prefix != null ? (var.prefix != "" ? var.prefix : null) : null + prefix = (var.prefix != null && trimspace(var.prefix) != "" ? "${var.prefix}-" : "") kms_region = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].region : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].region : null existing_kms_guid = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_instance : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].service_instance : null kms_service_name = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].service_name : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].service_name : null kms_account_id = var.existing_kms_instance_crn != null ? module.existing_kms_crn_parser[0].account_id : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].account_id : null kms_key_id = var.existing_kms_instance_crn != null ? module.kms[0].keys[format("%s.%s", local.scc_cos_key_ring_name, local.scc_cos_key_name)].key_id : var.existing_kms_key_crn != null ? module.existing_kms_key_crn_parser[0].resource : null - scc_cos_key_ring_name = try("${local.prefix}-${var.scc_cos_key_ring_name}", var.scc_cos_key_ring_name) - scc_cos_key_name = try("${local.prefix}-${var.scc_cos_key_name}", var.scc_cos_key_name) + scc_cos_key_ring_name = "${local.prefix}${var.scc_cos_key_ring_name}" + scc_cos_key_name = "${local.prefix}${var.scc_cos_key_name}" scc_cos_bucket_region = var.scc_cos_bucket_region != null && var.scc_cos_bucket_region != "" ? var.scc_cos_bucket_region : var.scc_region - scc_instance_name = try("${local.prefix}-${var.scc_instance_name}", var.scc_instance_name) + scc_instance_name = "${local.prefix}${var.scc_instance_name}" # Bucket name to be passed to the COS module to create a bucket - created_scc_cos_bucket_name = try("${local.prefix}-${var.scc_cos_bucket_name}", var.scc_cos_bucket_name) + created_scc_cos_bucket_name = "${local.prefix}${var.scc_cos_bucket_name}" # Final COS bucket name after being created by COS module (as it might have suffix added to it) scc_cos_bucket_name = var.existing_scc_instance_crn == null ? module.buckets[0].buckets[local.created_scc_cos_bucket_name].bucket_name : null create_cross_account_auth_policy = var.existing_scc_instance_crn == null ? !var.skip_cos_kms_iam_auth_policy && var.ibmcloud_kms_api_key == null ? false : (module.scc.account_id != module.existing_kms_crn_parser[0].account_id) : false