Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add variable to filter findings forwarded to SNOW based on severity label #35

Merged
merged 2 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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