Como listar descobertas de segurança usando a API Security Command Center

As descobertas do Security Command Center modelam os possíveis riscos à segurança de recursos em um projeto ou uma organização. Uma descoberta sempre está relacionada a um recurso específico no Security Command Center.

Este guia mostra como usar as bibliotecas de cliente do Security Command Center para acessar as descobertas. Cada descoberta pertence a uma fonte. A maioria dos provedores e detectores produz descobertas na mesma fonte.

Os papéis do IAM para o Security Command Center podem ser concedidos no nível da organização, da pasta ou do projeto. A capacidade de ver, editar, criar ou atualizar descobertas, recursos e fontes de segurança depende do nível a que você tem acesso. Para saber mais sobre os papéis do Security Command Center, consulte Controle de acesso.

Antes de começar

Antes de configurar uma fonte, faça o seguinte:

Tamanho da página

Todas as APIs de lista do Security Command Center são paginadas. Cada resposta retorna uma página de resultados e um token para retornar a próxima página. O tamanho da página é configurável. O tamanho de página padrão é 10. É possível defini-la para um mínimo de 1 e um máximo de 1.000.

Retenção de descobertas

Uma descoberta permanece disponível para que você liste ou consulte por pelo menos 13 meses.

O Security Command Center armazena snapshots de cada descoberta. Um snapshot de uma descoberta é mantido por pelo menos 13 meses. Se todos os snapshots de uma descoberta forem excluídos, ela não poderá mais ser consultada ou recuperada.

Para saber mais sobre a retenção de dados do Security Command Center, consulte Retenção de dados.

Listar todas as descobertas

gcloud

Para listar todas as descobertas em um projeto, pasta ou organização, execute o seguinte comando:

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

Substitua:

  • PARENT_TYPE: o nível da hierarquia de recursos em que as descobertas serão listadas. Use organizations, folders ou projects.
  • PARENT_ID: o ID numérico da organização, pasta ou projeto ou o ID alfanumérico do projeto.
  • LOCATION: se a residência de dados estiver ativada, o local do Security Command Center em que as descobertas serão listadas. Se a residência de dados não estiver ativada, use o valor global.

Para mais exemplos, execute:

gcloud scc findings list --help

Para conferir exemplos na documentação, consulte 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

A saída para cada descoberta é semelhante à seguinte:

{
  "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 descobertas

Um projeto, uma pasta ou uma organização pode ter várias descobertas. O exemplo anterior não usa um filtro, portanto, todos os registros de descoberta são retornados.

Para receber informações apenas sobre os campos que você quer, use filtros de localização. Esses filtros são como cláusulas "onde" em instruções SQL, mas, em vez de colunas, eles se aplicam aos objetos retornados pela API.

O exemplo a seguir lista apenas as descobertas que têm uma categoria "MEDIUM_RISK_ONE". Provedores de descoberta diferentes (também conhecidos como fontes de segurança) usam diferentes conjuntos de categorias. Para determinar as categorias que podem ser usadas no filtro, consulte a documentação do provedor de descoberta.

gcloud

Use o seguinte comando para filtrar as descobertas:

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

Substitua:

  • PARENT_TYPE: o nível da hierarquia de recursos em que as descobertas serão listadas. Use organizations, folders ou projects.
  • PARENT_ID: o ID numérico da organização, pasta ou projeto ou o ID alfanumérico do projeto.
  • LOCATION: se a residência de dados estiver ativada, o local do Security Command Center em que as descobertas serão listadas com um filtro. Se a residência de dados não estiver ativada, use o valor global.
  • SOURCE_ID: o ID da origem de segurança que fornece o tipo de descoberta.
  • FILTER: o filtro que você precisa usar. Por exemplo, o filtro a seguir retorna as descobertas somente da categoria MEDIUM_RISK_ONE:
    --filter="category=\"MEDIUM_RISK_ONE\""

Para mais exemplos, execute:

gcloud scc findings list --help

Para conferir exemplos na documentação, consulte 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

O Security Command Center também é compatível com matrizes e objetos JSON completos como tipos de propriedade em potencial. É possível filtrar por:

  • Elementos de matriz
  • Objetos JSON completos com correspondência parcial de string no objeto
  • Subcampos de objetos JSON

Operadores compatíveis

As instruções de consulta para descobertas do Security Command Center são compatíveis com os operadores compatíveis com a maioria das APIs do Google Cloud.

A lista a seguir mostra o uso de vários operadores:

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

A lista a seguir mostra todos os operadores e funções compatíveis com as instruções de consulta para descobertas:

    • para strings
    • = para igualdade total
    • : para correspondência parcial de string
  • Para números:
    • <, >, <=, >= para desigualdades
    • =, != fpara igualdade
    • para booleanos:
    • = para igualdade
  • Para relações lógicas:
    • AND
    • OR
    • NOT ou -
  • Para expressões de agrupamento:
    • (, ) (parênteses)
  • Para matrizes:
    • contains(), uma função para consultar descobertas com um campo de matriz que contém pelo menos um elemento que corresponde ao filtro especificado.
    • containsOnly(), uma função para consultar descobertas com um campo de matriz que contém apenas elementos que correspondem ao filtro especificado.
  • Para endereços IP:
    • inIpRange(), uma função para consultar endereços IP em um intervalo CIDR especificado.

Como filtrar endereços IP

Algumas propriedades de localização incluem endereços IP. É possível filtrar descobertas com base em endereços IP específicos ou em um intervalo de endereços IP.

Os endereços IP aparecem como strings em uma variedade de descobertas e propriedades, incluindo o seguinte:

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

Para filtrar um endereço IP específico, use o operador de igualdade, como mostrado no exemplo a seguir:

access.caller_ip="192.0.2.0"

Para filtrar descobertas com base em um intervalo de endereços IP, use a função inIpRange. Usando a função inIpRange, você filtra as descobertas apenas para as descobertas que contêm um endereço IP dentro de um intervalo CIDR especificado. Usando a operação NOT com inIpRange, é possível filtrar as descobertas somente para as descobertas que contêm um endereço IP fora do intervalo CIDR especificado.

O exemplo a seguir mostra a sintaxe da função inIpRange:

inIpRange(IP_FINDING_FIELD, "CIDR_RANGE")

Se o endereço IP estiver em um elemento de matriz em um campo de descoberta que contenha uma matriz, use a seguinte sintaxe com a função contains e inIpRange:

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

No exemplo a seguir, a função inIpRange avalia cada elemento destination_ip da matriz contido no campo de descoberta connections para um endereço IP que está no intervalo CIDR definido por 192.0.2.0/24:

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

O exemplo a seguir mostra um comando da CLI da gcloud que usa a função inIpRange para filtrar descobertas que têm um endereço IP no campo connections.source_ip que está dentro de um intervalo, mas não em outro do Google Analytics. O campo connections é um campo do tipo matriz, portanto, a função contains é usada:

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\"))"

Exemplo de objeto JSON

Os exemplos posteriores nesta página presumem que o seguinte objeto JSON seja um atributo de descoberta:

{
  "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"
    ]
  }
}

Exemplo de filtragem de descobertas

Suponha que o exemplo JSON anterior seja um atributo de descoberta chamado my_property. O exemplo a seguir inclui consultas para descobertas que têm o objeto como uma propriedade. Você também pode usar esses filtros com outros filtros usando AND e OR na 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 para campos do tipo matriz

Ao chamar ListFindings, você pode usar uma correspondência de substring :, que fará uma única verificação de uma correspondência parcial de string em todo o conteúdo da matriz. Como alternativa, é possível executar um subfiltro diretamente nos elementos da matriz e nos subcampos usando uma das seguintes funções:

  • A função contains() para retornar descobertas quando qualquer elemento da matriz contém o valor especificado.

  • A função containsOnly() para retornar descobertas somente se todos os elementos da matriz corresponderem ao subfiltro.

As duas funções aceitam recursos de consulta de subfiltro, como este:

  • Correspondência exata de elementos: faz a correspondência de elementos da matriz que contenham a string exata, "example".
  • Operações de números específicos: elementos de matriz de correspondência maiores ou iguais a 100.
  • Filtragem complexa contra estruturas de matriz: corresponde a elementos da matriz que contêm a propriedade x com um valor correspondente y.

Formato da função contains()

A função contains() tem o seguinte formato:

contains(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

Substitua:

  • ARRAY_ATTRIBUTE_NAME: um campo ou subcampo do tipo matriz (uma lista).
  • SUBFILTER: uma expressão que define os valores a serem procurados na matriz. O formato do subfiltro varia dependendo se ARRAY_ATTRIBUTE_NAME é uma matriz de objetos ou uma matriz de elementos primitivos. Se ARRAY_ATTRIBUTE_NAME for uma matriz de objetos que têm matrizes aninhadas, será possível usar um subfiltro com escopo para especificar que você quer que todas as condições sejam satisfeitas dentro do mesmo elemento ARRAY_ATTRIBUTE_NAME.

A API Security Command Center retorna descobertas em que ARRAY_ATTRIBUTE_NAME contém pelo menos um elemento que satisfaz o SUBFILTER.

Formato da função containsOnly()

A função containsOnly() tem o seguinte formato:

containsOnly(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

Substitua:

  • ARRAY_ATTRIBUTE_NAME: um campo ou subcampo do tipo matriz (uma lista). Ao executar consultas usando a API Security Command Center, é possível usar a função containsOnly() para qualquer atributo de matriz disponível.
  • SUBFILTER: uma expressão que define os valores a serem procurados na matriz. O formato do subfiltro varia dependendo se ARRAY_ATTRIBUTE_NAME é uma matriz de objetos ou uma matriz de elementos de tipo primitivo. Se ARRAY_ATTRIBUTE_NAME for uma matriz de objetos que têm matrizes aninhadas, será possível usar um subfiltro com escopo para especificar que você quer que todas as condições sejam satisfeitas dentro do mesmo elemento ARRAY_ATTRIBUTE_NAME.

A API Security Command Center retorna descobertas em que todos os elementos ARRAY_ATTRIBUTE_NAME correspondem a SUBFILTER.

Subfiltro para uma matriz de objetos

Veja a seguir um trecho do exemplo JSON anterior. Aqui, o campo list_middle_object é uma matriz de objetos:

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

No exemplo a seguir, consultas para descobertas em que pelo menos um dos elementos no campo list_middle_object tem um subcampo v com um valor maior ou igual a 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 exemplos práticos que usam as funções contains() e containsOnly(), consulte Descobertas que contêm valores de matriz específicos.

Subfiltro para uma matriz que contém elementos primitivos

Os tipos primitivos são strings, números e booleanos. Para usar a função contains() com uma matriz que contém tipos primitivos, use a palavra-chave especial, elem.

Veja a seguir um trecho do exemplo JSON anterior. Aqui, o campo u é uma matriz de elementos primitivos:

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

No exemplo a seguir, as descobertas são descobertas em que pelo menos um dos elementos no campo u é "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 exemplos práticos que usam a função contains(), consulte Descobertas que contêm valores de matriz específicos.

Subfiltro com escopo

Veja a seguir um trecho do exemplo JSON anterior. Aqui, o campo list_middle_object é uma matriz de objetos, e os objetos nessa matriz contêm uma matriz aninhada.

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

No exemplo a seguir, consultas de descobertas em que ambas as condições a seguir são satisfeitas no mesmo elemento list_middle_object:

  • O subcampo v tem um valor maior ou igual a 321.
  • O subcampo w não contém um elemento com uma propriedade 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 exemplos práticos que usam a função contains(), consulte Descobertas que contêm valores de matriz específicos.

Exemplo de classificação de descobertas

É possível classificar as descobertas por subcampos rígidos que são tipos primitivos: strings, números e booleanos. Suponha que o exemplo JSON anterior seja um atributo de descoberta chamado my_property. O exemplo a seguir inclui consultas para classificar os campos de descoberta. A palavra-chave DESC especifica que o campo a ser seguido precisa ser classificado em ordem decrescente. A ordem padrão é crescente.

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"

Exemplos de filtros

As seções a seguir mostram exemplos práticos de como encontrar filtros.

Filtrar descobertas que ocorreram após um momento

Esses filtros de exemplo correspondem às descobertas mais recentes após quarta-feira, 5 de junho de 2019, às 22:12:05 GMT. Com o filtro event_time, é possível expressar tempo usando os seguintes formatos e tipos:

  • Tempo Unix (em milissegundos) como um literal inteiro

    "event_time > 1559772725000"
    
  • RFC 3339 como um literal de string

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

Filtrar campos de tipo de matriz

O exemplo a seguir mostra o uso de uma correspondência parcial de string em um campo de tipo de matriz em um filtro:

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

A API Security Command Center retorna qualquer descoberta com uma string parcial website.com na matriz. Por exemplo, ele corresponde a uma descoberta com indicator.domains = [\"onewebsite.com\"] porque "website.com" é uma substring em um elemento na matriz.

Nas seções a seguir, os filtros de exemplo mostram algumas opções para uso da filtragem avançada de tipo de matriz que usa a função contains().

Filtrar no campo vulnerability.cve.references

O exemplo a seguir retorna descobertas em que pelo menos um elemento na matriz vulnerability.cve.references tem uma propriedade source igual a SOURCE_OF_REFERENCE e uma propriedade uri que tem FILTERED_URI.

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

Substitua:

  • SOURCE_OF_REFERENCE: nome da origem de uma referência de Vulnerabilidades e Exposições comuns (CVE, na sigla em inglês), por exemplo, NVD.
  • FILTERED_URI: URI da origem da referência do CVE.

Filtrar no campo indicator.domains

O exemplo a seguir retorna descobertas em que pelo menos um domínio indicador tem mycompanyprefix e .ca.

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

Filtrar no campo indicator.ip_addresses

O exemplo a seguir retorna descobertas em que pelo menos um elemento na matriz indicator.ip_addresses é igual a IP_ADDRESS.

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

Substitua IP_ADDRESS por um endereço IP associado às descobertas que você está procurando.

Filtrar por usuários externos do sistema

O exemplo a seguir retorna descobertas em que pelo menos um elemento na matriz external_systems.EXTERNAL_SYSTEM_NAME.assignees é igual a ASSIGNEE.

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

Substitua:

  • EXTERNAL_SYSTEM_NAME: o nome de um sistema SIEM/SOAR de terceiros, por exemplo, demisto.
  • ASSIGNEE: um responsável no sistema externo.

Filtrar no campo resource.folders.resource_folder

O exemplo a seguir retorna descobertas em que pelo menos um elemento na matriz resource.folders.resource_folder não é igual a FOLDER_NAME.

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

Filtrar no campo resource.folders.resource_folder_display_name

O exemplo a seguir retorna descobertas em que pelo menos um elemento na matriz resource.folders.resource_folder_display_name é igual a DISPLAY_NAME.

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

Substitua DISPLAY_NAME pelo nome definido pelo usuário para a pasta associada às descobertas que você está procurando.

O filtro inclui somente contas de serviço específicas

O exemplo a seguir retorna descobertas somente quando o valor de membro de cada entrada iam_bindings é igual a uma das contas de serviço fornecidas.

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

Substitua SERVICE_ACCOUNT1, SERVICE_ACCOUNT2 e SERVICE_ACCOUNT3 pelos endereços de e-mail das contas de serviço.

Para saber como usar as funções contains() e containsOnly() em um filtro de descoberta, consulte Subfiltros para campos do tipo matriz.

A seguir

Saiba mais sobre como configurar notificações de localização.