From c42afce64650191e1e31416939ebb6cd1e42205c Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Wed, 20 Mar 2024 17:34:05 +0000 Subject: [PATCH 1/9] fix: address review feedback --- README.md | 1 + modules/rules/README.md | 62 ++++++++++++++++++++++++++++++++++++++ modules/rules/main.tf | 54 +++++++++++++++++++++++++++++++++ modules/rules/outputs.tf | 9 ++++++ modules/rules/variables.tf | 50 ++++++++++++++++++++++++++++++ modules/rules/version.tf | 10 ++++++ 6 files changed, 186 insertions(+) create mode 100644 modules/rules/README.md create mode 100644 modules/rules/main.tf create mode 100644 modules/rules/outputs.tf create mode 100644 modules/rules/variables.tf create mode 100644 modules/rules/version.tf diff --git a/README.md b/README.md index 04a6012..add8c47 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ This module configures an IBM Cloud Security and Compliance instance. * [terraform-ibm-scc](#terraform-ibm-scc) * [Submodules](./modules) * [attachment](./modules/attachment) + * [rules](./modules/rules) * [Examples](./examples) * [Basic example](./examples/basic) * [Complete example](./examples/complete) diff --git a/modules/rules/README.md b/modules/rules/README.md new file mode 100644 index 0000000..9114be3 --- /dev/null +++ b/modules/rules/README.md @@ -0,0 +1,62 @@ +# SCC Profile Attachment module + +A module to configure an SCC Profile Attachment. + +Features: +- Create an attachment using a profile ID +- Use the default profile parameters, or pass a custom parameter list +- Configure a scan schedule for the attachment +- Configure notifications for the attachment + +### Usage + +```hcl +module "create_scc_profile_attachment " { + source = "terraform-ibm-modules/scc/ibm//modules/attachment" + ibmcloud_api_key = "XXXXXXXXXX" # pragma: allowlist secret + scc_instance_id = "57b7ac52-e837-484c-aa07-e3c2db815c44" # replace with the ID of your SCC instance + profile_id = "f54b4962-06c6-46bb-bb04-396d9fa9bd60" # select the ID of the profile you want to use + use_profile_default_parameters = true # if setting this to false, custom parameters must be passed using the 'custom_attachment_parameters' variable + attachment_name = "My attachment" + attachment_description = "My attachment description" + attachment_schedule = "daily" + # Configure the scope for the attachment - below scope will scan the whole account + scope { + environment = "ibm-cloud" + properties { + name = "scope-type" + value = "account" + } + } +} +``` + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3.0, <1.7.0 | +| [ibm](#requirement\_ibm) | >=1.63.0, <2.0.0 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [ibm_scc_rule.scc_rule_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/scc_rule) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = string
version = string
import = object({
parameters = optional(list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
})))
})
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = optional(list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
})))
})
}))
|
{
"description": "new rule",
"import": {},
"target": {
"additional_target_attributes": [
{
"name": "location",
"operator": "string_equals",
"value": "us-south"
}
],
"resource_kind": "instance",
"service_name": "kms"
},
"version": "1.0.0"
}
| no | +| [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the attachment. | `string` | `"57b7ac52-e837-484c-aa07-e3c2db815c44"` | no | + +### Outputs + +No outputs. + diff --git a/modules/rules/main.tf b/modules/rules/main.tf new file mode 100644 index 0000000..85a67c4 --- /dev/null +++ b/modules/rules/main.tf @@ -0,0 +1,54 @@ +############################################################################## +# Variable validation +############################################################################## + +locals { + # tflint-ignore: terraform_unused_declarations + # validate_attachment_parameters = var.custom_attachment_parameters == null && !var.use_profile_default_parameters ? tobool("A value must be passed for 'custom_attachment_parameters' if 'use_profile_default_parameters' is set to false.") : true +} + +############################################################################## +# SCC rules +############################################################################## + +resource "ibm_scc_rule" "scc_rule_instance" { + for_each = var.rules + instance_id = var.scc_instance_id + description = each.value.description + + import { + dynamic "parameters" { + for_each = each.value.import["parameters"] + content { + name = parameters.value.name + display_name = parameters.value.display_name + description = parameters.value.description + type = parameters.value.type + } + } + } + + required_config { + description = "description" + and { + description = "description" + property = "endpoints_restricted" + operator = "is_true" + } + } + + target { + service_name = each.value.target["service_name"] + service_display_name = each.value.target["service_display_name"] + resource_kind = each.value.target["resource_kind"] + dynamic "additional_target_attributes" { + for_each = each.value.target["additional_target_attributes"] + content { + name = additional_target_attributes.value.name + operator = additional_target_attributes.value.operator + value = additional_target_attributes.value.value + } + } + } + version = "1.0.0" +} diff --git a/modules/rules/outputs.tf b/modules/rules/outputs.tf new file mode 100644 index 0000000..99b4cca --- /dev/null +++ b/modules/rules/outputs.tf @@ -0,0 +1,9 @@ +# output "id" { +# description = "SCC profile attachment ID" +# value = resource.ibm_scc_profile_attachment.scc_profile_attachment.id +# } + +# output "attachment_parameters" { +# description = "SCC profile attachment parameters" +# value = resource.ibm_scc_profile_attachment.scc_profile_attachment.attachment_parameters +# } diff --git a/modules/rules/variables.tf b/modules/rules/variables.tf new file mode 100644 index 0000000..ff62259 --- /dev/null +++ b/modules/rules/variables.tf @@ -0,0 +1,50 @@ +variable "scc_instance_id" { + type = string + description = "ID of the SCC instance in which to create the attachment." + default = "57b7ac52-e837-484c-aa07-e3c2db815c44" +} + +variable "rules" { + description = "The rules to set for the SCC rules." + type = list(object({ + description = string + version = string + import = object({ + parameters = optional(list(object({ + name = optional(string) + display_name = optional(string) + description = optional(string) + type = optional(string) + }))) + }) + target = object({ + service_name = optional(string) + service_display_name = optional(string) + resource_kind = optional(string) + additional_target_attributes = optional(list(object({ + name = optional(string) + operator = optional(string) + value = optional(string) + }))) + }) + })) + + default = ( + { + description = "new rule" + version = "1.0.0" + import = {} + target = { + service_name = "kms" + resource_kind = "instance" + additional_target_attributes = [ + { + "name": "location", + "operator": "string_equals", + "value": "us-south" + } + ] + } + } + ) +} \ No newline at end of file diff --git a/modules/rules/version.tf b/modules/rules/version.tf new file mode 100644 index 0000000..615d3fe --- /dev/null +++ b/modules/rules/version.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3.0, <1.7.0" + + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">=1.63.0, <2.0.0" + } + } +} From e4a44d0b1015bd345585fdd4278309f21f87cd4b Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Thu, 21 Mar 2024 12:11:48 +0000 Subject: [PATCH 2/9] feat: add scc rules module --- README.md | 1 + examples/rules/README.md | 11 ++++++ examples/rules/main.tf | 70 +++++++++++++++++++++++++++++++++++++ examples/rules/outputs.tf | 48 +++++++++++++++++++++++++ examples/rules/provider.tf | 8 +++++ examples/rules/variables.tf | 33 +++++++++++++++++ examples/rules/version.tf | 12 +++++++ modules/rules/README.md | 2 +- modules/rules/main.tf | 39 +++++++++++---------- modules/rules/variables.tf | 51 ++++++++++----------------- 10 files changed, 223 insertions(+), 52 deletions(-) create mode 100644 examples/rules/README.md create mode 100644 examples/rules/main.tf create mode 100644 examples/rules/outputs.tf create mode 100644 examples/rules/provider.tf create mode 100644 examples/rules/variables.tf create mode 100644 examples/rules/version.tf diff --git a/README.md b/README.md index add8c47..b7a0c69 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This module configures an IBM Cloud Security and Compliance instance. * [rules](./modules/rules) * [Examples](./examples) * [Basic example](./examples/basic) + * [Basic example](./examples/rules) * [Complete example](./examples/complete) * [Contributing](#contributing) diff --git a/examples/rules/README.md b/examples/rules/README.md new file mode 100644 index 0000000..65515ba --- /dev/null +++ b/examples/rules/README.md @@ -0,0 +1,11 @@ +# Basic example + + + +A basic example that will provision the following: +- A new resource group if one is not passed in. +- A new Security and Compliance Center instance with COS bucket configuration diff --git a/examples/rules/main.tf b/examples/rules/main.tf new file mode 100644 index 0000000..8dd5cee --- /dev/null +++ b/examples/rules/main.tf @@ -0,0 +1,70 @@ +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.5" + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +module "cos" { + source = "terraform-ibm-modules/cos/ibm" + version = "7.5.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}-cb" +} + +module "create_scc_instance" { + source = "../.." + instance_name = "${var.prefix}-instance" + 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 + skip_cos_iam_authorization_policy = false +} + +module "create_scc_rules" { + source = "../../modules/rules" + scc_instance_id = module.create_scc_instance.guid + rules = [ + { + description = "new rule 1" + version = "1.0.0" + import = { + parameters = [] + } + target = { + service_name = "kms" + resource_kind = "instance" + additional_target_attributes = [ + { + "name" : "location", + "operator" : "string_equals", + "value" : "us-south" + } + ] + } + }, + { + description = "new rule 2" + version = "1.0.0" + import = { + parameters = [] + } + target = { + service_name = "kms" + resource_kind = "instance" + additional_target_attributes = [ + { + "name" : "location", + "operator" : "string_equals", + "value" : "eu-de" + } + ] + } + } + ] +} diff --git a/examples/rules/outputs.tf b/examples/rules/outputs.tf new file mode 100644 index 0000000..9c6f579 --- /dev/null +++ b/examples/rules/outputs.tf @@ -0,0 +1,48 @@ +######################################################################################################################## +# Outputs +######################################################################################################################## + +output "resource_group_id" { + description = "The id of the resource group where SCC instance is created by this module" + value = module.resource_group.resource_group_id +} + +output "id" { + description = "The id of the SCC instance created by this module" + value = module.create_scc_instance.id +} + +output "guid" { + description = "The GUID of the SCC instance created by this module" + value = module.create_scc_instance.guid +} + +output "crn" { + description = "The CRN of the SCC instance created by this module" + value = module.create_scc_instance.crn +} + +output "name" { + description = "The name of the SCC instance created by this module" + value = module.create_scc_instance.name +} + +output "location" { + description = "The location of the SCC instance created by this module" + value = module.create_scc_instance.location +} + +output "plan" { + description = "The pricing plan used to create SCC instance in this module" + value = module.create_scc_instance.plan +} + +output "cos_instance_id" { + description = "The COS instance ID created in this example" + value = module.cos.cos_instance_id +} + +output "cos_bucket" { + description = "The COS bucket created in this example" + value = module.cos.bucket_name +} diff --git a/examples/rules/provider.tf b/examples/rules/provider.tf new file mode 100644 index 0000000..84b6985 --- /dev/null +++ b/examples/rules/provider.tf @@ -0,0 +1,8 @@ +######################################################################################################################## +# Provider config +######################################################################################################################## + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/examples/rules/variables.tf b/examples/rules/variables.tf new file mode 100644 index 0000000..8c44c2a --- /dev/null +++ b/examples/rules/variables.tf @@ -0,0 +1,33 @@ +######################################################################################################################## +# Input variables +######################################################################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region to provision all resources created by this example" + default = "us-south" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources created by this example" + default = "scc" +} + +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/examples/rules/version.tf b/examples/rules/version.tf new file mode 100644 index 0000000..98294c3 --- /dev/null +++ b/examples/rules/version.tf @@ -0,0 +1,12 @@ +terraform { + required_version = ">= 1.3.0, <1.7.0" + + # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "1.63.0" + } + } +} diff --git a/modules/rules/README.md b/modules/rules/README.md index 9114be3..b26b5eb 100644 --- a/modules/rules/README.md +++ b/modules/rules/README.md @@ -53,7 +53,7 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = string
version = string
import = object({
parameters = optional(list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
})))
})
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = optional(list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
})))
})
}))
|
{
"description": "new rule",
"import": {},
"target": {
"additional_target_attributes": [
{
"name": "location",
"operator": "string_equals",
"value": "us-south"
}
],
"resource_kind": "instance",
"service_name": "kms"
},
"version": "1.0.0"
}
| no | +| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = string
version = string
import = object({
parameters = list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
}))
})
# required_config = object({
# description = string
# value = list(object({}))
# })
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
}))
})
}))
| n/a | yes | | [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the attachment. | `string` | `"57b7ac52-e837-484c-aa07-e3c2db815c44"` | no | ### Outputs diff --git a/modules/rules/main.tf b/modules/rules/main.tf index 85a67c4..c467c73 100644 --- a/modules/rules/main.tf +++ b/modules/rules/main.tf @@ -12,18 +12,21 @@ locals { ############################################################################## resource "ibm_scc_rule" "scc_rule_instance" { - for_each = var.rules + count = length(var.rules) > 0 ? length(var.rules) : 0 instance_id = var.scc_instance_id - description = each.value.description + description = var.rules[count.index].description - import { - dynamic "parameters" { - for_each = each.value.import["parameters"] - content { - name = parameters.value.name - display_name = parameters.value.display_name - description = parameters.value.description - type = parameters.value.type + dynamic "import" { + for_each = length(var.rules[count.index].import.parameters) > 0 ? [var.rules[count.index].import] : [] + content { + dynamic "parameters" { + for_each = import.value.parameters + content { + name = parameters.value.name + display_name = parameters.value.display_name + description = parameters.value.description + type = parameters.value.type + } } } } @@ -32,21 +35,21 @@ resource "ibm_scc_rule" "scc_rule_instance" { description = "description" and { description = "description" - property = "endpoints_restricted" - operator = "is_true" + property = "endpoints_restricted" + operator = "is_true" } } target { - service_name = each.value.target["service_name"] - service_display_name = each.value.target["service_display_name"] - resource_kind = each.value.target["resource_kind"] + service_name = var.rules[count.index].target.service_name + service_display_name = var.rules[count.index].target.service_display_name + resource_kind = var.rules[count.index].target.resource_kind dynamic "additional_target_attributes" { - for_each = each.value.target["additional_target_attributes"] + for_each = var.rules[count.index].target.additional_target_attributes content { - name = additional_target_attributes.value.name + name = additional_target_attributes.value.name operator = additional_target_attributes.value.operator - value = additional_target_attributes.value.value + value = additional_target_attributes.value.value } } } diff --git a/modules/rules/variables.tf b/modules/rules/variables.tf index ff62259..689c5e8 100644 --- a/modules/rules/variables.tf +++ b/modules/rules/variables.tf @@ -1,50 +1,35 @@ variable "scc_instance_id" { type = string description = "ID of the SCC instance in which to create the attachment." - default = "57b7ac52-e837-484c-aa07-e3c2db815c44" + default = "57b7ac52-e837-484c-aa07-e3c2db815c44" } variable "rules" { description = "The rules to set for the SCC rules." type = list(object({ description = string - version = string + version = string import = object({ - parameters = optional(list(object({ - name = optional(string) + parameters = list(object({ + name = optional(string) display_name = optional(string) - description = optional(string) - type = optional(string) - }))) + description = optional(string) + type = optional(string) + })) }) + # required_config = object({ + # description = string + # value = list(object({})) + # }) target = object({ - service_name = optional(string) + service_name = optional(string) service_display_name = optional(string) - resource_kind = optional(string) - additional_target_attributes = optional(list(object({ - name = optional(string) + resource_kind = optional(string) + additional_target_attributes = list(object({ + name = optional(string) operator = optional(string) - value = optional(string) - }))) + value = optional(string) + })) }) })) - - default = ( - { - description = "new rule" - version = "1.0.0" - import = {} - target = { - service_name = "kms" - resource_kind = "instance" - additional_target_attributes = [ - { - "name": "location", - "operator": "string_equals", - "value": "us-south" - } - ] - } - } - ) -} \ No newline at end of file +} From 60067a971f2efc5feb3ff7e0c5f9c6c8e5783a7f Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Thu, 21 Mar 2024 12:25:40 +0000 Subject: [PATCH 3/9] feat: add scc rules module --- README.md | 2 +- examples/rules/README.md | 3 +- examples/rules/outputs.tf | 5 +++ modules/rules/README.md | 69 ++++++++++++++++++++++++++------------- modules/rules/outputs.tf | 13 +++----- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index b7a0c69..6702c03 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ This module configures an IBM Cloud Security and Compliance instance. * [rules](./modules/rules) * [Examples](./examples) * [Basic example](./examples/basic) - * [Basic example](./examples/rules) * [Complete example](./examples/complete) + * [Rules example](./examples/rules) * [Contributing](#contributing) diff --git a/examples/rules/README.md b/examples/rules/README.md index 65515ba..ee9b2aa 100644 --- a/examples/rules/README.md +++ b/examples/rules/README.md @@ -1,4 +1,4 @@ -# Basic example +# Rules example diff --git a/modules/rules/outputs.tf b/modules/rules/outputs.tf index 99b4cca..519a0c2 100644 --- a/modules/rules/outputs.tf +++ b/modules/rules/outputs.tf @@ -1,9 +1,4 @@ -# output "id" { -# description = "SCC profile attachment ID" -# value = resource.ibm_scc_profile_attachment.scc_profile_attachment.id -# } - -# output "attachment_parameters" { -# description = "SCC profile attachment parameters" -# value = resource.ibm_scc_profile_attachment.scc_profile_attachment.attachment_parameters -# } +output "rule_ids" { + description = "SCC profile attachment parameters" + value = [for rule in resource.ibm_scc_rule.scc_rule_instance : rule.rule_id] +} From 0b5e4d787b19fa3a7c3176350e8961e196522b49 Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Thu, 21 Mar 2024 12:33:04 +0000 Subject: [PATCH 4/9] feat: add scc rules module --- examples/rules/main.tf | 3 +-- modules/rules/README.md | 3 ++- modules/rules/main.tf | 2 +- modules/rules/variables.tf | 7 ++++++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/rules/main.tf b/examples/rules/main.tf index 8dd5cee..ddf9e39 100644 --- a/examples/rules/main.tf +++ b/examples/rules/main.tf @@ -29,10 +29,10 @@ module "create_scc_instance" { module "create_scc_rules" { source = "../../modules/rules" scc_instance_id = module.create_scc_instance.guid + rules_version = "1.0.0" rules = [ { description = "new rule 1" - version = "1.0.0" import = { parameters = [] } @@ -50,7 +50,6 @@ module "create_scc_rules" { }, { description = "new rule 2" - version = "1.0.0" import = { parameters = [] } diff --git a/modules/rules/README.md b/modules/rules/README.md index 906c277..8a9ab21 100644 --- a/modules/rules/README.md +++ b/modules/rules/README.md @@ -74,7 +74,8 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = string
version = string
import = object({
parameters = list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
}))
})
# required_config = object({
# description = string
# value = list(object({}))
# })
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
}))
})
}))
| n/a | yes | +| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = string
import = object({
parameters = list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
}))
})
# required_config = object({
# description = string
# value = list(object({}))
# })
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
}))
})
}))
| n/a | yes | +| [rules\_version](#input\_rules\_version) | The version number of a rule. | `string` | `"1.0.0"` | no | | [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the attachment. | `string` | `"57b7ac52-e837-484c-aa07-e3c2db815c44"` | no | ### Outputs diff --git a/modules/rules/main.tf b/modules/rules/main.tf index c467c73..3964f31 100644 --- a/modules/rules/main.tf +++ b/modules/rules/main.tf @@ -53,5 +53,5 @@ resource "ibm_scc_rule" "scc_rule_instance" { } } } - version = "1.0.0" + version = var.rules_version } diff --git a/modules/rules/variables.tf b/modules/rules/variables.tf index 689c5e8..3d1676a 100644 --- a/modules/rules/variables.tf +++ b/modules/rules/variables.tf @@ -4,11 +4,16 @@ variable "scc_instance_id" { default = "57b7ac52-e837-484c-aa07-e3c2db815c44" } +variable "rules_version" { + type = string + description = "The version number of a rule." + default = "1.0.0" +} + variable "rules" { description = "The rules to set for the SCC rules." type = list(object({ description = string - version = string import = object({ parameters = list(object({ name = optional(string) From 9daa1492230ba333d3140e98b5489a7cb66e78cc Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Mon, 25 Mar 2024 00:17:27 +0000 Subject: [PATCH 5/9] feat: add rules module --- common-dev-assets | 2 +- examples/rules/README.md | 2 +- examples/rules/main.tf | 83 ++++++++++++++++++++++++++++++++++---- modules/rules/README.md | 4 +- modules/rules/main.tf | 58 +++++++++++++++++++++++--- modules/rules/variables.tf | 65 ++++++++++++++++++++++++++--- 6 files changed, 191 insertions(+), 23 deletions(-) diff --git a/common-dev-assets b/common-dev-assets index 8405107..465a57d 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 8405107509b351b346887674d06ee37e98140493 +Subproject commit 465a57d227d66bf8c80e75ec934c91dd7dd3d2d8 diff --git a/examples/rules/README.md b/examples/rules/README.md index ee9b2aa..2819e25 100644 --- a/examples/rules/README.md +++ b/examples/rules/README.md @@ -9,4 +9,4 @@ The text below should describe exactly what resources are provisioned / configur A basic example that will provision the following: - A new resource group if one is not passed in. - A new Security and Compliance Center instance with COS bucket configuration -- New SCC rules for Security and Compliance Center instance +- Creates 3 new custom SCC rules for a Security and Compliance Center instance diff --git a/examples/rules/main.tf b/examples/rules/main.tf index ddf9e39..3d72639 100644 --- a/examples/rules/main.tf +++ b/examples/rules/main.tf @@ -36,14 +36,23 @@ module "create_scc_rules" { import = { parameters = [] } + required_config = { + description = "restrict endpoints" + and = [ + { + property = "endpoints_restricted", + operator = "is_true" + } + ] + } target = { service_name = "kms" resource_kind = "instance" additional_target_attributes = [ { "name" : "location", - "operator" : "string_equals", - "value" : "us-south" + operator : "string_equals", + value : "us-south" } ] } @@ -53,17 +62,75 @@ module "create_scc_rules" { import = { parameters = [] } + required_config = { + description = "required config" + and = [ + { + property = "cloud_directory_enabled", + operator = "is_true" + }, + { + property = "email_dispatcher_provider", + operator = "string_not_equals" + value = "appid" + } + ] + } target = { - service_name = "kms" - resource_kind = "instance" - additional_target_attributes = [ + service_name = "appid", + service_display_name = "App ID", + resource_kind = "instance", + additional_target_attributes = [] + } + }, + { + description = "new rule 3" + import = { + parameters = [] + } + required_config = { + description = "required config" + or = [ { - "name" : "location", - "operator" : "string_equals", - "value" : "eu-de" + and = [ + { + property : "endpoints_restricted", + operator : "is_true" + }, + { + property : "cbr_private_public_allowed_ip_list", + operator : "is_empty" + } + ] + }, + { + and = [ + { + property : "endpoints_restricted", + operator : "is_true" + }, + { + property : "cbr_private_public_allowed_ip_list", + operator : "is_not_empty" + }, + ] + }, + { + and = [ + { + property : "firewall.allowed_ip", + operator : "is_not_empty" + }, + ] } ] } + target = { + service_name = "cloud-object-storage", + service_display_name = "Cloud Object Storage", + resource_kind = "bucket", + additional_target_attributes = [] + } } ] } diff --git a/modules/rules/README.md b/modules/rules/README.md index 8a9ab21..23b910c 100644 --- a/modules/rules/README.md +++ b/modules/rules/README.md @@ -74,9 +74,9 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = string
import = object({
parameters = list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
}))
})
# required_config = object({
# description = string
# value = list(object({}))
# })
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
}))
})
}))
| n/a | yes | +| [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = optional(string)
operator = optional(string)
property = optional(string)
value = optional(string)
import = object({
parameters = list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
}))
})
required_config = object({
description = optional(string)
operator = optional(string)
property = optional(string)
value = optional(string)
and = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
and = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
or = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
})
))
or = optional(list(
object({
description = optional(string)
operator = optional(string)
property = optional(string)
value = optional(string)
and = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
or = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
})
))
})
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
}))
})
}))
| n/a | yes | | [rules\_version](#input\_rules\_version) | The version number of a rule. | `string` | `"1.0.0"` | no | -| [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the attachment. | `string` | `"57b7ac52-e837-484c-aa07-e3c2db815c44"` | no | +| [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the attachment. | `string` | `"5cd2ee42-a26b-4631-a0d6-e0f220716d5f"` | no | ### Outputs diff --git a/modules/rules/main.tf b/modules/rules/main.tf index 3964f31..f7747af 100644 --- a/modules/rules/main.tf +++ b/modules/rules/main.tf @@ -32,11 +32,59 @@ resource "ibm_scc_rule" "scc_rule_instance" { } required_config { - description = "description" - and { - description = "description" - property = "endpoints_restricted" - operator = "is_true" + description = var.rules[count.index].required_config.description + operator = var.rules[count.index].required_config.operator + property = var.rules[count.index].required_config.property + value = var.rules[count.index].required_config.value + dynamic "and" { + for_each = var.rules[count.index].required_config.and == null ? [] : var.rules[count.index].required_config.and + content { + description = and.value.description + property = and.value.property + operator = and.value.operator + value = and.value.value + dynamic "and" { + for_each = and.value.and == null ? [] : and.value.and + content { + description = and.value.description + property = and.value.property + operator = and.value.operator + } + } + dynamic "or" { + for_each = and.value.or == null ? [] : and.value.or + content { + description = or.value.description + property = or.value.property + operator = or.value.operator + } + } + } + } + dynamic "or" { + for_each = var.rules[count.index].required_config.or == null ? [] : var.rules[count.index].required_config.or + content { + description = or.value.description + property = or.value.property + operator = or.value.operator + value = or.value.value + dynamic "and" { + for_each = or.value.and == null ? [] : or.value.and + content { + description = and.value.description + property = and.value.property + operator = and.value.operator + } + } + dynamic "or" { + for_each = or.value.or == null ? [] : or.value.or + content { + description = or.value.description + property = or.value.property + operator = or.value.operator + } + } + } } } diff --git a/modules/rules/variables.tf b/modules/rules/variables.tf index 3d1676a..4cb669c 100644 --- a/modules/rules/variables.tf +++ b/modules/rules/variables.tf @@ -1,7 +1,7 @@ variable "scc_instance_id" { type = string description = "ID of the SCC instance in which to create the attachment." - default = "57b7ac52-e837-484c-aa07-e3c2db815c44" + default = "5cd2ee42-a26b-4631-a0d6-e0f220716d5f" } variable "rules_version" { @@ -13,7 +13,10 @@ variable "rules_version" { variable "rules" { description = "The rules to set for the SCC rules." type = list(object({ - description = string + description = optional(string) + operator = optional(string) + property = optional(string) + value = optional(string) import = object({ parameters = list(object({ name = optional(string) @@ -22,10 +25,60 @@ variable "rules" { type = optional(string) })) }) - # required_config = object({ - # description = string - # value = list(object({})) - # }) + required_config = object({ + description = optional(string) + operator = optional(string) + property = optional(string) + value = optional(string) + and = optional(list( + object({ + description = optional(string) + operator = string + property = string + value = optional(string) + and = optional(list( + object({ + description = optional(string) + operator = string + property = string + value = optional(string) + }) + )) + or = optional(list( + object({ + description = optional(string) + operator = string + property = string + value = optional(string) + }) + )) + }) + )) + or = optional(list( + object({ + description = optional(string) + operator = optional(string) + property = optional(string) + value = optional(string) + and = optional(list( + object({ + description = optional(string) + operator = string + property = string + value = optional(string) + }) + )) + or = optional(list( + object({ + description = optional(string) + operator = string + property = string + value = optional(string) + }) + )) + }) + )) + }) target = object({ service_name = optional(string) service_display_name = optional(string) From 8f0f357e8ba184a09b02a4d26e86d65ede0aa922 Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Mon, 25 Mar 2024 00:18:18 +0000 Subject: [PATCH 6/9] feat: add rules module --- modules/rules/main.tf | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/rules/main.tf b/modules/rules/main.tf index f7747af..baab060 100644 --- a/modules/rules/main.tf +++ b/modules/rules/main.tf @@ -1,12 +1,3 @@ -############################################################################## -# Variable validation -############################################################################## - -locals { - # tflint-ignore: terraform_unused_declarations - # validate_attachment_parameters = var.custom_attachment_parameters == null && !var.use_profile_default_parameters ? tobool("A value must be passed for 'custom_attachment_parameters' if 'use_profile_default_parameters' is set to false.") : true -} - ############################################################################## # SCC rules ############################################################################## From ddc7dcc3d6e7605151287c4d9887c85aa8a8e97f Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Wed, 27 Mar 2024 13:31:18 +0000 Subject: [PATCH 7/9] feature: add rules submodule --- README.md | 2 +- examples/{rules => custom}/README.md | 0 examples/{rules => custom}/main.tf | 0 examples/{rules => custom}/outputs.tf | 0 examples/{rules => custom}/provider.tf | 0 examples/{rules => custom}/variables.tf | 0 examples/{rules => custom}/version.tf | 0 modules/rules/README.md | 9 +++++---- modules/rules/outputs.tf | 2 +- modules/rules/variables.tf | 4 +--- tests/pr_test.go | 11 +++++++++++ 11 files changed, 19 insertions(+), 9 deletions(-) rename examples/{rules => custom}/README.md (100%) rename examples/{rules => custom}/main.tf (100%) rename examples/{rules => custom}/outputs.tf (100%) rename examples/{rules => custom}/provider.tf (100%) rename examples/{rules => custom}/variables.tf (100%) rename examples/{rules => custom}/version.tf (100%) diff --git a/README.md b/README.md index 6702c03..62ce4c9 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This module configures an IBM Cloud Security and Compliance instance. * [Examples](./examples) * [Basic example](./examples/basic) * [Complete example](./examples/complete) - * [Rules example](./examples/rules) + * [Rules example](./examples/custom) * [Contributing](#contributing) diff --git a/examples/rules/README.md b/examples/custom/README.md similarity index 100% rename from examples/rules/README.md rename to examples/custom/README.md diff --git a/examples/rules/main.tf b/examples/custom/main.tf similarity index 100% rename from examples/rules/main.tf rename to examples/custom/main.tf diff --git a/examples/rules/outputs.tf b/examples/custom/outputs.tf similarity index 100% rename from examples/rules/outputs.tf rename to examples/custom/outputs.tf diff --git a/examples/rules/provider.tf b/examples/custom/provider.tf similarity index 100% rename from examples/rules/provider.tf rename to examples/custom/provider.tf diff --git a/examples/rules/variables.tf b/examples/custom/variables.tf similarity index 100% rename from examples/rules/variables.tf rename to examples/custom/variables.tf diff --git a/examples/rules/version.tf b/examples/custom/version.tf similarity index 100% rename from examples/rules/version.tf rename to examples/custom/version.tf diff --git a/modules/rules/README.md b/modules/rules/README.md index 23b910c..bda76ee 100644 --- a/modules/rules/README.md +++ b/modules/rules/README.md @@ -9,7 +9,8 @@ Features: ```hcl module "create_scc_rules" { - source = "../../modules/rules" + source = "terraform-ibm-modules/scc/ibm//modules/rules" + version = "X.X.X" scc_instance_id = "123-XXX-XXX" rules = [ { @@ -75,12 +76,12 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [rules](#input\_rules) | The rules to set for the SCC rules. |
list(object({
description = optional(string)
operator = optional(string)
property = optional(string)
value = optional(string)
import = object({
parameters = list(object({
name = optional(string)
display_name = optional(string)
description = optional(string)
type = optional(string)
}))
})
required_config = object({
description = optional(string)
operator = optional(string)
property = optional(string)
value = optional(string)
and = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
and = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
or = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
})
))
or = optional(list(
object({
description = optional(string)
operator = optional(string)
property = optional(string)
value = optional(string)
and = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
or = optional(list(
object({
description = optional(string)
operator = string
property = string
value = optional(string)
})
))
})
))
})
target = object({
service_name = optional(string)
service_display_name = optional(string)
resource_kind = optional(string)
additional_target_attributes = list(object({
name = optional(string)
operator = optional(string)
value = optional(string)
}))
})
}))
| n/a | yes | -| [rules\_version](#input\_rules\_version) | The version number of a rule. | `string` | `"1.0.0"` | no | -| [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the attachment. | `string` | `"5cd2ee42-a26b-4631-a0d6-e0f220716d5f"` | no | +| [rules\_version](#input\_rules\_version) | The version number of a rule. | `string` | n/a | yes | +| [scc\_instance\_id](#input\_scc\_instance\_id) | ID of the SCC instance in which to create the rules. | `string` | n/a | yes | ### Outputs | Name | Description | |------|-------------| -| [rule\_ids](#output\_rule\_ids) | SCC profile attachment parameters | +| [rule\_ids](#output\_rule\_ids) | The ids for the rules created by this module. | diff --git a/modules/rules/outputs.tf b/modules/rules/outputs.tf index 519a0c2..29be754 100644 --- a/modules/rules/outputs.tf +++ b/modules/rules/outputs.tf @@ -1,4 +1,4 @@ output "rule_ids" { - description = "SCC profile attachment parameters" + description = "The ids for the rules created by this module." value = [for rule in resource.ibm_scc_rule.scc_rule_instance : rule.rule_id] } diff --git a/modules/rules/variables.tf b/modules/rules/variables.tf index 4cb669c..29abccf 100644 --- a/modules/rules/variables.tf +++ b/modules/rules/variables.tf @@ -1,13 +1,11 @@ variable "scc_instance_id" { type = string - description = "ID of the SCC instance in which to create the attachment." - default = "5cd2ee42-a26b-4631-a0d6-e0f220716d5f" + description = "ID of the SCC instance in which to create the rules." } variable "rules_version" { type = string description = "The version number of a rule." - default = "1.0.0" } variable "rules" { diff --git a/tests/pr_test.go b/tests/pr_test.go index db0d058..cedb970 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -12,6 +12,7 @@ import ( const resourceGroup = "geretain-test-resources" // Use existing resource group const basicExampleDir = "examples/basic" const completeExampleDir = "examples/complete" +const customExampleDir = "examples/custom" func setupBasicExampleOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ @@ -55,6 +56,16 @@ func TestRunCompleteExample(t *testing.T) { assert.NotNil(t, output, "Expected some output") } +func TestRunCustomExample(t *testing.T) { + t.Parallel() + + options := setupCompleteExampleOptions(t, "scc-cust", customExampleDir) + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} + func TestRunBasicExample(t *testing.T) { t.Parallel() From df1241703304e3dfc8a999eb0463c5c9bfc6da41 Mon Sep 17 00:00:00 2001 From: Jordan-Williams2 Date: Tue, 2 Apr 2024 23:56:33 +0100 Subject: [PATCH 8/9] fix: address comments --- README.md | 2 +- common-dev-assets | 2 +- examples/custom/README.md | 2 +- modules/rules/outputs.tf | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 62ce4c9..18d327d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This module configures an IBM Cloud Security and Compliance instance. * [Examples](./examples) * [Basic example](./examples/basic) * [Complete example](./examples/complete) - * [Rules example](./examples/custom) + * [Custom example](./examples/custom) * [Contributing](#contributing) diff --git a/common-dev-assets b/common-dev-assets index 465a57d..89c38cb 160000 --- a/common-dev-assets +++ b/common-dev-assets @@ -1 +1 @@ -Subproject commit 465a57d227d66bf8c80e75ec934c91dd7dd3d2d8 +Subproject commit 89c38cbfebb0cf36968bd97612454b971f56e58b diff --git a/examples/custom/README.md b/examples/custom/README.md index 2819e25..951c0a1 100644 --- a/examples/custom/README.md +++ b/examples/custom/README.md @@ -1,4 +1,4 @@ -# Rules example +# Custom example diff --git a/modules/rules/outputs.tf b/modules/rules/outputs.tf index e63c8b8..b1750e8 100644 --- a/modules/rules/outputs.tf +++ b/modules/rules/outputs.tf @@ -1,8 +1,8 @@ output "rule_ids" { - description = "The ids for the rules created by this module." + description = "The unique identifier of the scc_rules created by this module." value = [ for rule in resource.ibm_scc_rule.scc_rule_instance : { - rule_id = rule.rule_id + rule_id = rule.rule_id } ] }