Skip to content

Commit

Permalink
Merge pull request #35 from schubergphilis/filter-findings-to-snow
Browse files Browse the repository at this point in the history
feat: add variable to filter findings forwarded to SNOW based on severity label
  • Loading branch information
marceldevroed committed Jun 26, 2024
2 parents 4a0a256 + 6d671e4 commit 084fb1b
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 15 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ There are 3 different deployment modes for this module. All the modes deploy a L
* This deployment method can be used by setting the value of the variable `servicenow_integration` to `true` (default = false).
* The module will deploy all the needed resources to support integration with ServiceNow, including (but not limited to): An SQS Queue, EventBridge Rule and the needed IAM user.
* When an event in SecurityHub fires, an event will be created by EventBridge and dropped onto an SQS Queue.
* With the variable `severity_filter` it can be configured which findings will be forwarded based on the severity label.
* ServiceNow will pull the events from the SQS queue with the `SCSyncUser` using `acccess_key` & `secret_access_key`.

Note : The user will be created by the module, but the `acccess_key` & `secret_access_key` need to be generated in the AWS Console, to prevent storing this data in the Terraform state. If you want Terraform to create the `acccess_key` & `secret_access_key` (and output them), set variable `create_servicenow_access_keys` to `true` (default = false)
Expand Down Expand Up @@ -206,7 +207,7 @@ Suppress finding for specific resources:
| <a name="input_lambda_events_suppressor"></a> [lambda\_events\_suppressor](#input\_lambda\_events\_suppressor) | Lambda Events Suppressor settings - Supresses the Security Hub findings in response to EventBridge Trigger | <pre>object({<br> name = optional(string, "securityhub-events-suppressor")<br> log_level = optional(string, "INFO")<br> memory_size = optional(number, 256)<br> runtime = optional(string, "python3.8")<br> timeout = optional(number, 120)<br><br> security_group_egress_rules = optional(list(object({<br> cidr_ipv4 = optional(string)<br> cidr_ipv6 = optional(string)<br> description = string<br> from_port = optional(number, 0)<br> ip_protocol = optional(string, "-1")<br> prefix_list_id = optional(string)<br> referenced_security_group_id = optional(string)<br> to_port = optional(number, 0)<br> })), [])<br> })</pre> | `{}` | no |
| <a name="input_lambda_streams_suppressor"></a> [lambda\_streams\_suppressor](#input\_lambda\_streams\_suppressor) | Lambda Streams Suppressor settings - Supresses the Security Hub findings in response to DynamoDB streams | <pre>object({<br> name = optional(string, "securityhub-streams-suppressor")<br> log_level = optional(string, "INFO")<br> memory_size = optional(number, 256)<br> runtime = optional(string, "python3.8")<br> timeout = optional(number, 120)<br><br> security_group_egress_rules = optional(list(object({<br> cidr_ipv4 = optional(string)<br> cidr_ipv6 = optional(string)<br> description = string<br> from_port = optional(number, 0)<br> ip_protocol = optional(string, "-1")<br> prefix_list_id = optional(string)<br> referenced_security_group_id = optional(string)<br> to_port = optional(number, 0)<br> })), [])<br> })</pre> | `{}` | no |
| <a name="input_lambda_suppressor_iam_role_name"></a> [lambda\_suppressor\_iam\_role\_name](#input\_lambda\_suppressor\_iam\_role\_name) | The name of the role which will be assumed by both Suppressor Lambda functions | `string` | `"LambdaSecurityHubSuppressorRole"` | no |
| <a name="input_servicenow_integration"></a> [servicenow\_integration](#input\_servicenow\_integration) | ServiceNow integration settings | <pre>object({<br> enabled = optional(bool, false)<br> create_access_keys = optional(bool, false)<br> cloudwatch_retention_days = optional(number, 365)<br> })</pre> | <pre>{<br> "enabled": false<br>}</pre> | no |
| <a name="input_servicenow_integration"></a> [servicenow\_integration](#input\_servicenow\_integration) | ServiceNow integration settings | <pre>object({<br> enabled = optional(bool, false)<br> create_access_keys = optional(bool, false)<br> cloudwatch_retention_days = optional(number, 365)<br> severity_label_filter = optional(list(string), [])<br> })</pre> | <pre>{<br> "enabled": false<br>}</pre> | no |
| <a name="input_step_function_suppressor_iam_role_name"></a> [step\_function\_suppressor\_iam\_role\_name](#input\_step\_function\_suppressor\_iam\_role\_name) | The name of the role which will be assumed by Suppressor Step function | `string` | `"StepFunctionSecurityHubSuppressorRole"` | no |
| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | The subnet ids where the lambda's needs to run | `list(string)` | `null` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign to the resources | `map(string)` | `{}` | no |
Expand Down
2 changes: 1 addition & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The following variable defaults have been modified:

### Behaviour

The need to provide a `providers = { aws = aws }` argument has been removed, but is still allowed. E.g. when deploying this module in the audit account typically `providers = { aws = aws.audit }` is passed.
The need to provide a `providers = { aws = aws }` argument has been removed, but is still allowed. E.g. when deploying this module in the audit account typically `providers = { aws = aws.audit }` is passed.

## Upgrading to v1.0.0

Expand Down
13 changes: 7 additions & 6 deletions modules/servicenow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| kms\_key\_arn | The ARN of the KMS key used to encrypt the resources | `string` | n/a | yes |
| tags | A mapping of tags to assign to the resources | `map(string)` | n/a | yes |
| cloudwatch\_retention\_days | Time to retain the CloudWatch Logs for the ServiceNow integration | `number` | `14` | no |
| create\_access\_keys | Whether to create an access\_key and secret\_access key for the ServiceNow user | `bool` | `false` | no |
| Name | Description | Type | Default | Required |
|-----------------------------|------------------------------------------------------------------------------------------------------------------------|----------------|--------|:--------:|
| kms\_key\_arn | The ARN of the KMS key used to encrypt the resources | `string` | n/a | yes |
| tags | A mapping of tags to assign to the resources | `map(string)` | n/a | yes |
| cloudwatch\_retention\_days | Time to retain the CloudWatch Logs for the ServiceNow integration | `number` | `14` | no |
| create\_access\_keys | Whether to create an access\_key and secret\_access key for the ServiceNow user | `bool` | `false` | no |
| severity\_label\_filter | Only forward findings to ServiceNow with severity labels from this list (by default all severity labels are forwarded) | `list(string)` | `[]` | no |

## Outputs

Expand Down
9 changes: 2 additions & 7 deletions modules/servicenow/eventbridge.tf
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
resource "aws_cloudwatch_event_rule" "securityhub" {
name = "snow-RuleLifeCycleEvents"
description = "Send Security Hub imported findings to the AwsServiceManagementConnectorForSecurityHubQueue SQS."

event_pattern = <<EOF
{
"detail-type": ["Security Hub Findings - Imported"],
"source": ["aws.securityhub"]
}
EOF
event_pattern = templatefile("${path.module}/templates/findings_filter.json.tftpl", {
severity_label_filter = jsonencode(var.severity_label_filter) })
}

resource "aws_cloudwatch_event_target" "securityhub" {
Expand Down
14 changes: 14 additions & 0 deletions modules/servicenow/templates/findings_filter.json.tftpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"detail-type" : ["Security Hub Findings - Imported"],
"source" : ["aws.securityhub"]
%{ if length(jsondecode(severity_label_filter)) > 0 ~}
,
"detail": {
"findings": {
"Severity": {
"Label": ${severity_label_filter}
}
}
}
%{ endif ~}
}
6 changes: 6 additions & 0 deletions modules/servicenow/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ variable "create_access_keys" {
description = "Whether to create an access_key and secret_access key for the ServiceNow user"
}

variable "severity_label_filter" {
type = list(string)
default = []
description = "Only forward findings to ServiceNow with severity labels from this list (by default all severity labels are forwarded)"
}

variable "kms_key_arn" {
type = string
description = "The ARN of the KMS key used to encrypt the resources"
Expand Down
1 change: 1 addition & 0 deletions servicenow.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module "servicenow_integration" {

cloudwatch_retention_days = var.servicenow_integration.cloudwatch_retention_days
create_access_keys = var.servicenow_integration.create_access_keys
severity_label_filter = var.servicenow_integration.severity_label_filter
kms_key_arn = var.kms_key_arn
tags = var.tags
}
1 change: 1 addition & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ variable "servicenow_integration" {
enabled = optional(bool, false)
create_access_keys = optional(bool, false)
cloudwatch_retention_days = optional(number, 365)
severity_label_filter = optional(list(string), [])
})
default = {
enabled = false
Expand Down

0 comments on commit 084fb1b

Please sign in to comment.