diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/metadata.json b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/metadata.json new file mode 100644 index 00000000000..518c2b16717 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/metadata.json @@ -0,0 +1,14 @@ +{ + "id": "b97a1065-a86b-442f-86c4-f95afd9b3ac6", + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "category": "Observability", + "descriptionText": "There should be a 'azurerm_monitor_activity_log_alert' resource configured to capture 'delete security solution' events", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_activity_log_alert", + "platform": "Terraform", + "descriptionID": "b97a1065", + "cloudProvider": "azure", + "cwe": "778", + "riskScore": "3.0", + "experimental": "true" +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/query.rego b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/query.rego new file mode 100644 index 00000000000..3d3f3718daf --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/query.rego @@ -0,0 +1,95 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +filter_fields := ["caller", "level", "levels", "status", "statuses", "sub_status", "sub_statuses"] + +CxPolicy[result] { + resources := {input.document[index].id : log_alerts | + log_alerts := input.document[index].resource.azurerm_monitor_activity_log_alert + } + + value := at_least_one_valid_log_alert(resources) + value.result != "has_valid_log" + + results := get_results(value)[_] + + result := { + "documentId": results.doc_id, + "resourceType": "azurerm_monitor_activity_log_alert", + "resourceName": tf_lib.get_resource_name(results.resource, results.name), + "searchKey": sprintf("azurerm_monitor_activity_log_alert[%s].criteria", [results.name]), + "issueType": results.issueType, + "keyExpectedValue": "A 'azurerm_monitor_activity_log_alert' resource that monitors 'delete security solution' events should be defined", + "keyActualValue": results.keyActualValue, + "searchLine": common_lib.build_search_line(["resource", "azurerm_monitor_activity_log_alert", results.name, "criteria"], []) + } +} + +at_least_one_valid_log_alert(resources) = {"result" : "has_valid_log"} { + resources[doc_index][x].criteria.category == "Administrative" + resources[doc_index][x].criteria.operation_name == "Microsoft.Security/securitySolutions/delete" + not has_filter(resources[doc_index][x].criteria) + common_lib.valid_key(resources[doc_index][x].action, "action_group_id") + +} else = {"result" : "has_log_without_action", "logs": logs} { + logs := {doc_index: filtered | + resources[doc_index] + filtered := {key: resource | + resource := resources[doc_index][key] + resource.criteria.category == "Administrative" + resource.criteria.operation_name == "Microsoft.Security/securitySolutions/delete" + not has_filter(resource.criteria)} + } + logs[_] != {} + +} else = {"result" : "has_log_with_filter", "logs": logs} { + logs := {doc_index: filtered | + resources[doc_index] + filtered := {key: resource | + resource := resources[doc_index][key] + resource.criteria.category == "Administrative" + resource.criteria.operation_name == "Microsoft.Security/securitySolutions/delete"} + } + logs[_] != {} + +} + +get_results(value) = results { # Case of one or more resources failing due to not setting an "action.action_group_id" field + value.result == "has_log_without_action" + + results := [z | + log := value.logs[doc_id][name] + z := { + "doc_id" : doc_id, + "resource" : log, + "issueType": "MissingAttribute", + "name" : name, + "keyActualValue" : sprintf("The 'azurerm_monitor_activity_log_alert[%s]' resource monitors 'delete security solution' events but is missing an 'action.action_group_id' field", [name]) + }] + +} else = results { # Case of one or more resources failing due to setting filter(s) + value.result == "has_log_with_filter" + + results := [z | + filters = get_filters(value.logs[doc_id][name].criteria) + z := { + "doc_id" : doc_id, + "resource" : value.logs[doc_id][name], + "issueType": "IncorrectValue", + "name" : name, + "keyActualValue" : sprintf("The 'azurerm_monitor_activity_log_alert[%s]' resource monitors 'delete security solution' events but sets %d filter(s): %s", [name, count(filters),concat(", ",filters)]) + }] + +} + +has_filter(criteria) { + common_lib.valid_key(criteria, filter_fields[_]) +} + +get_filters(criteria) = [x | + y := filter_fields[_] + common_lib.valid_key(criteria, y) + x := y +] diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/negative1.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/negative1.tf new file mode 100644 index 00000000000..264ceb29d16 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/negative1.tf @@ -0,0 +1,21 @@ +resource "azurerm_monitor_activity_log_alert" "negative1" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Negative sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + + webhook_properties = { + from = "terraform" + } + } +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive1.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive1.tf new file mode 100644 index 00000000000..b8b81f1e39e --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive1.tf @@ -0,0 +1,54 @@ +# In the future this should flag the project (currently impossible) and request for a valid "log_alert" to be defined +resource "azurerm_monitor_activity_log_alert" "positive1_1" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Storage/storageAccounts/write" # wrong operation name + category = "Administrative" + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive1_2" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Policy" # wrong category + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive1_3" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Storage/storageAccounts/write" # wrong operation name + category = "Policy" # wrong category + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive2_1.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive2_1.tf new file mode 100644 index 00000000000..6b1bc8ecc63 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive2_1.tf @@ -0,0 +1,76 @@ +# Case of correct "operation_name" and "category" but a type of filter is set +resource "azurerm_monitor_activity_log_alert" "positive2_1" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + caller = "admin@contoso.com" # filters by caller + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive2_2" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + level = "Informational" # filters by level + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive2_3" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + levels = ["Informational", "Warning"] # filters by levels + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive2_4" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + status = "Succeeded" # filters by status + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive2_2.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive2_2.tf new file mode 100644 index 00000000000..8a170f11693 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive2_2.tf @@ -0,0 +1,56 @@ +resource "azurerm_monitor_activity_log_alert" "positive2_5" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + statuses = ["Succeeded", "Failed"] # filters by statuses + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive2_6" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + sub_status = "Accepted" # filters by sub_status + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} + +resource "azurerm_monitor_activity_log_alert" "positive2_7" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + sub_statuses = ["Accepted", "Conflict"] # filters by sub_statuses + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive_expected_result.json b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive_expected_result.json new file mode 100644 index 00000000000..48cd89dddfe --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive2/positive_expected_result.json @@ -0,0 +1,44 @@ +[ + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 9, + "fileName": "positive2_1.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 28, + "fileName": "positive2_1.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 47, + "fileName": "positive2_1.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 66, + "fileName": "positive2_1.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 8, + "fileName": "positive2_2.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 27, + "fileName": "positive2_2.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 46, + "fileName": "positive2_2.tf" + } +] diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive3_1.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive3_1.tf new file mode 100644 index 00000000000..449b26dbcb2 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive3_1.tf @@ -0,0 +1,16 @@ +# Case of correct "operation_name" and "category" but the "action.action_group_id" field is missing +resource "azurerm_monitor_activity_log_alert" "positive3_1" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + } + + # Missing action +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive3_2.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive3_2.tf new file mode 100644 index 00000000000..1c0c21b22a6 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive3_2.tf @@ -0,0 +1,18 @@ +# Case of correct "operation_name" and "category" but the "action.action_group_id" field is missing +resource "azurerm_monitor_activity_log_alert" "positive3_2" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + } + + action { + # Missing action_group_id + } +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive_expected_result.json b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive_expected_result.json new file mode 100644 index 00000000000..df7ec6ee0e6 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive3/positive_expected_result.json @@ -0,0 +1,14 @@ +[ + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 9, + "fileName": "positive3_1.tf" + }, + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 9, + "fileName": "positive3_2.tf" + } +] diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive4_1.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive4_1.tf new file mode 100644 index 00000000000..596f1173265 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive4_1.tf @@ -0,0 +1,16 @@ +# Query prioritizes flagging the log alert(s) that is "correct" but missing the "action_group_id" field over all others +resource "azurerm_monitor_activity_log_alert" "positive4_1" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + } + + # Missing action block +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive4_2.tf b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive4_2.tf new file mode 100644 index 00000000000..02c0e2fc4b1 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive4_2.tf @@ -0,0 +1,20 @@ +resource "azurerm_monitor_activity_log_alert" "positive4_2" { + name = "example-activitylogalert" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + scopes = [azurerm_resource_group.example.id] + description = "Positive sample" + + criteria { + resource_id = azurerm_storage_account.to_monitor.id + operation_name = "Microsoft.Security/securitySolutions/delete" + category = "Administrative" + caller = "admin@contoso.com" # filters by caller + level = "Informational" # filters by level + status = "Succeeded" # filters by status + } + + action { + action_group_id = azurerm_monitor_action_group.main.id + } +} diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive_expected_result.json b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive_expected_result.json new file mode 100644 index 00000000000..0ec2da06fea --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive4/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Activity Log Alert For Delete Security Solution Not Configured", + "severity": "MEDIUM", + "line": 9, + "fileName": "positive4_1.tf" + } +] diff --git a/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive_expected_result.json b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive_expected_result.json new file mode 100644 index 00000000000..0d4f101c7a3 --- /dev/null +++ b/assets/queries/terraform/azure/activity_log_alert_for_delete_security_solution_not_configured/test/positive_expected_result.json @@ -0,0 +1,2 @@ +[ +] diff --git a/assets/similarityID_transition/terraform_azure.yaml b/assets/similarityID_transition/terraform_azure.yaml index 627d0128f1f..8f9d256c728 100644 --- a/assets/similarityID_transition/terraform_azure.yaml +++ b/assets/similarityID_transition/terraform_azure.yaml @@ -3,6 +3,10 @@ similarityIDChangeList: queryName: Sensitive Port Is Exposed To Wide Private Network observations: "" change: 5 + - queryId: b97a1065-a86b-442f-86c4-f95afd9b3ac6 + queryName: Beta - Activity Log Alert For Delete Security Solution Not Configured + observations: "" + change: 2 - queryId: 8553d83f-fe77-4c96-8850-a95c5895b336 queryName: Beta - Activity Log Alert For Create or Update Security Solution Not Configured observations: ""