diff --git a/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/metadata.json b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/metadata.json new file mode 100644 index 00000000000..db95a6d6179 --- /dev/null +++ b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/metadata.json @@ -0,0 +1,14 @@ +{ + "id": "51a2c34d-dfd0-436f-aa34-e8f796e052fd", + "queryName": "Beta - SQL DB Instance With Local Data Loading Enabled", + "severity": "MEDIUM", + "category": "Insecure Defaults", + "descriptionText": "All 'google_sql_database_instance' resources based on 'MYSQL' should disable the 'local_infile' flag to prevent unwanted exposure", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/sql_database_instance.html#settings-1", + "platform": "Terraform", + "descriptionID": "51a2c34d", + "cloudProvider": "gcp", + "cwe": "732", + "riskScore": "3.0", + "experimental": "true" +} diff --git a/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/query.rego b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/query.rego new file mode 100644 index 00000000000..91949f66079 --- /dev/null +++ b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/query.rego @@ -0,0 +1,85 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.google_sql_database_instance[name] + + contains(resource.database_version, "MYSQL") + results := get_results(resource, name) + + result := { + "documentId": input.document[i].id, + "resourceType": "google_sql_database_instance", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": results.searchKey, + "issueType": results.issueType, + "keyExpectedValue": results.keyExpectedValue, + "keyActualValue": results.keyActualValue, + "searchLine": results.searchLine + } +} + +get_results(resource, name) = results { + not common_lib.valid_key(resource, "settings") + + results := { + "searchKey": sprintf("google_sql_database_instance[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' should be defined and set 'local_infile' to 'off'", [name]), + "keyActualValue": sprintf("'google_sql_database_instance[%s].settings' is undefined or null", [name]), + "searchLine": common_lib.build_search_line(["resource", "google_sql_database_instance", name], []) + + } +} else = results { + not common_lib.valid_key(resource.settings, "database_flags") + + results := { + "searchKey": sprintf("google_sql_database_instance[%s].settings", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' should be defined and set 'local_infile' to 'off'", [name]), + "keyActualValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' is undefined or null", [name]), + "searchLine": common_lib.build_search_line(["resource", "google_sql_database_instance", name, "settings"], []) + } + +} else = results { + not has_flag(resource.settings.database_flags) + + results := { + "searchKey": sprintf("google_sql_database_instance[%s].settings.database_flags", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' should be defined and set 'local_infile' to 'off'", [name]), + "keyActualValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' does not set 'local_infile'", [name]), + "searchLine": common_lib.build_search_line(["resource", "google_sql_database_instance", name, "settings", "database_flags"], []) + } + +} else = results { # array + resource.settings.database_flags[x].name == "local_infile" + resource.settings.database_flags[x].value != "off" + + results := { + "searchKey": sprintf("google_sql_database_instance[%s].settings.database_flags[%d].name", [name, x]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' should be defined and set 'local_infile' to 'off'", [name]), + "keyActualValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' sets 'local_infile' to '%s'", [name, resource.settings.database_flags[x].value]), + "searchLine": common_lib.build_search_line(["resource", "google_sql_database_instance", name, "settings", "database_flags", x, "name"], []) + } +} else = results { + resource.settings.database_flags.name == "local_infile" + resource.settings.database_flags.value != "off" + + results := { + "searchKey": sprintf("google_sql_database_instance[%s].settings.database_flags.name", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' should be defined and set 'local_infile' to 'off'", [name]), + "keyActualValue": sprintf("'google_sql_database_instance[%s].settings.database_flags' sets 'local_infile' to '%s'", [name, resource.settings.database_flags.value]), + "searchLine": common_lib.build_search_line(["resource", "google_sql_database_instance", name, "settings", "database_flags", "name"], []) + } +} + +has_flag(database_flags) { + database_flags[_].name == "local_infile" +} else { + database_flags.name == "local_infile" +} diff --git a/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/negative.tf b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/negative.tf new file mode 100644 index 00000000000..7b61d61a0c8 --- /dev/null +++ b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/negative.tf @@ -0,0 +1,49 @@ +resource "google_sql_database_instance" "negative_1" { + name = "main-instance" + database_version = "POSTGRES_15" # Is not a MYSQL instance + region = "us-central1" + + settings { + tier = "db-f1-micro" + } +} + +resource "google_sql_database_instance" "negative_2" { + name = "mysql-instance-with-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + settings { + tier = "db-f1-micro" + + database_flags { + name = "sample_flag1" + value = "off" + } + + database_flags { # Has flag set to "off" + name = "local_infile" + value = "off" + } + + database_flags { + name = "sample_flag2" + value = "off" + } + } +} + +resource "google_sql_database_instance" "negative_3" { # Single object support test + name = "mysql-instance-with-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + settings { + tier = "db-f1-micro" + + database_flags { + name = "local_infile" + value = "off" + } # Has flag set to "off" + } +} diff --git a/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/positive.tf b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/positive.tf new file mode 100644 index 00000000000..cca046cd67f --- /dev/null +++ b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/positive.tf @@ -0,0 +1,64 @@ +resource "google_sql_database_instance" "positive_1" { + name = "mysql-instance-without-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + # Missing 'settings' field +} + +resource "google_sql_database_instance" "positive_2" { + name = "mysql-instance-without-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + settings {} # Missing 'database_flags' field +} + +resource "google_sql_database_instance" "positive_3" { + name = "mysql-instance-without-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + settings { + database_flags { + name = "sample_flag1" + value = "off" + } # Missing 'local_infile' flag + } +} + +resource "google_sql_database_instance" "positive_4" { + name = "mysql-instance-with-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + settings { + database_flags { + name = "sample_flag1" + value = "off" + } + + database_flags { # Flag is not set to "off" + name = "local_infile" + value = "on" + } + + database_flags { + name = "sample_flag2" + value = "off" + } + } +} + +resource "google_sql_database_instance" "positive_5" { # Single object support test + name = "mysql-instance-with-flag" + database_version = "MYSQL_8_0" + region = "us-central1" + + settings { + database_flags { + name = "local_infile" + value = "on" + } # Flag is not set to "off" + } +} diff --git a/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/positive_expected_result.json b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/positive_expected_result.json new file mode 100644 index 00000000000..162410cf2b9 --- /dev/null +++ b/assets/queries/terraform/gcp/sql_db_instance_with_local_data_loading_enabled/test/positive_expected_result.json @@ -0,0 +1,27 @@ +[ + { + "queryName": "Beta - SQL DB Instance With Local Data Loading Enabled", + "severity": "MEDIUM", + "line": 1 + }, + { + "queryName": "Beta - SQL DB Instance With Local Data Loading Enabled", + "severity": "MEDIUM", + "line": 14 + }, + { + "queryName": "Beta - SQL DB Instance With Local Data Loading Enabled", + "severity": "MEDIUM", + "line": 23 + }, + { + "queryName": "Beta - SQL DB Instance With Local Data Loading Enabled", + "severity": "MEDIUM", + "line": 42 + }, + { + "queryName": "Beta - SQL DB Instance With Local Data Loading Enabled", + "severity": "MEDIUM", + "line": 60 + } +] diff --git a/assets/similarityID_transition/terraform_gcp.yaml b/assets/similarityID_transition/terraform_gcp.yaml index 89ca54e2221..a4eee1bd2e3 100644 --- a/assets/similarityID_transition/terraform_gcp.yaml +++ b/assets/similarityID_transition/terraform_gcp.yaml @@ -3,6 +3,10 @@ similarityIDChangeList: queryName: Beta - Google DNS Policy Logging Disabled observations: "" change: 2 + - queryId: 51a2c34d-dfd0-436f-aa34-e8f796e052fd + queryName: Beta - SQL DB Instance With Local Data Loading Enabled + observations: "" + change: 2 - queryId: b5b70198-2a34-4792-b0d9-ce99abe485bb queryName: Beta - SQL DB Instance With Exposed Show Privileges observations: ""