Mostrar resultados de seguridad con la API de Security Command Center

Los resultados de Security Command Center modelizan los posibles riesgos de seguridad de los recursos de un proyecto o una organización. Un resultado siempre está relacionado con un recurso específico de Security Command Center.

En esta guía se explica cómo usar las bibliotecas de cliente de Security Command Center para acceder a los resultados. Cada resultado pertenece a una fuente. La mayoría de los detectores o proveedores de resultados producen resultados en la misma fuente.

Los roles de gestión de identidades y accesos de Security Command Center se pueden conceder a nivel de organización, carpeta o proyecto. La posibilidad de ver, editar, crear o actualizar hallazgos, recursos y fuentes de seguridad depende del nivel de acceso que se te haya concedido. Para obtener más información sobre los roles de Security Command Center, consulta Control de acceso.

Antes de empezar

Antes de configurar una fuente, debes hacer lo siguiente:

Tamaño de página

Todas las APIs de lista de Security Command Center están paginadas. Cada respuesta devuelve una página de resultados y un token para devolver la página siguiente. El tamaño de la página se puede configurar. El tamaño de página predeterminado es 10. Puedes definir un mínimo de 1 y un máximo de 1000.

Retención de resultados

En función de tu nivel de Security Command Center, los resultados estarán disponibles para que los consultes o los busques durante un periodo determinado. Para obtener más información sobre la conservación de datos de Security Command Center, consulta el artículo Conservación de datos.

Mostrar todos los resultados

gcloud

Para enumerar todos los resultados de un proyecto, una carpeta o una organización, ejecuta el siguiente comando:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
  --location=LOCATION

Haz los cambios siguientes:

  • PARENT_TYPE: el nivel de la jerarquía de recursos para el que se deben enumerar los resultados. Use organizations, folders o projects.
  • PARENT_ID: el ID numérico de la organización, la carpeta o el proyecto, o el ID de proyecto alfanumérico.
  • LOCATION: la ubicación de Security Command Center en la que se deben enumerar las detecciones. Si la residencia de datos está habilitada, usa eu, sa o us. De lo contrario, usa el valor global.

Para ver más ejemplos, ejecuta el siguiente comando:

gcloud scc findings list --help

Para ver ejemplos en la documentación, consulta gcloud scc findings list.

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"google.golang.org/api/iterator"
)

// listFindings prints all findings in orgID to w. orgID is the numeric
// identifier of the organization.
func listFindings(w io.Writer, orgID string) error {
	// orgID := "12321311"
	// Instantiate a context and a security service client to make API calls.
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &securitycenterpb.ListFindingsRequest{
		// List findings across all sources.
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}/sources/-/locations/global"
		//		"projects/{projectId}/sources/-/locations/global"
		//		"folders/{folderId}/sources/-/locations/global"
		Parent: fmt.Sprintf("organizations/%s/sources/-/locations/global", orgID),
	}
	it := client.ListFindings(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("it.Next: %w", err)
		}
		finding := result.Finding
		fmt.Fprintf(w, "Finding Name: %s, ", finding.Name)
		fmt.Fprintf(w, "Resource Name %s, ", finding.ResourceName)
		fmt.Fprintf(w, "Category: %s\n", finding.Category)
	}
	return nil
}

Java


import com.google.cloud.securitycenter.v2.ListFindingsRequest;
import com.google.cloud.securitycenter.v2.ListFindingsResponse.ListFindingsResult;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import java.io.IOException;

public class ListAllFindings {

  public static void main(String[] args) throws IOException {
    // organizationId: The source to list all findings for.
    // You can also use project/ folder as the parent resource.
    String organizationId = "google-cloud-organization-id";

    // Specify the location to list the findings.
    String location = "global";

    // The source id to scope the findings.
    String sourceId = "source-id";

    listAllFindings(organizationId, sourceId, location);
  }

  // List all findings under a given parent resource.
  public static void listAllFindings(String organizationId, String sourceId, String location)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      ListFindingsRequest request =
          ListFindingsRequest.newBuilder()
              // To list findings across all sources, use "-".
              .setParent(
                  String.format("organizations/%s/sources/%s/locations/%s", organizationId,
                      sourceId,
                      location))
              .build();

      for (ListFindingsResult result : client.listFindings(request).iterateAll()) {
        System.out.printf("Finding: %s", result.getFinding().getName());
      }
      System.out.println("\nListing complete.");
    }
  }
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;

// Creates a new client.
const client = new SecurityCenterClient();

// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
const location = 'global';

// Required. Name of the source the findings belong to. If no location is
// specified, the default is global. The following list shows some examples:
// - `organizations/[organization_id]/sources/[source_id]/locations/[location_id]`
// - `folders/[folder_id]/sources/[source_id]`
// - `folders/[folder_id]/sources/[source_id]/locations/[location_id]`
// - `projects/[project_id]/sources/[source_id]`
// - `projects/[project_id]/sources/[source_id]/locations/[location_id]`
// To groupBy across all sources provide a source_id of `-`.
const parent = `organizations/${organizationId}/sources/-/locations/${location}`;

// Build the list findings request.
const listFindingsRequest = {
  parent,
};

async function listAllFindings() {
  // Call the API.
  const iterable = client.listFindingsAsync(listFindingsRequest);
  let count = 0;

  for await (const response of iterable) {
    // Just print a few for demonstration.
    if (count > 5) break;
    console.log(
      `${++count} ${response.finding.name} ${response.finding.resourceName}`
    );
  }
}

await listAllFindings();

Python

def list_all_findings(organization_id, source_name, location_id) -> int:
    """
    lists all findings for a source
    Args:
       organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
       source_name: is the resource path for a source that has been created
       location_id: GCP location id; example: 'global'
    Returns:
        int: returns the count of all findings for a source
    """
    from google.cloud import securitycenter_v2

    # Create a client.
    client = securitycenter_v2.SecurityCenterClient()
    parent = f"organizations/{organization_id}"
    all_sources = f"{parent}/sources/{source_name}/locations/{location_id}"

    # Create the request dictionary
    request = {"parent": all_sources}

    # Print the request for debugging
    print("Request: ", request)

    finding_result_iterator = client.list_findings(request={"parent": all_sources})
    for count, finding_result in enumerate(finding_result_iterator):
        print(
            "{}: name: {} resource: {}".format(
                count, finding_result.finding.name, finding_result.finding.resource_name
            )
        )
    return finding_result_iterator

La salida de cada resultado es similar a la siguiente:

{
  "finding": {
    "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID",
    "parent": "organizations/ORGANIZATION_ID/sources/SOURCE_ID",
    "resourceName": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER",
    "state": "ACTIVE",
    "category": "Malware: Cryptomining Bad Domain",
    "sourceProperties": {
      "sourceId": {
        "projectNumber": "PROJECT_NUMBER",
        "customerOrganizationNumber": "ORGANIZATION_ID"
      },
      "detectionCategory": {
        "technique": "cryptomining",
        "indicator": "domain",
        "ruleName": "bad_domain",
        "subRuleName": "cryptomining"
      },
      "detectionPriority": "LOW",
      "affectedResources": [
        {
          "gcpResourceName": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER"
        }
      ],
      "evidence": [
        {
          "sourceLogId": {
            "projectId": "PROJECT_ID",
            "resourceContainer": "projects/PROJECT_ID",
            "timestamp": {
              "seconds": "1636566099",
              "nanos": 5.41483849E8
            },
            "insertId": "INSERT_ID"
          }
        }
      ],
      "properties": {
        "domains": ["DOMAIN"],
        "instanceDetails": "/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_ID",
        "network": {
          "project": "PROJECT_ID",
          "location": "ZONE"
        },
        "dnsContexts": [
          {
            "authAnswer": true,
            "sourceIp": "SOURCE_IP_ADDRESS",
            "queryName": "DOMAIN",
            "queryType": "A",
            "responseCode": "NXDOMAIN"
          }
        ],
        "vpc": {
          "vpcName": "default"
        }
      },
      "findingId": "FINDING_ID",
      "contextUris": {
        "mitreUri": {
          "displayName": "MITRE Link",
          "url": "https://attack.mitre.org/techniques/T1496/"
        },
        "virustotalIndicatorQueryUri": [
          {
            "displayName": "VirusTotal Domain Link",
            "url": "https://www.virustotal.com/gui/domain/DOMAIN/detection"
          }
        ],
        "cloudLoggingQueryUri": [
          {
            "displayName": "Cloud Logging Query Link",
            "url": "https://console.cloud.google.com/logs/query;query\u003dtimestamp%3D%222021-11-10T17:41:39.541483849Z%22%0AinsertId%3D%22INSERT_ID%22%0Aresource.labels.project_id%3D%22PROJECT_ID%22?project\u003dPROJECT_ID"
          }
        ],
        "relatedFindingUri": {}
      }
    },
    "securityMarks": {
      "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID/securityMarks"
    },
    "eventTime": "2021-11-10T17:41:41.594Z",
    "createTime": "2021-11-10T17:41:42.014Z",
    "severity": "LOW",
    "workflowState": "NEW",
    "canonicalName": "projects/PROJECT_NUMBER/sources/SOURCE_ID/findings/FINDING_ID",
    "mute": "UNDEFINED",
    "findingClass": "THREAT",
    "indicator": {
      "domains": ["DOMAIN"]
    }
  },
  "resource": {
    "name": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER",
    "projectName": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER",
    "projectDisplayName": "PROJECT_ID",
    "parentName": "//cloudresourcemanager.googleapis.com/organizations/ORGANIZATION_ID",
    "parentDisplayName": "PARENT_NAME",
    "type": "google.cloud.resourcemanager.Project",
    "displayName": "PROJECT_ID"
  }
}

Filtrar hallazgos

Un proyecto, una carpeta o una organización pueden tener muchos resultados. En el ejemplo anterior no se usa ningún filtro, por lo que se devuelven todos los registros de hallazgos.

Para obtener información solo sobre los campos que te interesan, puedes usar filtros de búsqueda. Estos filtros son como las cláusulas "where" de las instrucciones SQL, pero, en lugar de aplicarse a las columnas, se aplican a los objetos devueltos por la API.

En el siguiente ejemplo solo se muestran los resultados que tienen la categoría "MEDIUM_RISK_ONE". Los distintos proveedores de resultados (también conocidos como fuentes de seguridad) usan diferentes conjuntos de categorías. Para determinar las categorías que puedes usar en tu filtro, consulta la documentación del proveedor de detecciones.

gcloud

Usa el siguiente comando para filtrar los resultados:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
  --location=LOCATION \
  --source=SOURCE_ID \
  --filter="FILTER"

Haz los cambios siguientes:

  • PARENT_TYPE: el nivel de la jerarquía de recursos para el que se deben enumerar los resultados. Use organizations, folders o projects.
  • PARENT_ID: el ID numérico de la organización, la carpeta o el proyecto, o el ID de proyecto alfanumérico.
  • LOCATION: la ubicación de Security Command Center en la que se deben enumerar las detecciones con un filtro. Si la residencia de datos está habilitada, usa eu, sa o us. De lo contrario, usa el valor global.
  • SOURCE_ID: ID de la fuente de seguridad que proporciona el tipo de resultado.
  • FILTER: el filtro que necesitas usar. Por ejemplo, el siguiente filtro devuelve resultados de la categoría MEDIUM_RISK_ONE únicamente:
    --filter="category=\"MEDIUM_RISK_ONE\""

Para ver más ejemplos, ejecuta el siguiente comando:

gcloud scc findings list --help

Para ver ejemplos en la documentación, consulta gcloud scc findings list.

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"google.golang.org/api/iterator"
)

// listFilteredFindings prints findings with category 'MEDIUM_RISK_ONE' for a
// specific source to w. sourceName is the full resource name of the source
// to search for findings under.
func listFilteredFindings(w io.Writer, sourceName string) error {
	// Specific source:
	// 		sourceName := "{parent}/sources/{sourceId}"
	// All sources:
	// 		sourceName := "{parent}/sources/-"
	// where,
	// Parent must be in one of the following formats:
	//		"organizations/{orgId}"
	//		"projects/{projectId}"
	//		"folders/{folderId}"
	// Instantiate a context and a security service client to make API calls.
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &securitycenterpb.ListFindingsRequest{
		Parent: sourceName,
		Filter: `category="MEDIUM_RISK_ONE"`,
	}
	it := client.ListFindings(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("it.Next: %w", err)
		}
		finding := result.Finding
		fmt.Fprintf(w, "Finding Name: %s, ", finding.Name)
		fmt.Fprintf(w, "Resource Name %s, ", finding.ResourceName)
		fmt.Fprintf(w, "Category: %s\n", finding.Category)
	}
	return nil
}

Java


import com.google.cloud.securitycenter.v2.ListFindingsRequest;
import com.google.cloud.securitycenter.v2.ListFindingsResponse.ListFindingsResult;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import java.io.IOException;

public class ListFindingsWithFilter {

  public static void main(String[] args) throws IOException {
    // TODO: Replace the variables within {}
    // organizationId: Google Cloud Organization id.
    // You can also use project/ folder as the parent resource.
    String organizationId = "google-cloud-organization-id";

    // Specify the location to list the findings.
    String location = "global";

    // The source id to scope the findings.
    String sourceId = "source-id";

    listFilteredFindings(organizationId, sourceId, location);
  }

  // List filtered findings under a source.
  public static void listFilteredFindings(String organizationId, String sourceId, String location)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (SecurityCenterClient client = SecurityCenterClient.create()) {

      // Use any one of the following formats:
      //  * organizations/{organization_id}/sources/{source_id}/locations/{location}
      //  * folders/{folder_id}/sources/{source_id}/locations/{location}
      //  * projects/{project_id}/sources/{source_id}/locations/{location}
      String parent = String.format("organizations/%s/sources/%s/locations/%s", organizationId,
          sourceId,
          location);

      // Listing all findings of category "MEDIUM_RISK_ONE".
      String filter = "category=\"MEDIUM_RISK_ONE\"";

      ListFindingsRequest request =
          ListFindingsRequest.newBuilder()
              .setParent(parent)
              .setFilter(filter)
              .build();

      for (ListFindingsResult result : client.listFindings(request).iterateAll()) {
        System.out.printf("Finding: %s", result.getFinding().getName());
      }
      System.out.println("\nListing complete.");
    }
  }
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;

// Creates a new client.
const client = new SecurityCenterClient();

// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
const location = 'global';

// Required. Name of the source to groupBy. If no location is specified,
// finding is assumed to be in global.
//  The following list shows some examples:
// - `organizations/[organization_id]/sources/[source_id]`
// - `organizations/[organization_id]/sources/[source_id]/locations/[location_id]`
// - `folders/[folder_id]/sources/[source_id]`
// - `folders/[folder_id]/sources/[source_id]/locations/[location_id]`
// - `projects/[project_id]/sources/[source_id]`
// - `projects/[project_id]/sources/[source_id]/locations/[location_id]`
// To groupBy across all sources provide a source_id of `-`.
const parent = `organizations/${organizationId}/sources/-/locations/${location}`;

// Listing all findings of category "MEDIUM_RISK_ONE".
const filter = 'category="MEDIUM_RISK_ONE"';

// Build the list findings with filter request.
const listFilteredFindingsRequest = {
  parent,
  filter,
};

async function listFilteredFindings() {
  // Call the API.
  const iterable = client.listFindingsAsync(listFilteredFindingsRequest);
  let count = 0;
  console.log('Findings:');
  for await (const response of iterable) {
    // Just print a few for demonstration.
    if (count > 5) break;
    console.log(
      `${++count} ${response.finding.name} ${response.finding.resourceName}`
    );
  }
}
await listFilteredFindings();

Python

def list_filtered_findings(organization_id, source_name, location_id) -> int:
    """
    lists filtered findings for a source
    Args:
        organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
        source_name: is the resource path for a source that has been created
        location_id: GCP location id; example: 'global'
    Returns:
         int: returns the filtered findings for a source
    """
    count = 0
    from google.cloud import securitycenter_v2

    # Create a new client.
    client = securitycenter_v2.SecurityCenterClient()
    parent = f"organizations/{organization_id}"
    all_sources = f"{parent}/sources/{source_name}/locations/{location_id}"
    finding_result_iterator = client.list_findings(
        request={"parent": all_sources, "filter": 'severity="LOW"'}
    )
    # Iterate an print all finding names and the resource they are
    # in reference to.
    for count, finding_result in enumerate(finding_result_iterator):
        print(
            "{}: name: {} resource: {}".format(
                count, finding_result.finding.name, finding_result.finding.resource_name
            )
        )
    return count

Security Command Center también admite arrays y objetos JSON completos como posibles tipos de propiedad. Puedes filtrar por:

  • Elementos de un array
  • Objetos JSON completos con coincidencias de cadena parciales en el objeto
  • Subcampos de objeto JSON

Operadores admitidos

Las instrucciones de consulta de los resultados de Security Command Center admiten los operadores que admiten la mayoría de las APIs. Google Cloud

En la siguiente lista se muestra el uso de varios operadores:

  • state="ACTIVE" AND NOT mute="MUTED"
  • create_time>"2023-08-15T19:05:32.428Z"
  • resource.parent_name:"prod"
  • severity="CRITICAL" OR severity="HIGH"

En la siguiente lista se muestran todos los operadores y funciones que se admiten en las instrucciones de consulta de los resultados:

  • Para cadenas:
    • = para lograr la igualdad plena
    • : para la coincidencia parcial de cadenas
  • Para números (excepto int64):
    • <, >, <=, >= para desigualdades
    • =, != por la igualdad
  • Para números (int 64):
    • =, != por la igualdad
  • Para valores booleanos:
    • = por la igualdad
  • Para las relaciones lógicas:
    • AND
    • OR
    • NOT o -
  • Para agrupar expresiones:
    • (, ) (paréntesis)
  • Para las matrices:
    • contains(), una función para consultar resultados con un campo de matriz que contenga al menos un elemento que coincida con el filtro especificado
    • containsOnly(), una función para consultar resultados con un campo de matriz que solo contiene elementos que coinciden con el filtro especificado.
  • Para direcciones IP:
    • inIpRange(), una función para consultar direcciones IP dentro de un intervalo CIDR especificado

Filtrar por direcciones IP

Algunas propiedades de las detecciones incluyen direcciones IP. Puedes filtrar los resultados según direcciones IP específicas o un intervalo de direcciones IP.

Las direcciones IP aparecen como cadenas en varios resultados y propiedades de resultados, entre los que se incluyen los siguientes:

  • access.caller_ip
  • connections.destinationIp
  • connections.sourceIp
  • indicator.ip_addresses

Para filtrar por una dirección IP específica, puede usar el operador de igualdad, como se muestra en el siguiente ejemplo:

access.caller_ip="192.0.2.0"

Para filtrar los resultados en función de un intervalo de direcciones IP, usa la función inIpRange. Con la función inIpRange, puedes filtrar los resultados para que solo se muestren aquellos que contengan una dirección IP dentro de un intervalo CIDR especificado. Si usas la operación NOT con inIpRange, puedes filtrar los resultados para que solo se muestren aquellos que contengan una dirección IP que no esté incluida en el intervalo CIDR especificado.

En el siguiente ejemplo se muestra la sintaxis de la función inIpRange:

inIpRange(IP_FINDING_FIELD, "CIDR_RANGE")

Si la dirección IP se encuentra en un elemento de matriz de un campo de detección que contiene una matriz, utiliza la siguiente sintaxis con las funciones contains y inIpRange:

contains(ATTRIBUTE_WITH_ARRAY, inIpRange(IP_FINDING_FIELD, "CIDR_RANGE"))

En el siguiente ejemplo, la función inIpRange evalúa cada elemento destination_ip de la matriz que se encuentra en el campo connections finding para una dirección IP que está en el intervalo CIDR definido por 192.0.2.0/24:

contains(connections, inIpRange(destination_ip, "192.0.2.0/24"))

En el siguiente ejemplo se muestra un comando de la CLI de gcloud que usa la función inIpRange para filtrar los resultados que tienen una dirección IP en el campo connections.source_ip que está dentro de un intervalo, pero no en otro. El campo connections es un campo de tipo array, por lo que se usa la función contains:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(connections, inIpRange(source_ip, \"2001:db8::/32\")) \
      AND NOT contains(connections, inIpRange(source_ip, \"192.0.2.0/24\"))"

Ejemplo de objeto JSON

En los ejemplos que se muestran más adelante en esta página se da por hecho que el siguiente objeto JSON es un atributo de detección:

{
  "outer_object": {
    "middle_object": {
      "deeply_nested_object": {
        "x": 123
      },
      "y": "some-string-value"
    },
    "list_middle_object": [
      {
        "v": 321,
        "w": [
          {
            "a": 3,
            "b": 4
          }
        ]
      }
    ],
    "z": "some-other-string-value",
    "u": [
      "list-element-1",
      "list-element-2",
      "list-element-3"
    ]
  }
}

Ejemplo de filtrado de resultados

Supongamos que el ejemplo de JSON anterior es un atributo de resultado llamado my_property. En el siguiente ejemplo se incluyen consultas de resultados que tienen el objeto como propiedad. También puedes usar estos filtros con otros filtros mediante AND y OR en tu consulta.

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.middle_object.deeply_nested_object.x = 123"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.middle_object.y = \"some-string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.middle_object.y : \"string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.z = \"some-other-string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.z : \"other-string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.u : \"list-element-1\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.u : \"list-element-2\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.u : \"list-element-3\""

Subfiltros de campos de tipo array

Cuando llamas a ListFindings, puedes usar una coincidencia de subcadena :, que hace una sola comprobación de una coincidencia de cadena parcial en todo el contenido de la matriz. También puedes ejecutar un subfiltro directamente en los elementos de la matriz y sus subcampos con una de las siguientes funciones:

  • La función contains() para devolver resultados cuando alguno de los elementos de la matriz contiene el valor especificado.

  • La función containsOnly() para devolver resultados solo si todos los elementos de la matriz coinciden con el subfiltro.

Ambas funciones admiten consultas de subfiltros, como las siguientes:

  • Coincidencia exacta de elementos: coincide con los elementos de la matriz que contienen la cadena exacta, "example".
  • Operaciones con números específicos: busca elementos de la matriz que sean mayores o iguales que 100.
  • Filtrado complejo en estructuras de arrays: busca elementos de un array que contengan la propiedad x con el valor y correspondiente.

Formato de la función contains()

La función contains() tiene el siguiente formato:

contains(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

Haz los cambios siguientes:

  • ARRAY_ATTRIBUTE_NAME: campo o subcampo de tipo array (una lista).
  • SUBFILTER: expresión que define los valores que se van a buscar en la matriz. El formato del subfiltro varía en función de si ARRAY_ATTRIBUTE_NAME es un array de objetos o un array de elementos de tipo primitivo. Si ARRAY_ATTRIBUTE_NAME es una matriz de objetos que tienen matrices anidadas, puedes usar un subfiltro acotado para especificar que quieres que se cumplan todas las condiciones en el mismo elemento ARRAY_ATTRIBUTE_NAME.

La API de Security Command Center devuelve resultados en los que el elemento ARRAY_ATTRIBUTE_NAME contiene al menos un elemento que cumple la condición SUBFILTER.

Formato de la función containsOnly()

La función containsOnly() tiene el siguiente formato:

containsOnly(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

Haz los cambios siguientes:

  • ARRAY_ATTRIBUTE_NAME: campo o subcampo de tipo array (una lista). Cuando ejecutas consultas con la API de Security Command Center, puedes usar la función containsOnly() para cualquier atributo de matriz disponible.
  • SUBFILTER: expresión que define los valores que se van a buscar en la matriz. El formato del subfiltro varía en función de si ARRAY_ATTRIBUTE_NAME es un array de objetos o un array de elementos de tipo primitivo. Si ARRAY_ATTRIBUTE_NAME es una matriz de objetos que tienen matrices anidadas, puede usar un subfiltro con ámbito para especificar que quiere que se cumplan todas las condiciones en el mismo elemento ARRAY_ATTRIBUTE_NAME.

La API de Security Command Center devuelve los resultados en los que todos los elementos ARRAY_ATTRIBUTE_NAME coinciden con los SUBFILTER.

Subfiltro de una matriz de objetos

A continuación, se muestra un fragmento del ejemplo de JSON anterior. En este caso, el campo list_middle_object es una matriz de objetos:

    "list_middle_object": [
      {
        "v": 321,
        "w": [
          {
            "a": 3,
            "b": 4
          }
        ]
      }
    ]

En el siguiente ejemplo, se consultan las detecciones en las que al menos uno de los elementos del campo list_middle_object tiene un subcampo v con un valor mayor o igual que 321:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(my_property.outer_object.list_middle_object, v  >= 321)"

Para ver ejemplos prácticos que usan las funciones contains() y containsOnly(), consulta Resultados que contienen valores de matriz específicos.

Subfiltro de una matriz que contiene elementos de tipo primitivo

Los tipos primitivos son cadenas, números y valores booleanos. Para usar la función contains() en una matriz que contenga tipos primitivos, debes usar la palabra clave especial elem.

A continuación, se muestra un fragmento del ejemplo de JSON anterior. En este caso, el campo u es una matriz de elementos de tipo primitivo:

"u": ["list-element-1", "list-element-2", "list-element-3"]

En el siguiente ejemplo se consultan los resultados en los que al menos uno de los elementos del campo u es "list-element-1":

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(my_property.outer_object.u, elem = \"list-element-1\")"

Para ver ejemplos prácticos que usan la función contains(), consulta Resultados que contienen valores de matriz específicos.

Subfiltro delimitado

A continuación, se muestra un fragmento del ejemplo de JSON anterior. En este caso, el campo list_middle_object es una matriz de objetos y los objetos de esta matriz contienen una matriz anidada.

"list_middle_object": [
  {
    "v": 321,
    "w": [
      {
        "a": 3,
        "b": 4
      }
    ]
  }
]

En el siguiente ejemplo se consultan las detecciones en las que se cumplen las dos condiciones siguientes en el mismo elemento list_middle_object:

  • El subcampo v tiene un valor igual o superior a 321.
  • El subcampo w no contiene ningún elemento con una propiedad a igual a 3.
gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(my_property.outer_object.list_middle_object, v  >= 321 AND -contains(w, a = 3))"

Para ver ejemplos prácticos que usan la función contains(), consulta Resultados que contienen valores de matriz específicos.

Ejemplo de ordenación de resultados

Puede ordenar los resultados por subcampos estrictos que sean tipos primitivos: cadenas, números y booleanos. Supongamos que el ejemplo de JSON anterior es un atributo de resultado llamado my_property. En el siguiente ejemplo se incluyen consultas para ordenar los campos de los resultados. La palabra clave DESC especifica que el campo que le sigue debe ordenarse en orden descendente. El orden predeterminado es ascendente.

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.deeply_nested_object.x DESC"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.deeply_nested_object.x"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.y DESC"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.y"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.z DESC"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.z"

Ejemplos de filtros

En las siguientes secciones se muestran ejemplos prácticos de cómo encontrar filtros.

Filtrar los resultados que se hayan producido después de un momento determinado

Estos filtros de ejemplo coinciden con los resultados que se han producido más recientemente después del miércoles 5 de junio del 2019 a las 22:12:05 GMT. Con el filtro event_time, puedes expresar el tiempo con los siguientes formatos y tipos:

  • Tiempo de inicio de registro de tiempo Unix (en milisegundos) como literal entero.

    "event_time > 1559772725000"
    
  • RFC 3339 como literal de cadena

    "event_time > \"2019-06-05T22:34:40+00:00\""
    

Filtrar por campos de tipo array

En el siguiente ejemplo se muestra el uso de una concordancia parcial de cadena en un campo de tipo array dentro de un filtro:

"indicator.domains : \"website.com\""

La API de Security Command Center devuelve cualquier resultado con una cadena parcial website.com en la matriz. Por ejemplo, coincide con un resultado que contiene indicator.domains = [\"onewebsite.com\"] porque "website.com" es una subcadena de un elemento de la matriz.

En las siguientes secciones, los filtros de ejemplo muestran algunas opciones para usar el filtrado de tipo array enriquecido con la función contains().

Filtrar por el campo vulnerability.cve.references

En el siguiente ejemplo se devuelven resultados en los que al menos un elemento de la matriz vulnerability.cve.references tiene una propiedad source igual a SOURCE_OF_REFERENCE y una propiedad uri que tiene FILTERED_URI.

"contains(vulnerability.cve.references, source = \"SOURCE_OF_REFERENCE\" AND uri : \"FILTERED_URI\")"

Haz los cambios siguientes:

Filtrar por el campo indicator.domains

En el siguiente ejemplo se devuelven los resultados en los que al menos un dominio de indicador tiene tanto mycompanyprefix como .ca.

"contains(indicator.domains, elem : \"mycompanyprefix\" AND elem : \".ca\")"

Filtrar por el campo indicator.ip_addresses

En el siguiente ejemplo se devuelven los resultados en los que al menos un elemento de la matriz indicator.ip_addresses es igual a IP_ADDRESS.

"contains(indicator.ip_addresses, elem = \"IP_ADDRESS\")"

Sustituye IP_ADDRESS por una dirección IP asociada a los resultados que buscas.

Filtrar por asignatarios del sistema externo

En el siguiente ejemplo se devuelven los resultados en los que al menos un elemento de la matriz external_systems.EXTERNAL_SYSTEM_NAME.assignees es igual a ASSIGNEE.

"contains(external_systems.EXTERNAL_SYSTEM_NAME.assignees, elem = \"ASSIGNEE\")"

Haz los cambios siguientes:

  • EXTERNAL_SYSTEM_NAME: el nombre de un sistema SIEM o SOAR de terceros, por ejemplo, demisto.
  • ASSIGNEE: un asignado en el sistema externo.

Filtrar por el campo resource.folders.resource_folder

En el siguiente ejemplo se devuelven los resultados en los que al menos un elemento de la matriz resource.folders.resource_folder no es igual a FOLDER_NAME.

"contains(resource.folders.resource_folder, -(elem = \"FOLDER_NAME\"))"

Filtrar por el campo resource.folders.resource_folder_display_name

En el siguiente ejemplo se devuelven los resultados en los que al menos un elemento de la matriz resource.folders.resource_folder_display_name es igual a DISPLAY_NAME.

"contains(resource.folders.resource_folder_display_name, elem = \"DISPLAY_NAME\")"

Sustituye DISPLAY_NAME por el nombre definido por el usuario de la carpeta asociada a los resultados que buscas.

El filtro solo incluye cuentas de servicio específicas

En el ejemplo siguiente, solo se devuelven resultados cuando el valor del miembro de cada entrada iam_bindings es igual a una de las cuentas de servicio proporcionadas.

containsOnly(iam_bindings, (member = SERVICE_ACCOUNT1 OR member = SERVICE_ACCOUNT2 OR member = "SERVICE_ACCOUNT3 "))

Sustituye SERVICE_ACCOUNT1, SERVICE_ACCOUNT2 y SERVICE_ACCOUNT3 por las direcciones de correo de las cuentas de servicio.

Para saber cómo usar las funciones contains() y containsOnly() en un filtro de resultados, consulta Subfiltros de campos de tipo array.

Siguientes pasos

Consulta más información sobre cómo configurar las notificaciones de búsqueda.