From 72e9b82b223f7d0e09b0b36227826df45a0e9cab Mon Sep 17 00:00:00 2001 From: Antero Silva Date: Mon, 9 Mar 2026 17:53:12 +0000 Subject: [PATCH 1/4] feat(queries): add 12 Beta security queries across AWS/Azure/GCP/K8s/Dockerfile Add new queries covering security gaps identified against best practices: AWS Terraform: - Beta - Lambda Function URL Without Authentication (HIGH, CWE-306) - Beta - Backup Vault Without KMS Key (MEDIUM, CWE-311) - Beta - Transfer Family Server Publicly Accessible (HIGH, CWE-668) Azure Terraform: - Beta - AKS Defender Profile Disabled (MEDIUM, CWE-778) - Beta - Service Bus Namespace Without CMK (LOW, CWE-311) - Beta - Machine Learning Workspace Without CMK (MEDIUM, CWE-311) GCP Terraform: - Beta - Cloud Run Service Allows Unauthenticated Access (HIGH, CWE-306) - Beta - Artifact Registry Repository Public Access (HIGH, CWE-284) - Beta - Secret Manager Secret Without CMEK (MEDIUM, CWE-311) Kubernetes: - Beta - Container Seccomp Profile Not Set (MEDIUM, CWE-250) - Beta - Ingress Without TLS (HIGH, CWE-319) Dockerfile: - Beta - ENV Instruction Has Secret (HIGH, CWE-798) Each query includes query.rego, metadata.json, and positive/negative test fixtures. Co-Authored-By: Claude Sonnet 4.6 --- .../env_instruction_has_secret/metadata.json | 13 ++++++ .../env_instruction_has_secret/query.rego | 34 +++++++++++++++ .../test/negative.dockerfile | 6 +++ .../test/positive.dockerfile | 5 +++ .../test/positive_expected_result.json | 20 +++++++++ .../metadata.json | 13 ++++++ .../query.rego | 37 ++++++++++++++++ .../test/negative1.yaml | 12 ++++++ .../test/negative2.yaml | 11 +++++ .../test/positive1.yaml | 10 +++++ .../test/positive_expected_result.json | 8 ++++ .../k8s/ingress_without_tls/metadata.json | 13 ++++++ .../k8s/ingress_without_tls/query.rego | 40 +++++++++++++++++ .../ingress_without_tls/test/negative1.yaml | 20 +++++++++ .../ingress_without_tls/test/positive1.yaml | 16 +++++++ .../test/positive_expected_result.json | 8 ++++ .../metadata.json | 13 ++++++ .../backup_vault_without_kms_key/query.rego | 22 ++++++++++ .../test/negative1.tf | 4 ++ .../test/positive1.tf | 3 ++ .../test/positive_expected_result.json | 8 ++++ .../metadata.json | 13 ++++++ .../query.rego | 22 ++++++++++ .../test/negative1.tf | 4 ++ .../test/positive1.tf | 4 ++ .../test/positive_expected_result.json | 8 ++++ .../metadata.json | 13 ++++++ .../query.rego | 23 ++++++++++ .../test/negative1.tf | 7 +++ .../test/positive1.tf | 4 ++ .../test/positive2.tf | 3 ++ .../test/positive_expected_result.json | 14 ++++++ .../metadata.json | 13 ++++++ .../aks_defender_profile_disabled/query.rego | 22 ++++++++++ .../test/negative1.tf | 17 ++++++++ .../test/positive1.tf | 14 ++++++ .../test/positive_expected_result.json | 8 ++++ .../metadata.json | 13 ++++++ .../query.rego | 22 ++++++++++ .../test/negative1.tf | 15 +++++++ .../test/positive1.tf | 11 +++++ .../test/positive_expected_result.json | 8 ++++ .../metadata.json | 13 ++++++ .../query.rego | 22 ++++++++++ .../test/negative1.tf | 10 +++++ .../test/positive1.tf | 6 +++ .../test/positive_expected_result.json | 8 ++++ .../metadata.json | 13 ++++++ .../query.rego | 43 +++++++++++++++++++ .../test/negative1.tf | 6 +++ .../test/positive1.tf | 6 +++ .../test/positive2.tf | 6 +++ .../test/positive_expected_result.json | 14 ++++++ .../metadata.json | 13 ++++++ .../query.rego | 40 +++++++++++++++++ .../test/negative1.tf | 6 +++ .../test/positive1.tf | 6 +++ .../test/positive2.tf | 6 +++ .../test/positive_expected_result.json | 14 ++++++ .../metadata.json | 13 ++++++ .../query.rego | 33 ++++++++++++++ .../test/negative1.tf | 13 ++++++ .../test/positive1.tf | 6 +++ .../test/positive2.tf | 10 +++++ .../test/positive_expected_result.json | 14 ++++++ 65 files changed, 895 insertions(+) create mode 100644 assets/queries/dockerfile/env_instruction_has_secret/metadata.json create mode 100644 assets/queries/dockerfile/env_instruction_has_secret/query.rego create mode 100644 assets/queries/dockerfile/env_instruction_has_secret/test/negative.dockerfile create mode 100644 assets/queries/dockerfile/env_instruction_has_secret/test/positive.dockerfile create mode 100644 assets/queries/dockerfile/env_instruction_has_secret/test/positive_expected_result.json create mode 100644 assets/queries/k8s/container_seccomp_profile_not_set/metadata.json create mode 100644 assets/queries/k8s/container_seccomp_profile_not_set/query.rego create mode 100644 assets/queries/k8s/container_seccomp_profile_not_set/test/negative1.yaml create mode 100644 assets/queries/k8s/container_seccomp_profile_not_set/test/negative2.yaml create mode 100644 assets/queries/k8s/container_seccomp_profile_not_set/test/positive1.yaml create mode 100644 assets/queries/k8s/container_seccomp_profile_not_set/test/positive_expected_result.json create mode 100644 assets/queries/k8s/ingress_without_tls/metadata.json create mode 100644 assets/queries/k8s/ingress_without_tls/query.rego create mode 100644 assets/queries/k8s/ingress_without_tls/test/negative1.yaml create mode 100644 assets/queries/k8s/ingress_without_tls/test/positive1.yaml create mode 100644 assets/queries/k8s/ingress_without_tls/test/positive_expected_result.json create mode 100644 assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json create mode 100644 assets/queries/terraform/aws/backup_vault_without_kms_key/query.rego create mode 100644 assets/queries/terraform/aws/backup_vault_without_kms_key/test/negative1.tf create mode 100644 assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive1.tf create mode 100644 assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive_expected_result.json create mode 100644 assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json create mode 100644 assets/queries/terraform/aws/lambda_function_url_without_authentication/query.rego create mode 100644 assets/queries/terraform/aws/lambda_function_url_without_authentication/test/negative1.tf create mode 100644 assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive1.tf create mode 100644 assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive_expected_result.json create mode 100644 assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json create mode 100644 assets/queries/terraform/aws/transfer_family_server_publicly_accessible/query.rego create mode 100644 assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/negative1.tf create mode 100644 assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive1.tf create mode 100644 assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive2.tf create mode 100644 assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive_expected_result.json create mode 100644 assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json create mode 100644 assets/queries/terraform/azure/aks_defender_profile_disabled/query.rego create mode 100644 assets/queries/terraform/azure/aks_defender_profile_disabled/test/negative1.tf create mode 100644 assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive1.tf create mode 100644 assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive_expected_result.json create mode 100644 assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json create mode 100644 assets/queries/terraform/azure/machine_learning_workspace_without_cmk/query.rego create mode 100644 assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/negative1.tf create mode 100644 assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive1.tf create mode 100644 assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive_expected_result.json create mode 100644 assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json create mode 100644 assets/queries/terraform/azure/service_bus_namespace_without_cmk/query.rego create mode 100644 assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/negative1.tf create mode 100644 assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive1.tf create mode 100644 assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive_expected_result.json create mode 100644 assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json create mode 100644 assets/queries/terraform/gcp/artifact_registry_repository_public_access/query.rego create mode 100644 assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/negative1.tf create mode 100644 assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive1.tf create mode 100644 assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive2.tf create mode 100644 assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive_expected_result.json create mode 100644 assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json create mode 100644 assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/query.rego create mode 100644 assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/negative1.tf create mode 100644 assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive1.tf create mode 100644 assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive2.tf create mode 100644 assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive_expected_result.json create mode 100644 assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json create mode 100644 assets/queries/terraform/gcp/secret_manager_secret_without_cmek/query.rego create mode 100644 assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/negative1.tf create mode 100644 assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive1.tf create mode 100644 assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive2.tf create mode 100644 assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive_expected_result.json diff --git a/assets/queries/dockerfile/env_instruction_has_secret/metadata.json b/assets/queries/dockerfile/env_instruction_has_secret/metadata.json new file mode 100644 index 00000000000..5a1db5890cd --- /dev/null +++ b/assets/queries/dockerfile/env_instruction_has_secret/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "781e75f7-bf43-4ab7-bae7-a08ad6607af3", + "queryName": "Beta - ENV Instruction Contains Secret", + "severity": "HIGH", + "category": "Secret Management", + "descriptionText": "Dockerfile ENV instructions should not store secrets, passwords, API keys or tokens as plaintext values. These values are embedded in every image layer and visible in 'docker inspect' output, risking credential exposure. Use build-time secrets (BuildKit) or a secrets manager instead.", + "descriptionUrl": "https://docs.docker.com/build/building/secrets/", + "platform": "Dockerfile", + "descriptionID": "7abccf53", + "cloudProvider": "common", + "cwe": "798", + "riskScore": "8.5" +} \ No newline at end of file diff --git a/assets/queries/dockerfile/env_instruction_has_secret/query.rego b/assets/queries/dockerfile/env_instruction_has_secret/query.rego new file mode 100644 index 00000000000..8ba27a3a8f7 --- /dev/null +++ b/assets/queries/dockerfile/env_instruction_has_secret/query.rego @@ -0,0 +1,34 @@ +package Cx + +secret_env_patterns := { + "password", "passwd", "pwd", "secret", "api_key", "apikey", + "token", "private_key", "auth_key", "access_key", "secret_key", + "encryption_key", "db_pass", "database_password", "app_secret" +} + +CxPolicy[result] { + resource := input.document[i].command[name][_] + resource.Cmd == "env" + + env_entry := resource.Value[_] + parts := split(env_entry, "=") + count(parts) >= 2 + + env_key := lower(parts[0]) + env_val := concat("=", array.slice(parts, 1, count(parts))) + + contains(env_key, secret_env_patterns[_]) + env_val != "" + not startswith(env_val, "$") + not startswith(env_val, "\${") + not env_val == "changeme" + not env_val == "placeholder" + + result := { + "documentId": input.document[i].id, + "searchKey": sprintf("FROM={{%s}}.ENV {{%s}}", [name, parts[0]]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("ENV '%s' should not contain a hardcoded secret value; use BuildKit secrets or a runtime secrets manager", [parts[0]]), + "keyActualValue": sprintf("ENV '%s' appears to contain a hardcoded secret value", [parts[0]]), + } +} diff --git a/assets/queries/dockerfile/env_instruction_has_secret/test/negative.dockerfile b/assets/queries/dockerfile/env_instruction_has_secret/test/negative.dockerfile new file mode 100644 index 00000000000..da77762a8ea --- /dev/null +++ b/assets/queries/dockerfile/env_instruction_has_secret/test/negative.dockerfile @@ -0,0 +1,6 @@ +FROM python:3.11-slim +ENV APP_SECRET=${APP_SECRET} +ENV DATABASE_PASSWORD=$DB_PASS +ENV LOG_LEVEL=info +ENV PORT=8080 +RUN pip install flask diff --git a/assets/queries/dockerfile/env_instruction_has_secret/test/positive.dockerfile b/assets/queries/dockerfile/env_instruction_has_secret/test/positive.dockerfile new file mode 100644 index 00000000000..afeb54f42bf --- /dev/null +++ b/assets/queries/dockerfile/env_instruction_has_secret/test/positive.dockerfile @@ -0,0 +1,5 @@ +FROM python:3.11-slim +ENV APP_SECRET=my_super_secret_value +ENV DATABASE_PASSWORD=s3cr3t123 +ENV API_KEY=AKIAIOSFODNN7EXAMPLE +RUN pip install flask diff --git a/assets/queries/dockerfile/env_instruction_has_secret/test/positive_expected_result.json b/assets/queries/dockerfile/env_instruction_has_secret/test/positive_expected_result.json new file mode 100644 index 00000000000..7165086eb9f --- /dev/null +++ b/assets/queries/dockerfile/env_instruction_has_secret/test/positive_expected_result.json @@ -0,0 +1,20 @@ +[ + { + "queryName": "Beta - ENV Instruction Contains Secret", + "severity": "HIGH", + "line": 2, + "fileName": "positive.dockerfile" + }, + { + "queryName": "Beta - ENV Instruction Contains Secret", + "severity": "HIGH", + "line": 3, + "fileName": "positive.dockerfile" + }, + { + "queryName": "Beta - ENV Instruction Contains Secret", + "severity": "HIGH", + "line": 4, + "fileName": "positive.dockerfile" + } +] \ No newline at end of file diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json b/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json new file mode 100644 index 00000000000..23da50a48b1 --- /dev/null +++ b/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "ab2bf277-cd73-451c-8a34-70ea5c7ee258", + "queryName": "Beta - Container Seccomp Profile Not Set", + "severity": "MEDIUM", + "category": "Insecure Configurations", + "descriptionText": "Containers should have a seccomp profile set to 'RuntimeDefault' or 'Localhost' in their security context. Without it, the container has an unconfined syscall profile, increasing the attack surface if a container breakout occurs.", + "descriptionUrl": "https://kubernetes.io/docs/tutorials/security/seccomp/", + "platform": "Kubernetes", + "descriptionID": "30a7f7cc", + "cloudProvider": "common", + "cwe": "250", + "riskScore": "5.5" +} \ No newline at end of file diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/query.rego b/assets/queries/k8s/container_seccomp_profile_not_set/query.rego new file mode 100644 index 00000000000..667ac9d0f13 --- /dev/null +++ b/assets/queries/k8s/container_seccomp_profile_not_set/query.rego @@ -0,0 +1,37 @@ +package Cx + +import data.generic.k8s as k8sLib +import data.generic.common as common_lib + +valid_types := {"RuntimeDefault", "Localhost"} + +CxPolicy[result] { + document := input.document[i] + specInfo := k8sLib.getSpecInfo(document) + metadata := document.metadata + types := {"initContainers", "containers"} + container := specInfo.spec[types[x]][j] + + not has_valid_seccomp(container, specInfo.spec) + + result := { + "documentId": document.id, + "resourceType": document.kind, + "resourceName": metadata.name, + "searchKey": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}.securityContext", [metadata.name, specInfo.path, types[x], container.name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("Container '%s' should have seccompProfile.type set to 'RuntimeDefault' or 'Localhost'", [container.name]), + "keyActualValue": sprintf("Container '%s' does not have a valid seccompProfile configured", [container.name]), + "searchLine": common_lib.build_search_line(split(specInfo.path, "."), [types[x], j, "securityContext"]), + } +} + +# seccomp defined at container level +has_valid_seccomp(container, _) { + container.securityContext.seccompProfile.type == valid_types[_] +} + +# seccomp defined at pod spec level +has_valid_seccomp(_, spec) { + spec.securityContext.seccompProfile.type == valid_types[_] +} diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/test/negative1.yaml b/assets/queries/k8s/container_seccomp_profile_not_set/test/negative1.yaml new file mode 100644 index 00000000000..26891bd9d43 --- /dev/null +++ b/assets/queries/k8s/container_seccomp_profile_not_set/test/negative1.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: negative-pod-container-level +spec: + containers: + - name: app + image: nginx:1.21 + securityContext: + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/test/negative2.yaml b/assets/queries/k8s/container_seccomp_profile_not_set/test/negative2.yaml new file mode 100644 index 00000000000..220a2c2ed19 --- /dev/null +++ b/assets/queries/k8s/container_seccomp_profile_not_set/test/negative2.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Pod +metadata: + name: negative-pod-pod-level +spec: + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: app + image: nginx:1.21 diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/test/positive1.yaml b/assets/queries/k8s/container_seccomp_profile_not_set/test/positive1.yaml new file mode 100644 index 00000000000..76d9c9ecda7 --- /dev/null +++ b/assets/queries/k8s/container_seccomp_profile_not_set/test/positive1.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: positive-pod +spec: + containers: + - name: app + image: nginx:1.21 + securityContext: + runAsNonRoot: true diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/test/positive_expected_result.json b/assets/queries/k8s/container_seccomp_profile_not_set/test/positive_expected_result.json new file mode 100644 index 00000000000..a02c9575500 --- /dev/null +++ b/assets/queries/k8s/container_seccomp_profile_not_set/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Container Seccomp Profile Not Set", + "severity": "MEDIUM", + "line": 7, + "fileName": "positive1.yaml" + } +] \ No newline at end of file diff --git a/assets/queries/k8s/ingress_without_tls/metadata.json b/assets/queries/k8s/ingress_without_tls/metadata.json new file mode 100644 index 00000000000..af9fe6f2814 --- /dev/null +++ b/assets/queries/k8s/ingress_without_tls/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "c81c6c42-6c17-48c4-bde6-ea242e76f275", + "queryName": "Beta - Ingress Without TLS", + "severity": "HIGH", + "category": "Networking and Firewall", + "descriptionText": "Kubernetes Ingress resources should configure TLS to encrypt traffic between clients and the ingress controller. Without a 'tls' block, traffic is served over plain HTTP, exposing sensitive data in transit.", + "descriptionUrl": "https://kubernetes.io/docs/concepts/services-networking/ingress/#tls", + "platform": "Kubernetes", + "descriptionID": "0dcbf4a2", + "cloudProvider": "common", + "cwe": "319", + "riskScore": "7.5" +} \ No newline at end of file diff --git a/assets/queries/k8s/ingress_without_tls/query.rego b/assets/queries/k8s/ingress_without_tls/query.rego new file mode 100644 index 00000000000..c62669402d6 --- /dev/null +++ b/assets/queries/k8s/ingress_without_tls/query.rego @@ -0,0 +1,40 @@ +package Cx + +import data.generic.common as common_lib + +CxPolicy[result] { + document := input.document[i] + document.kind == "Ingress" + metadata := document.metadata + not common_lib.valid_key(document.spec, "tls") + + result := { + "documentId": document.id, + "resourceType": document.kind, + "resourceName": metadata.name, + "searchKey": sprintf("metadata.name={{%s}}.spec", [metadata.name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("Ingress '%s' should have 'spec.tls' configured", [metadata.name]), + "keyActualValue": sprintf("Ingress '%s' does not have 'spec.tls' configured; traffic is served over HTTP", [metadata.name]), + "searchLine": common_lib.build_search_line(["spec"], []), + } +} + +CxPolicy[result] { + document := input.document[i] + document.kind == "Ingress" + metadata := document.metadata + tls_entries := document.spec.tls + count(tls_entries) == 0 + + result := { + "documentId": document.id, + "resourceType": document.kind, + "resourceName": metadata.name, + "searchKey": sprintf("metadata.name={{%s}}.spec.tls", [metadata.name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("Ingress '%s' should have at least one TLS entry in 'spec.tls'", [metadata.name]), + "keyActualValue": sprintf("Ingress '%s' has an empty 'spec.tls' list", [metadata.name]), + "searchLine": common_lib.build_search_line(["spec", "tls"], []), + } +} diff --git a/assets/queries/k8s/ingress_without_tls/test/negative1.yaml b/assets/queries/k8s/ingress_without_tls/test/negative1.yaml new file mode 100644 index 00000000000..e7618d4a41a --- /dev/null +++ b/assets/queries/k8s/ingress_without_tls/test/negative1.yaml @@ -0,0 +1,20 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: negative-ingress +spec: + tls: + - hosts: + - example.com + secretName: example-tls + rules: + - host: example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: my-service + port: + number: 80 diff --git a/assets/queries/k8s/ingress_without_tls/test/positive1.yaml b/assets/queries/k8s/ingress_without_tls/test/positive1.yaml new file mode 100644 index 00000000000..d204c9d6c94 --- /dev/null +++ b/assets/queries/k8s/ingress_without_tls/test/positive1.yaml @@ -0,0 +1,16 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: positive-ingress +spec: + rules: + - host: example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: my-service + port: + number: 80 diff --git a/assets/queries/k8s/ingress_without_tls/test/positive_expected_result.json b/assets/queries/k8s/ingress_without_tls/test/positive_expected_result.json new file mode 100644 index 00000000000..386e92aba3f --- /dev/null +++ b/assets/queries/k8s/ingress_without_tls/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Ingress Without TLS", + "severity": "HIGH", + "line": 5, + "fileName": "positive1.yaml" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json b/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json new file mode 100644 index 00000000000..33dbb51be4d --- /dev/null +++ b/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "f979bf87-34fd-4bab-a5b1-530268a581d5", + "queryName": "Beta - Backup Vault Without KMS Key", + "severity": "MEDIUM", + "category": "Encryption", + "descriptionText": "AWS Backup Vaults should be encrypted using a customer-managed KMS key. Without a 'kms_key_arn', backups are protected only by the default AWS-managed key, offering no additional control over key rotation or access.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_vault#kms_key_arn", + "platform": "Terraform", + "descriptionID": "6df8a84c", + "cloudProvider": "aws", + "cwe": "311", + "riskScore": "5.5" +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/backup_vault_without_kms_key/query.rego b/assets/queries/terraform/aws/backup_vault_without_kms_key/query.rego new file mode 100644 index 00000000000..09d60fa3fcf --- /dev/null +++ b/assets/queries/terraform/aws/backup_vault_without_kms_key/query.rego @@ -0,0 +1,22 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.aws_backup_vault[name] + not common_lib.valid_key(resource, "kms_key_arn") + + result := { + "documentId": input.document[i].id, + "resourceType": "aws_backup_vault", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("aws_backup_vault[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'aws_backup_vault[%s].kms_key_arn' should be defined", [name]), + "keyActualValue": sprintf("'aws_backup_vault[%s].kms_key_arn' is not defined; vault uses AWS-managed key", [name]), + "searchLine": common_lib.build_search_line(["resource", "aws_backup_vault", name], []), + "remediation": "kms_key_arn = aws_kms_key.example.arn", + "remediationType": "addition", + } +} diff --git a/assets/queries/terraform/aws/backup_vault_without_kms_key/test/negative1.tf b/assets/queries/terraform/aws/backup_vault_without_kms_key/test/negative1.tf new file mode 100644 index 00000000000..20b595131c4 --- /dev/null +++ b/assets/queries/terraform/aws/backup_vault_without_kms_key/test/negative1.tf @@ -0,0 +1,4 @@ +resource "aws_backup_vault" "negative1" { + name = "example_vault" + kms_key_arn = aws_kms_key.example.arn +} diff --git a/assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive1.tf b/assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive1.tf new file mode 100644 index 00000000000..a94ff9f997e --- /dev/null +++ b/assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive1.tf @@ -0,0 +1,3 @@ +resource "aws_backup_vault" "positive1" { + name = "example_vault" +} diff --git a/assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive_expected_result.json b/assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive_expected_result.json new file mode 100644 index 00000000000..c9cdd590efe --- /dev/null +++ b/assets/queries/terraform/aws/backup_vault_without_kms_key/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Backup Vault Without KMS Key", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive1.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json b/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json new file mode 100644 index 00000000000..20fe36e724d --- /dev/null +++ b/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "0cbdf8fb-83cd-418f-918f-de86df0621b6", + "queryName": "Beta - Lambda Function URL Without Authentication", + "severity": "HIGH", + "category": "Access Control", + "descriptionText": "AWS Lambda Function URLs should require authentication. Setting 'authorization_type' to 'NONE' allows unauthenticated public invocation of the function, exposing it to abuse or data exfiltration.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function_url#authorization_type", + "platform": "Terraform", + "descriptionID": "1c4bf6dc", + "cloudProvider": "aws", + "cwe": "306", + "riskScore": "8.1" +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/lambda_function_url_without_authentication/query.rego b/assets/queries/terraform/aws/lambda_function_url_without_authentication/query.rego new file mode 100644 index 00000000000..cc4db8b5dd7 --- /dev/null +++ b/assets/queries/terraform/aws/lambda_function_url_without_authentication/query.rego @@ -0,0 +1,22 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.aws_lambda_function_url[name] + resource.authorization_type == "NONE" + + result := { + "documentId": input.document[i].id, + "resourceType": "aws_lambda_function_url", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("aws_lambda_function_url[%s].authorization_type", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'aws_lambda_function_url[%s].authorization_type' should not be 'NONE'", [name]), + "keyActualValue": sprintf("'aws_lambda_function_url[%s].authorization_type' is 'NONE', allowing unauthenticated invocations", [name]), + "searchLine": common_lib.build_search_line(["resource", "aws_lambda_function_url", name, "authorization_type"], []), + "remediation": "authorization_type = \"AWS_IAM\"", + "remediationType": "replacement", + } +} diff --git a/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/negative1.tf b/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/negative1.tf new file mode 100644 index 00000000000..9577d0039e0 --- /dev/null +++ b/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/negative1.tf @@ -0,0 +1,4 @@ +resource "aws_lambda_function_url" "negative1" { + function_name = aws_lambda_function.example.function_name + authorization_type = "AWS_IAM" +} diff --git a/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive1.tf b/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive1.tf new file mode 100644 index 00000000000..095e2667520 --- /dev/null +++ b/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive1.tf @@ -0,0 +1,4 @@ +resource "aws_lambda_function_url" "positive1" { + function_name = aws_lambda_function.example.function_name + authorization_type = "NONE" +} diff --git a/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive_expected_result.json b/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive_expected_result.json new file mode 100644 index 00000000000..c51760d4f23 --- /dev/null +++ b/assets/queries/terraform/aws/lambda_function_url_without_authentication/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Lambda Function URL Without Authentication", + "severity": "HIGH", + "line": 3, + "fileName": "positive1.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json new file mode 100644 index 00000000000..79ef7dfce2a --- /dev/null +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "ef088173-6ce6-46b6-af2e-708ab73737c1", + "queryName": "Beta - Transfer Family Server Publicly Accessible", + "severity": "HIGH", + "category": "Networking and Firewall", + "descriptionText": "AWS Transfer Family servers should use VPC endpoint type instead of PUBLIC to restrict access and reduce the attack surface. Public endpoints expose the file transfer service directly to the internet.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/transfer_server#endpoint_type", + "platform": "Terraform", + "descriptionID": "1d9081ec", + "cloudProvider": "aws", + "cwe": "668", + "riskScore": "7.5" +} \ No newline at end of file diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/query.rego b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/query.rego new file mode 100644 index 00000000000..e5aba02eb10 --- /dev/null +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/query.rego @@ -0,0 +1,23 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.aws_transfer_server[name] + endpoint := object.get(resource, "endpoint_type", "PUBLIC") + endpoint != "VPC" + + result := { + "documentId": input.document[i].id, + "resourceType": "aws_transfer_server", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("aws_transfer_server[%s].endpoint_type", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'aws_transfer_server[%s].endpoint_type' should be 'VPC'", [name]), + "keyActualValue": sprintf("'aws_transfer_server[%s].endpoint_type' is '%s'", [name, endpoint]), + "searchLine": common_lib.build_search_line(["resource", "aws_transfer_server", name, "endpoint_type"], []), + "remediation": "endpoint_type = \"VPC\"", + "remediationType": "replacement", + } +} diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/negative1.tf b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/negative1.tf new file mode 100644 index 00000000000..f9a413622d3 --- /dev/null +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/negative1.tf @@ -0,0 +1,7 @@ +resource "aws_transfer_server" "negative1" { + identity_provider_type = "SERVICE_MANAGED" + endpoint_type = "VPC" + endpoint_details { + vpc_id = aws_vpc.example.id + } +} diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive1.tf b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive1.tf new file mode 100644 index 00000000000..2728be2f100 --- /dev/null +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive1.tf @@ -0,0 +1,4 @@ +resource "aws_transfer_server" "positive1" { + identity_provider_type = "SERVICE_MANAGED" + endpoint_type = "PUBLIC" +} diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive2.tf b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive2.tf new file mode 100644 index 00000000000..7a01ae4b32e --- /dev/null +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive2.tf @@ -0,0 +1,3 @@ +resource "aws_transfer_server" "positive2" { + identity_provider_type = "SERVICE_MANAGED" +} diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive_expected_result.json b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive_expected_result.json new file mode 100644 index 00000000000..95c458d90f7 --- /dev/null +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/test/positive_expected_result.json @@ -0,0 +1,14 @@ +[ + { + "queryName": "Beta - Transfer Family Server Publicly Accessible", + "severity": "HIGH", + "line": 3, + "fileName": "positive1.tf" + }, + { + "queryName": "Beta - Transfer Family Server Publicly Accessible", + "severity": "HIGH", + "line": 1, + "fileName": "positive2.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json b/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json new file mode 100644 index 00000000000..ca0c025277d --- /dev/null +++ b/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "beb57138-c9ee-421a-8332-6224ab3a2a6a", + "queryName": "Beta - AKS Defender Profile Disabled", + "severity": "MEDIUM", + "category": "Observability", + "descriptionText": "Azure Kubernetes Service clusters should have Microsoft Defender enabled via the 'microsoft_defender' block. Without it, threat detection for the cluster workloads is not active, leaving security incidents undetected.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#microsoft_defender", + "platform": "Terraform", + "descriptionID": "f8f4f141", + "cloudProvider": "azure", + "cwe": "778", + "riskScore": "5.3" +} \ No newline at end of file diff --git a/assets/queries/terraform/azure/aks_defender_profile_disabled/query.rego b/assets/queries/terraform/azure/aks_defender_profile_disabled/query.rego new file mode 100644 index 00000000000..884771f88a8 --- /dev/null +++ b/assets/queries/terraform/azure/aks_defender_profile_disabled/query.rego @@ -0,0 +1,22 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.azurerm_kubernetes_cluster[name] + not common_lib.valid_key(resource, "microsoft_defender") + + result := { + "documentId": input.document[i].id, + "resourceType": "azurerm_kubernetes_cluster", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("azurerm_kubernetes_cluster[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'azurerm_kubernetes_cluster[%s].microsoft_defender' should be configured", [name]), + "keyActualValue": sprintf("'azurerm_kubernetes_cluster[%s].microsoft_defender' is not defined", [name]), + "searchLine": common_lib.build_search_line(["resource", "azurerm_kubernetes_cluster", name], []), + "remediation": "microsoft_defender {\n log_analytics_workspace_id = azurerm_log_analytics_workspace.example.id\n }", + "remediationType": "addition", + } +} diff --git a/assets/queries/terraform/azure/aks_defender_profile_disabled/test/negative1.tf b/assets/queries/terraform/azure/aks_defender_profile_disabled/test/negative1.tf new file mode 100644 index 00000000000..45757fd915d --- /dev/null +++ b/assets/queries/terraform/azure/aks_defender_profile_disabled/test/negative1.tf @@ -0,0 +1,17 @@ +resource "azurerm_kubernetes_cluster" "negative1" { + name = "example-aks" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + dns_prefix = "exampleaks" + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_D2_v2" + } + identity { + type = "SystemAssigned" + } + microsoft_defender { + log_analytics_workspace_id = azurerm_log_analytics_workspace.example.id + } +} diff --git a/assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive1.tf b/assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive1.tf new file mode 100644 index 00000000000..04157c1e49d --- /dev/null +++ b/assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive1.tf @@ -0,0 +1,14 @@ +resource "azurerm_kubernetes_cluster" "positive1" { + name = "example-aks" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + dns_prefix = "exampleaks" + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_D2_v2" + } + identity { + type = "SystemAssigned" + } +} diff --git a/assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive_expected_result.json b/assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive_expected_result.json new file mode 100644 index 00000000000..398ac164f1e --- /dev/null +++ b/assets/queries/terraform/azure/aks_defender_profile_disabled/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - AKS Defender Profile Disabled", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive1.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json new file mode 100644 index 00000000000..917f45a6b1e --- /dev/null +++ b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "34d7d523-ed2c-43f4-9c20-ca22d07a0f56", + "queryName": "Beta - Machine Learning Workspace Without CMK", + "severity": "MEDIUM", + "category": "Encryption", + "descriptionText": "Azure Machine Learning workspaces store model artifacts, datasets, and experiment logs. These should be encrypted with a customer-managed key using the 'encryption' block to meet data residency and compliance requirements.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/machine_learning_workspace#encryption", + "platform": "Terraform", + "descriptionID": "b489594d", + "cloudProvider": "azure", + "cwe": "311", + "riskScore": "5.0" +} \ No newline at end of file diff --git a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/query.rego b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/query.rego new file mode 100644 index 00000000000..fda7e6e583d --- /dev/null +++ b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/query.rego @@ -0,0 +1,22 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.azurerm_machine_learning_workspace[name] + not common_lib.valid_key(resource, "encryption") + + result := { + "documentId": input.document[i].id, + "resourceType": "azurerm_machine_learning_workspace", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("azurerm_machine_learning_workspace[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'azurerm_machine_learning_workspace[%s].encryption' should be defined with a customer-managed key", [name]), + "keyActualValue": sprintf("'azurerm_machine_learning_workspace[%s].encryption' is not defined; using Microsoft-managed key", [name]), + "searchLine": common_lib.build_search_line(["resource", "azurerm_machine_learning_workspace", name], []), + "remediation": "encryption {\n key_vault_id = azurerm_key_vault.example.id\n key_id = azurerm_key_vault_key.example.id\n }", + "remediationType": "addition", + } +} diff --git a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/negative1.tf b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/negative1.tf new file mode 100644 index 00000000000..1786dcab8ad --- /dev/null +++ b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/negative1.tf @@ -0,0 +1,15 @@ +resource "azurerm_machine_learning_workspace" "negative1" { + name = "example-mlworkspace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + application_insights_id = azurerm_application_insights.example.id + key_vault_id = azurerm_key_vault.example.id + storage_account_id = azurerm_storage_account.example.id + identity { + type = "SystemAssigned" + } + encryption { + key_vault_id = azurerm_key_vault.example.id + key_id = azurerm_key_vault_key.example.id + } +} diff --git a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive1.tf b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive1.tf new file mode 100644 index 00000000000..10c248ff30e --- /dev/null +++ b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive1.tf @@ -0,0 +1,11 @@ +resource "azurerm_machine_learning_workspace" "positive1" { + name = "example-mlworkspace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + application_insights_id = azurerm_application_insights.example.id + key_vault_id = azurerm_key_vault.example.id + storage_account_id = azurerm_storage_account.example.id + identity { + type = "SystemAssigned" + } +} diff --git a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive_expected_result.json b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive_expected_result.json new file mode 100644 index 00000000000..18cc9f05af5 --- /dev/null +++ b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Machine Learning Workspace Without CMK", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive1.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json new file mode 100644 index 00000000000..9e4d6ba56c9 --- /dev/null +++ b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "8a800912-0bcb-441c-aa95-306d3d9a7bdd", + "queryName": "Beta - Service Bus Namespace Without CMK", + "severity": "LOW", + "category": "Encryption", + "descriptionText": "Azure Service Bus namespaces should be encrypted with a customer-managed key (CMK) for enhanced control over encryption keys. Without a 'customer_managed_key' block, Microsoft-managed keys are used with no customer key management.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/servicebus_namespace#customer_managed_key", + "platform": "Terraform", + "descriptionID": "39e5eb1f", + "cloudProvider": "azure", + "cwe": "311", + "riskScore": "3.0" +} \ No newline at end of file diff --git a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/query.rego b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/query.rego new file mode 100644 index 00000000000..2068a9ebab8 --- /dev/null +++ b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/query.rego @@ -0,0 +1,22 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.azurerm_servicebus_namespace[name] + not common_lib.valid_key(resource, "customer_managed_key") + + result := { + "documentId": input.document[i].id, + "resourceType": "azurerm_servicebus_namespace", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("azurerm_servicebus_namespace[%s]", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'azurerm_servicebus_namespace[%s].customer_managed_key' should be defined", [name]), + "keyActualValue": sprintf("'azurerm_servicebus_namespace[%s].customer_managed_key' is not defined; using Microsoft-managed key", [name]), + "searchLine": common_lib.build_search_line(["resource", "azurerm_servicebus_namespace", name], []), + "remediation": "customer_managed_key {\n key_vault_key_id = azurerm_key_vault_key.example.id\n identity_id = azurerm_user_assigned_identity.example.id\n }", + "remediationType": "addition", + } +} diff --git a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/negative1.tf b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/negative1.tf new file mode 100644 index 00000000000..2c535a3a434 --- /dev/null +++ b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/negative1.tf @@ -0,0 +1,10 @@ +resource "azurerm_servicebus_namespace" "negative1" { + name = "example-sbnamespace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "Premium" + customer_managed_key { + key_vault_key_id = azurerm_key_vault_key.example.id + identity_id = azurerm_user_assigned_identity.example.id + } +} diff --git a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive1.tf b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive1.tf new file mode 100644 index 00000000000..b3824d1445c --- /dev/null +++ b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive1.tf @@ -0,0 +1,6 @@ +resource "azurerm_servicebus_namespace" "positive1" { + name = "example-sbnamespace" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku = "Premium" +} diff --git a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive_expected_result.json b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive_expected_result.json new file mode 100644 index 00000000000..c0ffa818ee0 --- /dev/null +++ b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/test/positive_expected_result.json @@ -0,0 +1,8 @@ +[ + { + "queryName": "Beta - Service Bus Namespace Without CMK", + "severity": "LOW", + "line": 1, + "fileName": "positive1.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json new file mode 100644 index 00000000000..6a084aa512b --- /dev/null +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "664c673f-71f2-4a7f-a54a-2efa25e8567f", + "queryName": "Beta - Artifact Registry Repository With Public Access", + "severity": "HIGH", + "category": "Access Control", + "descriptionText": "GCP Artifact Registry repositories should not grant access to 'allUsers' or 'allAuthenticatedUsers'. Public access allows anyone to read or push container images and packages, risking supply chain attacks or data leakage.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/artifact_registry_repository_iam_member", + "platform": "Terraform", + "descriptionID": "3116634b", + "cloudProvider": "gcp", + "cwe": "284", + "riskScore": "8.2" +} \ No newline at end of file diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/query.rego b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/query.rego new file mode 100644 index 00000000000..535e8340eb0 --- /dev/null +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/query.rego @@ -0,0 +1,43 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +public_members := {"allUsers", "allAuthenticatedUsers"} + +CxPolicy[result] { + resource := input.document[i].resource.google_artifact_registry_repository_iam_member[name] + resource.member == public_members[_] + + result := { + "documentId": input.document[i].id, + "resourceType": "google_artifact_registry_repository_iam_member", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("google_artifact_registry_repository_iam_member[%s].member", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'google_artifact_registry_repository_iam_member[%s].member' should not be 'allUsers' or 'allAuthenticatedUsers'", [name]), + "keyActualValue": sprintf("'google_artifact_registry_repository_iam_member[%s].member' is '%s'", [name, resource.member]), + "searchLine": common_lib.build_search_line(["resource", "google_artifact_registry_repository_iam_member", name, "member"], []), + "remediation": "Replace public member with a specific service account or group identity", + "remediationType": "replacement", + } +} + +CxPolicy[result] { + resource := input.document[i].resource.google_artifact_registry_repository_iam_binding[name] + member := resource.members[_] + member == public_members[_] + + result := { + "documentId": input.document[i].id, + "resourceType": "google_artifact_registry_repository_iam_binding", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("google_artifact_registry_repository_iam_binding[%s].members", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'google_artifact_registry_repository_iam_binding[%s].members' should not include public identities", [name]), + "keyActualValue": sprintf("'google_artifact_registry_repository_iam_binding[%s].members' contains '%s'", [name, member]), + "searchLine": common_lib.build_search_line(["resource", "google_artifact_registry_repository_iam_binding", name, "members"], []), + "remediation": "Remove public identities from members", + "remediationType": "removal", + } +} diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/negative1.tf b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/negative1.tf new file mode 100644 index 00000000000..44d93ecdab4 --- /dev/null +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/negative1.tf @@ -0,0 +1,6 @@ +resource "google_artifact_registry_repository_iam_member" "negative1" { + repository = google_artifact_registry_repository.my_repo.name + location = google_artifact_registry_repository.my_repo.location + role = "roles/artifactregistry.reader" + member = "serviceAccount:ci-runner@project.iam.gserviceaccount.com" +} diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive1.tf b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive1.tf new file mode 100644 index 00000000000..07aad5b33cd --- /dev/null +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive1.tf @@ -0,0 +1,6 @@ +resource "google_artifact_registry_repository_iam_member" "positive1" { + repository = google_artifact_registry_repository.my_repo.name + location = google_artifact_registry_repository.my_repo.location + role = "roles/artifactregistry.reader" + member = "allUsers" +} diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive2.tf b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive2.tf new file mode 100644 index 00000000000..212d0476fed --- /dev/null +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive2.tf @@ -0,0 +1,6 @@ +resource "google_artifact_registry_repository_iam_binding" "positive2" { + repository = google_artifact_registry_repository.my_repo.name + location = google_artifact_registry_repository.my_repo.location + role = "roles/artifactregistry.reader" + members = ["allAuthenticatedUsers"] +} diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive_expected_result.json b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive_expected_result.json new file mode 100644 index 00000000000..83452caeb90 --- /dev/null +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/test/positive_expected_result.json @@ -0,0 +1,14 @@ +[ + { + "queryName": "Beta - Artifact Registry Repository With Public Access", + "severity": "HIGH", + "line": 5, + "fileName": "positive1.tf" + }, + { + "queryName": "Beta - Artifact Registry Repository With Public Access", + "severity": "HIGH", + "line": 5, + "fileName": "positive2.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json new file mode 100644 index 00000000000..06cc2ade65a --- /dev/null +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "07a27a3b-46e9-4172-bc68-25e3277d7998", + "queryName": "Beta - Cloud Run Service Allows Unauthenticated Access", + "severity": "HIGH", + "category": "Access Control", + "descriptionText": "GCP Cloud Run services should not allow unauthenticated invocations. Granting 'roles/run.invoker' to 'allUsers' exposes the service publicly without authentication, enabling potential abuse or data exposure.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloud_run_service_iam_member", + "platform": "Terraform", + "descriptionID": "b89d8324", + "cloudProvider": "gcp", + "cwe": "306", + "riskScore": "8.0" +} \ No newline at end of file diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/query.rego b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/query.rego new file mode 100644 index 00000000000..a7e0b7686c0 --- /dev/null +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/query.rego @@ -0,0 +1,40 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.google_cloud_run_service_iam_member[name] + resource.member == "allUsers" + + result := { + "documentId": input.document[i].id, + "resourceType": "google_cloud_run_service_iam_member", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("google_cloud_run_service_iam_member[%s].member", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'google_cloud_run_service_iam_member[%s].member' should not be 'allUsers'", [name]), + "keyActualValue": sprintf("'google_cloud_run_service_iam_member[%s].member' is 'allUsers', allowing unauthenticated access", [name]), + "searchLine": common_lib.build_search_line(["resource", "google_cloud_run_service_iam_member", name, "member"], []), + "remediation": "Remove 'allUsers' member and use specific service accounts or authenticated identities", + "remediationType": "removal", + } +} + +CxPolicy[result] { + resource := input.document[i].resource.google_cloud_run_service_iam_binding[name] + resource.members[_] == "allUsers" + + result := { + "documentId": input.document[i].id, + "resourceType": "google_cloud_run_service_iam_binding", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("google_cloud_run_service_iam_binding[%s].members", [name]), + "issueType": "IncorrectValue", + "keyExpectedValue": sprintf("'google_cloud_run_service_iam_binding[%s].members' should not contain 'allUsers'", [name]), + "keyActualValue": sprintf("'google_cloud_run_service_iam_binding[%s].members' contains 'allUsers', allowing unauthenticated access", [name]), + "searchLine": common_lib.build_search_line(["resource", "google_cloud_run_service_iam_binding", name, "members"], []), + "remediation": "Remove 'allUsers' from members and use specific authenticated identities", + "remediationType": "removal", + } +} diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/negative1.tf b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/negative1.tf new file mode 100644 index 00000000000..731733d3dc4 --- /dev/null +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/negative1.tf @@ -0,0 +1,6 @@ +resource "google_cloud_run_service_iam_member" "negative1" { + service = google_cloud_run_service.default.name + location = google_cloud_run_service.default.location + role = "roles/run.invoker" + member = "serviceAccount:my-service-account@project.iam.gserviceaccount.com" +} diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive1.tf b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive1.tf new file mode 100644 index 00000000000..dc21bd32ae7 --- /dev/null +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive1.tf @@ -0,0 +1,6 @@ +resource "google_cloud_run_service_iam_member" "positive1" { + service = google_cloud_run_service.default.name + location = google_cloud_run_service.default.location + role = "roles/run.invoker" + member = "allUsers" +} diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive2.tf b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive2.tf new file mode 100644 index 00000000000..5a9bc9b34f1 --- /dev/null +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive2.tf @@ -0,0 +1,6 @@ +resource "google_cloud_run_service_iam_binding" "positive2" { + service = google_cloud_run_service.default.name + location = google_cloud_run_service.default.location + role = "roles/run.invoker" + members = ["allUsers", "serviceAccount:my-sa@project.iam.gserviceaccount.com"] +} diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive_expected_result.json b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive_expected_result.json new file mode 100644 index 00000000000..fb483861be0 --- /dev/null +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/test/positive_expected_result.json @@ -0,0 +1,14 @@ +[ + { + "queryName": "Beta - Cloud Run Service Allows Unauthenticated Access", + "severity": "HIGH", + "line": 5, + "fileName": "positive1.tf" + }, + { + "queryName": "Beta - Cloud Run Service Allows Unauthenticated Access", + "severity": "HIGH", + "line": 5, + "fileName": "positive2.tf" + } +] \ No newline at end of file diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json new file mode 100644 index 00000000000..81c865d3a7a --- /dev/null +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json @@ -0,0 +1,13 @@ +{ + "id": "fe0ff686-f344-4d06-ba0c-84321161aebb", + "queryName": "Beta - Secret Manager Secret Without CMEK", + "severity": "MEDIUM", + "category": "Encryption", + "descriptionText": "GCP Secret Manager secrets should use customer-managed encryption keys (CMEK) for enhanced key control. Without a 'customer_managed_encryption.kms_key_name' in the replication config, secrets are encrypted with Google-managed keys.", + "descriptionUrl": "https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/secret_manager_secret#customer_managed_encryption", + "platform": "Terraform", + "descriptionID": "9be17ab9", + "cloudProvider": "gcp", + "cwe": "311", + "riskScore": "5.0" +} \ No newline at end of file diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/query.rego b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/query.rego new file mode 100644 index 00000000000..ab38ccba04a --- /dev/null +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/query.rego @@ -0,0 +1,33 @@ +package Cx + +import data.generic.common as common_lib +import data.generic.terraform as tf_lib + +CxPolicy[result] { + resource := input.document[i].resource.google_secret_manager_secret[name] + replication := object.get(resource, "replication", {}) + not has_cmek(replication) + + result := { + "documentId": input.document[i].id, + "resourceType": "google_secret_manager_secret", + "resourceName": tf_lib.get_resource_name(resource, name), + "searchKey": sprintf("google_secret_manager_secret[%s].replication", [name]), + "issueType": "MissingAttribute", + "keyExpectedValue": sprintf("'google_secret_manager_secret[%s]' should configure customer_managed_encryption with a KMS key", [name]), + "keyActualValue": sprintf("'google_secret_manager_secret[%s]' uses Google-managed encryption keys", [name]), + "searchLine": common_lib.build_search_line(["resource", "google_secret_manager_secret", name, "replication"], []), + "remediation": "replication {\n user_managed {\n replicas {\n location = \"us-central1\"\n customer_managed_encryption {\n kms_key_name = google_kms_crypto_key.example.id\n }\n }\n }\n }", + "remediationType": "replacement", + } +} + +has_cmek(replication) { + is_object(replication.user_managed) + replication.user_managed.replicas[_].customer_managed_encryption.kms_key_name != "" +} + +has_cmek(replication) { + is_array(replication.user_managed.replicas) + replication.user_managed.replicas[_].customer_managed_encryption.kms_key_name != "" +} diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/negative1.tf b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/negative1.tf new file mode 100644 index 00000000000..4a112a2123e --- /dev/null +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/negative1.tf @@ -0,0 +1,13 @@ +resource "google_secret_manager_secret" "negative1" { + secret_id = "my-secret" + replication { + user_managed { + replicas { + location = "us-central1" + customer_managed_encryption { + kms_key_name = google_kms_crypto_key.example.id + } + } + } + } +} diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive1.tf b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive1.tf new file mode 100644 index 00000000000..0fe27f8127a --- /dev/null +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive1.tf @@ -0,0 +1,6 @@ +resource "google_secret_manager_secret" "positive1" { + secret_id = "my-secret" + replication { + auto {} + } +} diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive2.tf b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive2.tf new file mode 100644 index 00000000000..a8fc758bf5a --- /dev/null +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive2.tf @@ -0,0 +1,10 @@ +resource "google_secret_manager_secret" "positive2" { + secret_id = "my-secret" + replication { + user_managed { + replicas { + location = "us-central1" + } + } + } +} diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive_expected_result.json b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive_expected_result.json new file mode 100644 index 00000000000..ae905454f1f --- /dev/null +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/test/positive_expected_result.json @@ -0,0 +1,14 @@ +[ + { + "queryName": "Beta - Secret Manager Secret Without CMEK", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive1.tf" + }, + { + "queryName": "Beta - Secret Manager Secret Without CMEK", + "severity": "MEDIUM", + "line": 1, + "fileName": "positive2.tf" + } +] \ No newline at end of file From 21bbbcca906d7b19c34e9551c4e5f2496dfc2990 Mon Sep 17 00:00:00 2001 From: Antero Silva Date: Mon, 9 Mar 2026 22:05:45 +0000 Subject: [PATCH 2/4] feat(queries): add experimental flag to all new Beta query metadata files Set "experimental": "true" in metadata.json for all 12 newly created Beta queries across AWS, Azure, GCP, K8s, and Dockerfile platforms, aligning with the existing KICS convention for Beta queries. Co-Authored-By: Claude Sonnet 4.6 --- .../dockerfile/env_instruction_has_secret/metadata.json | 3 ++- .../k8s/container_seccomp_profile_not_set/metadata.json | 3 ++- assets/queries/k8s/ingress_without_tls/metadata.json | 3 ++- .../terraform/aws/backup_vault_without_kms_key/metadata.json | 3 ++- .../lambda_function_url_without_authentication/metadata.json | 3 ++- .../transfer_family_server_publicly_accessible/metadata.json | 3 ++- .../azure/aks_defender_profile_disabled/metadata.json | 3 ++- .../azure/machine_learning_workspace_without_cmk/metadata.json | 3 ++- .../azure/service_bus_namespace_without_cmk/metadata.json | 3 ++- .../artifact_registry_repository_public_access/metadata.json | 3 ++- .../gcp/cloud_run_service_allows_unauthenticated/metadata.json | 3 ++- .../gcp/secret_manager_secret_without_cmek/metadata.json | 3 ++- 12 files changed, 24 insertions(+), 12 deletions(-) diff --git a/assets/queries/dockerfile/env_instruction_has_secret/metadata.json b/assets/queries/dockerfile/env_instruction_has_secret/metadata.json index 5a1db5890cd..e6d01cb3d7b 100644 --- a/assets/queries/dockerfile/env_instruction_has_secret/metadata.json +++ b/assets/queries/dockerfile/env_instruction_has_secret/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "7abccf53", "cloudProvider": "common", "cwe": "798", - "riskScore": "8.5" + "riskScore": "8.5", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json b/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json index 23da50a48b1..1f696f0ceae 100644 --- a/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json +++ b/assets/queries/k8s/container_seccomp_profile_not_set/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "30a7f7cc", "cloudProvider": "common", "cwe": "250", - "riskScore": "5.5" + "riskScore": "5.5", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/k8s/ingress_without_tls/metadata.json b/assets/queries/k8s/ingress_without_tls/metadata.json index af9fe6f2814..bf88ab507af 100644 --- a/assets/queries/k8s/ingress_without_tls/metadata.json +++ b/assets/queries/k8s/ingress_without_tls/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "0dcbf4a2", "cloudProvider": "common", "cwe": "319", - "riskScore": "7.5" + "riskScore": "7.5", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json b/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json index 33dbb51be4d..fa257ecf6bb 100644 --- a/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json +++ b/assets/queries/terraform/aws/backup_vault_without_kms_key/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "6df8a84c", "cloudProvider": "aws", "cwe": "311", - "riskScore": "5.5" + "riskScore": "5.5", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json b/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json index 20fe36e724d..951bcf7bc3e 100644 --- a/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json +++ b/assets/queries/terraform/aws/lambda_function_url_without_authentication/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "1c4bf6dc", "cloudProvider": "aws", "cwe": "306", - "riskScore": "8.1" + "riskScore": "8.1", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json index 79ef7dfce2a..a19da0c694d 100644 --- a/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json +++ b/assets/queries/terraform/aws/transfer_family_server_publicly_accessible/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "1d9081ec", "cloudProvider": "aws", "cwe": "668", - "riskScore": "7.5" + "riskScore": "7.5", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json b/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json index ca0c025277d..aa5a36a631c 100644 --- a/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json +++ b/assets/queries/terraform/azure/aks_defender_profile_disabled/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "f8f4f141", "cloudProvider": "azure", "cwe": "778", - "riskScore": "5.3" + "riskScore": "5.3", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json index 917f45a6b1e..7d5b42849c5 100644 --- a/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json +++ b/assets/queries/terraform/azure/machine_learning_workspace_without_cmk/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "b489594d", "cloudProvider": "azure", "cwe": "311", - "riskScore": "5.0" + "riskScore": "5.0", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json index 9e4d6ba56c9..c3894c8e6db 100644 --- a/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json +++ b/assets/queries/terraform/azure/service_bus_namespace_without_cmk/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "39e5eb1f", "cloudProvider": "azure", "cwe": "311", - "riskScore": "3.0" + "riskScore": "3.0", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json index 6a084aa512b..cc85c77d0df 100644 --- a/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json +++ b/assets/queries/terraform/gcp/artifact_registry_repository_public_access/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "3116634b", "cloudProvider": "gcp", "cwe": "284", - "riskScore": "8.2" + "riskScore": "8.2", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json index 06cc2ade65a..ad6bf39b261 100644 --- a/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json +++ b/assets/queries/terraform/gcp/cloud_run_service_allows_unauthenticated/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "b89d8324", "cloudProvider": "gcp", "cwe": "306", - "riskScore": "8.0" + "riskScore": "8.0", + "experimental": "true" } \ No newline at end of file diff --git a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json index 81c865d3a7a..e6f9b47e501 100644 --- a/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json +++ b/assets/queries/terraform/gcp/secret_manager_secret_without_cmek/metadata.json @@ -9,5 +9,6 @@ "descriptionID": "9be17ab9", "cloudProvider": "gcp", "cwe": "311", - "riskScore": "5.0" + "riskScore": "5.0", + "experimental": "true" } \ No newline at end of file From 451b17a0f8c1ff2e390f031d890bd5840ebdb1d4 Mon Sep 17 00:00:00 2001 From: Antero Silva Date: Wed, 11 Mar 2026 11:38:36 +0000 Subject: [PATCH 3/4] Update positive.yaml --- .../test/positive.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/positive.yaml b/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/positive.yaml index 4188b2e53d4..f3b12fac6e6 100644 --- a/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/positive.yaml +++ b/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/positive.yaml @@ -1,12 +1,13 @@ +--- apiVersion: apps/v1 kind: Deployment metadata: name: label-mismatch spec: + replicas: 3 selector: matchLabels: app: web-store - replicas: 3 template: metadata: labels: @@ -18,25 +19,25 @@ spec: - labelSelector: matchLabels: app: web-store - topologyKey: "kubernetes.io/hostname" + topologyKey: kubernetes.io/hostname containers: - - name: web-app - image: nginx:1.16-alpine + - image: nginx:1.16-alpine + name: web-app --- apiVersion: apps/v1 kind: Deployment metadata: name: no-affinity spec: + replicas: 3 selector: matchLabels: app: web-store - replicas: 3 template: metadata: labels: app: web-store spec: containers: - - name: web-app - image: nginx:1.16-alpine + - image: nginx:1.16-alpine + name: web-app From 33cd1780d2dbd7305024c184806cb3b5ba191c9e Mon Sep 17 00:00:00 2001 From: Antero Silva Date: Wed, 11 Mar 2026 11:39:37 +0000 Subject: [PATCH 4/4] Update negative.yaml --- .../test/negative.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/negative.yaml b/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/negative.yaml index 806b28bab5a..13681533471 100644 --- a/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/negative.yaml +++ b/assets/queries/k8s/deployment_has_no_pod_anti_affinity/test/negative.yaml @@ -3,10 +3,10 @@ kind: Deployment metadata: name: web-server spec: + replicas: 3 selector: matchLabels: app: web-store - replicas: 3 template: metadata: labels: @@ -21,7 +21,7 @@ spec: operator: In values: - web-store - topologyKey: "kubernetes.io/hostname" + topologyKey: kubernetes.io/hostname containers: - - name: web-app - image: nginx:1.16-alpine \ No newline at end of file + - image: nginx:1.16-alpine + name: web-app