Répertorier des résultats de sécurité à l'aide de l'API Security Command Center

Les résultats de Security Command Center modélisent les risques de sécurité potentiels associés aux éléments d'un projet ou d'une organisation. Un résultat correspond toujours à un élément spécifique dans Security Command Center.

Ce guide explique comment utiliser les bibliothèques clientes Security Command Center pour accéder aux résultats. Chaque résultat appartient à une source. La plupart des détecteurs ou des fournisseurs de résultats produisent des résultats dans la même source.

Les rôles IAM pour Security Command Center peuvent être attribués au niveau de l'organisation, d'un dossier ou d'un projet. Votre capacité à afficher, modifier, créer ou mettre à jour des résultats, des éléments et des sources de sécurité dépend du niveau d'accès qui vous est accordé. Pour en savoir plus sur les rôles Security Command Center, consultez la page Contrôle des accès.

Avant de commencer

Avant de configurer une source, vous devez effectuer les opérations suivantes :

Taille de la page

Toutes les API de liste Security Command Center sont paginées. Chaque réponse renvoie une page de résultats et un jeton pour renvoyer la page suivante. La taille de la page est configurable. La taille de page par défaut est de 10. Vous pouvez définir une valeur minimale de 1 et une valeur maximale de 1 000.

Conservation des résultats

Vous avez la possibilité de répertorier ou de rechercher un résultat pendant au moins 13 mois.

Security Command Center stocke des instantanés de chaque résultat. L'instantané d'un résultat est conservé pendant au moins 13 mois. Si tous les instantanés d'un résultat sont supprimés, le résultat ne peut plus être listé ni récupéré.

Pour en savoir plus sur la conservation des données dans Security Command Center, consultez la section Conservation des données.

Lister tous les résultats

gcloud

Pour répertorier tous les résultats d'un projet, d'un dossier ou d'une organisation, exécutez la commande suivante:

gcloud scc findings list PARENT_ID

Remplacez PARENT_ID par l'une des valeurs suivantes :

  • Un ID d'organisation au format suivant : ORGANIZATION_ID (l'ID numérique uniquement)
  • ID de dossier au format suivant: folders/FOLDER_ID
  • Un ID de projet au format suivant: projects/PROJECT_ID

Pour plus d'exemples, exécutez la commande suivante :

gcloud scc findings list --help

Pour obtenir des exemples dans la documentation, consultez gcloud scc results list.

Python

from google.cloud import securitycenter

# Create a client.
client = securitycenter.SecurityCenterClient()

# 'parent' must be in one of the following formats:
#   "organizations/{organization_id}"
#   "projects/{project_id}"
#   "folders/{folder_id}"
parent = f"organizations/{organization_id}"
# The "sources/-" suffix lists findings across all sources.  You
# also use a specific source_name instead.
all_sources = f"{parent}/sources/-"
finding_result_iterator = client.list_findings(request={"parent": all_sources})
for i, finding_result in enumerate(finding_result_iterator):
    print(
        "{}: name: {} resource: {}".format(
            i, finding_result.finding.name, finding_result.finding.resource_name
        )
    )

Java

static ImmutableList<ListFindingsResult> listAllFindings(OrganizationName organizationName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Input parameters for SourceName must be in one of the following formats:
    //    * OrganizationName organizationName = OrganizationName.of("organization-id");
    //      organizationName.getOrganization();
    //    * ProjectName projectName = ProjectName.of("project-id");
    //      projectName.getProject();
    //    * FolderName folderName = FolderName.of("folder-id");
    //      folderName.getFolder();
    //
    // "-" Indicates listing across all sources.
    SourceName sourceName = SourceName.of(organizationName.getOrganization(), "-");

    ListFindingsRequest.Builder request =
        ListFindingsRequest.newBuilder().setParent(sourceName.toString());

    // Call the API.
    ListFindingsPagedResponse response = client.listFindings(request.build());

    // This creates one list for all findings.  If your organization has a large number of
    // findings this can cause out of memory issues.  You can process them in incrementally
    // by returning the Iterable returned response.iterateAll() directly.
    ImmutableList<ListFindingsResult> results = ImmutableList.copyOf(response.iterateAll());
    System.out.println("Findings:");
    System.out.println(results);
    return results;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"cloud.google.com/go/securitycenter/apiv1/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/-"
		//		"projects/{projectId}/sources/-"
		//		"folders/{folderId}/sources/-"
		Parent: fmt.Sprintf("organizations/%s/sources/-", 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
}

Node.js

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

// Creates a new client.
const client = new SecurityCenterClient();
//  organizationId is the numeric ID of the organization.
/*
 * TODO(developer): Uncomment the following lines
 */
// const organizationId = "1234567777";

async function listAllFindings() {
  const [response] = await client.listFindings({
    // List findings across all sources.
    // parent: must be in one of the following formats:
    //    `organizations/${organization_id}/sources/-`
    //    `projects/${project_id}/sources/-`
    //    `folders/${folder_id}/sources/-`
    parent: `organizations/${organizationId}/sources/-`,
  });
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.finding.name} ${result.finding.resourceName}`
    )
  );
}
listAllFindings();

Le résultat de chaque élément se présente comme suit :

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

Filtrer les résultats

Un projet, un dossier ou une organisation peut présenter de nombreux résultats. L'exemple précédent n'utilise pas de filtre. Par conséquent, tous les enregistrements de résultats sont renvoyés. Security Command Center vous permet d'utiliser des filtres de résultats pour obtenir des informations uniquement sur les résultats qui vous intéressent.

Les filtres de résultats sont semblables à des clauses "where" dans les instructions SQL, à ceci près qu'à la place des colonnes, elles s'appliquent aux objets renvoyés par l'API.

L'exemple suivant ne répertorie que les résultats possédant une catégorie "MEDIUM_RISK_ONE". Différents fournisseurs de résultats (également appelés sources de sécurité) utilisent différents ensembles de catégories. Pour déterminer les catégories que vous pouvez utiliser dans votre filtre, consultez la documentation du fournisseur de résultats.

gcloud

Utilisez la commande suivante pour filtrer les résultats:

gcloud scc findings list PARENT_ID --source=SOURCE_ID --filter="FILTER"

Remplacez les éléments suivants :

  • FILTER par le filtre que vous devez utiliser. Par exemple, le filtre suivant ne renvoie que les résultats de la catégorie MEDIUM_RISK_ONE:
    --filter="category=\"MEDIUM_RISK_ONE\""
  • PARENT_ID par l'une des valeurs suivantes :
    • Un ID d'organisation au format suivant : ORGANIZATION_ID (l'ID numérique uniquement)
    • Un ID de projet au format suivant: projects/PROJECT_ID
    • ID de dossier au format suivant: folders/FOLDER_ID
  • SOURCE_ID par l'ID de la source de sécurité qui fournit le type de résultat.

Pour plus d'exemples, exécutez la commande suivante :

gcloud scc findings list --help

Pour obtenir des exemples dans la documentation, consultez gcloud scc results list.

Python

from google.cloud import securitycenter

# Create a new client.
client = securitycenter.SecurityCenterClient()

# 'source_name' is the resource path for a source that has been
# created previously (you can use list_sources to find a specific one).
# Its format is:
# source_name = f"{parent}/sources/{source_id}"
# 'parent' must be in one of the following formats:
#   "organizations/{organization_id}"
#   "projects/{project_id}"
#   "folders/{folder_id}"
# You an also use a wild-card "-" for all sources:
#   source_name = "organizations/111122222444/sources/-"
finding_result_iterator = client.list_findings(
    request={"parent": source_name, "filter": 'category="MEDIUM_RISK_ONE"'}
)
# Iterate an print all finding names and the resource they are
# in reference to.
for i, finding_result in enumerate(finding_result_iterator):
    print(
        "{}: name: {} resource: {}".format(
            i, finding_result.finding.name, finding_result.finding.resource_name
        )
    )

Java

static ImmutableList<ListFindingsResult> listFilteredFindings(SourceName sourceName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // parentId: must be one of the following:
    //    "organization-id"
    //    "project-id"
    //    "folder-id"
    // SourceName sourceName = SourceName.of(parentId, sourceId);

    // Create filter to category of MEDIUM_RISK_ONE
    String filter = "category=\"MEDIUM_RISK_ONE\"";

    ListFindingsRequest.Builder request =
        ListFindingsRequest.newBuilder().setParent(sourceName.toString()).setFilter(filter);

    // Call the API.
    ListFindingsPagedResponse response = client.listFindings(request.build());

    // This creates one list for all findings.  If your organization has a large number of
    // findings this can cause out of memory issues.  You can process them in incrementally
    // by returning the Iterable returned response.iterateAll() directly.
    ImmutableList<ListFindingsResult> results = ImmutableList.copyOf(response.iterateAll());
    System.out.println("Findings:");
    System.out.println(results);
    return results;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"cloud.google.com/go/securitycenter/apiv1/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
}

Node.js

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

// Creates a new client.
const client = new SecurityCenterClient();
//  sourceName is the full resource path of the source to search for
//  findings.
/*
 * TODO(developer): Uncomment the following lines
 */
// const sourceName = `${parent}/sources/${sourceId}`;
// where,
// parent: must be in one of the following formats:
//    `organizations/${organization_id}`
//    `projects/${project_id}`
//    `folders/${folder_id}`
async function listFilteredFindings() {
  const [response] = await client.listFindings({
    // List findings across all sources.
    parent: sourceName,
    filter: 'category="MEDIUM_RISK_ONE"',
  });
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.finding.name} ${result.finding.resourceName}`
    )
  );
}
listFilteredFindings();

Security Command Center est également compatible avec les tableaux et objets JSON entiers en tant que types de propriétés potentiels. Vous pouvez appliquer les filtres suivants :

  • Éléments de tableau
  • Objets JSON entiers avec correspondance de chaîne partielle dans l'objet
  • Sous-champs d'objets JSON

Opérateurs compatibles

Les instructions de requête pour les résultats de Security Command Center sont compatibles avec les opérateurs compatibles avec la plupart des API Google Cloud.

La liste suivante montre les différents opérateurs utilisés:

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

La liste suivante présente tous les opérateurs et fonctions compatibles avec les instructions de requête pour les résultats:

  • Pour les chaînes :
    • = pour une égalité totale
    • : pour une correspondance de chaîne partielle
  • Pour les chiffres :
    • <, >, <=, >= pour les inégalités
    • =, != pour les égalités
  • Pour les valeurs booléennes :
    • = pour obtenir les mêmes résultats
  • Pour les relations logiques :
    • AND
    • OR
    • NOT ou -
  • Pour les expressions de regroupement :
    • (, ) (parenthèses)
  • Pour les tableaux :
    • contains(), une fonction permettant d'interroger les résultats avec un champ de tableau contenant au moins un élément correspondant au filtre spécifié
    • containsOnly(), une fonction permettant d'interroger les résultats avec un champ de tableau ne contenant que des éléments correspondant au filtre spécifié
  • Pour les adresses IP :
    • inIpRange(), une fonction permettant d'interroger des adresses IP dans une plage CIDR spécifiée

Filtrer sur les adresses IP

Certaines propriétés de résultats incluent des adresses IP. Vous pouvez filtrer les résultats en fonction d'adresses IP spécifiques ou d'une plage d'adresses IP.

Les adresses IP apparaissent sous forme de chaînes dans divers résultats et propriétés de résultat, y compris les suivantes:

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

Pour filtrer sur une adresse IP spécifique, vous pouvez utiliser l'opérateur d'égalité, comme illustré dans l'exemple suivant:

access.caller_ip="192.0.2.0"

Pour filtrer les résultats en fonction d'une plage d'adresses IP, utilisez la fonction inIpRange. À l'aide de la fonction inIpRange, vous filtrez uniquement les résultats contenant une adresse IP dans une plage CIDR spécifiée. En utilisant l'opération NOT avec inIpRange, vous pouvez filtrer les résultats pour n'afficher que ceux contenant une adresse IP située en dehors de la plage CIDR spécifiée.

L'exemple suivant montre la syntaxe de la fonction inIpRange:

inIpRange(IP_FINDING_FIELD, "CIDR_RANGE")

Si l'adresse IP se trouve dans un élément de tableau d'un champ de résultat contenant un tableau, utilisez la syntaxe suivante avec les fonctions contains et inIpRange:

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

Dans l'exemple suivant, la fonction inIpRange évalue chaque élément destination_ip du tableau contenu dans le champ de recherche connections pour trouver une adresse IP comprise dans la plage CIDR définie par 192.0.2.0/24:

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

L'exemple suivant montre une commande de gcloud CLI qui utilise la fonction inIpRange pour filtrer les résultats dont l'adresse IP du champ connections.source_ip est comprise dans une plage, mais pas dans une autre. Le champ connections est un champ de type tableau. La fonction contains est donc utilisée:

  gcloud scc findings list example-organization.com \
    --source=123456789012345678 \
    --filter="contains(connections, inIpRange(source_ip, "2001:db8::/32")) \
      AND NOT contains(connections, inIpRange(source_ip, "192.0.2.0/24"))

Exemple d'objet JSON

Dans les exemples décrits ultérieurement sur cette page, nous partons du principe que l'objet JSON suivant est un attribut de résultat :

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

Exemple de filtrage de résultats

Supposons que l'exemple JSON précédent est un attribut de résultat nommé my_property. L'exemple suivant inclut des requêtes de résultats contenant l'objet en tant que propriété. Vous pouvez également associer ces filtres à d'autres filtres en utilisant AND et OR dans votre requête.

# ORGANIZATION_ID=organization-id
# SOURCE_ID="source-id"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.middle_object.deeply_nested_object.x = 123"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.middle_object.y = \"some-string-value\""

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.middle_object.y : \"string-value\""

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.z = \"some-other-string-value\""

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.z : \"other-string-value\""

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.u : \"list-element-1\""

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.u : \"list-element-2\""

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="my_property.outer_object.u : \"list-element-3\""

Filtrer les champs de type tableau

Lorsque vous appelez ListFindings, vous pouvez utiliser une correspondance de sous-chaîne :, qui effectue une seule vérification d'une correspondance de chaîne partielle dans l'ensemble du contenu du tableau. Vous pouvez également exécuter un sous-filtre directement sur les éléments du tableau et ses sous-champs à l'aide de l'une des fonctions suivantes:

  • La fonction contains() pour renvoyer les résultats lorsque l'un des éléments du tableau contient la valeur spécifiée.

  • La fonction containsOnly() pour ne renvoyer les résultats que si tous les éléments du tableau correspondent au sous-filtre.

Ces deux fonctions sont compatibles avec des fonctionnalités de requête de sous-filtre, telles que les suivantes:

  • Correspondance exacte des éléments : fait correspondre les éléments d'un tableau contenant la chaîne exacte "example".
  • Opérations arithmétiques spécifiques : fait correspondre les éléments d'un tableau supérieurs ou égaux à 100.
  • Filtrage complexe en fonction des structures des tableaux : fait correspondre les éléments d'un tableau contenant la propriété x avec une valeur y correspondante.

Format de la fonction contains()

La fonction contains() a le format suivant :

contains(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

Remplacez les éléments suivants :

  • ARRAY_ATTRIBUTE_NAME : champ ou sous-champ de type tableau (liste).
  • SUBFILTER : expression qui définit les valeurs à rechercher dans le tableau. Le format du sous-filtre diffère selon que ARRAY_ATTRIBUTE_NAME est un tableau d'objets ou un tableau d'éléments de type primitif. Si ARRAY_ATTRIBUTE_NAME est un tableau d'objets comportant des tableaux imbriqués, vous pouvez utiliser un sous-filtre spécifique pour indiquer que vous souhaitez que toutes les conditions soient remplies dans le même élément ARRAY_ATTRIBUTE_NAME.

L'API Security Command Center renvoie les résultats pour lesquels ARRAY_ATTRIBUTE_NAME contient au moins un élément correspondant au sous-filtre SUBFILTER.

Format de la fonction containsOnly()

La fonction containsOnly() a le format suivant :

containsOnly(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

Remplacez les éléments suivants :

  • ARRAY_ATTRIBUTE_NAME: champ ou sous-champ de type tableau (liste). Lorsque vous exécutez des requêtes à l'aide de l'API Security Command Center, vous pouvez utiliser la fonction containsOnly() pour tout attribut de tableau disponible.

  • SUBFILTER : expression qui définit les valeurs à rechercher dans le tableau. Le format du sous-filtre diffère selon que ARRAY_ATTRIBUTE_NAME est un tableau d'objets ou un tableau d'éléments de type primitif. Si ARRAY_ATTRIBUTE_NAME est un tableau d'objets comportant des tableaux imbriqués, vous pouvez utiliser un sous-filtre limité pour indiquer que vous souhaitez que toutes les conditions soient remplies dans le même élément ARRAY_ATTRIBUTE_NAME.

L'API Security Command Center renvoie les résultats dont tous les éléments ARRAY_ATTRIBUTE_NAME correspondent à SUBFILTER.

Sous-filtre pour un tableau d'objets

Voici un extrait de l'exemple JSON précédent. Ici, le champ list_middle_object est un tableau d'objets :

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

L'exemple suivant interroge les résultats pour lesquels au moins un des éléments du champ list_middle_object comporte un sous-champ v dont la valeur est supérieure ou égale à 321 :

# ORGANIZATION_ID=organization-id
# SOURCE_ID="source-id"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="contains(my_property.outer_object.list_middle_object, v  >= 321)"

Pour obtenir des exemples pratiques qui utilisent les fonctions contains() et containsOnly(), consultez la section Résultats contenant des valeurs de tableau spécifiques.

Sous-filtre pour un tableau contenant des éléments de type primitif

Les types primitifs sont des chaînes, des nombres et des valeurs booléennes. Pour utiliser la fonction contains() sur un tableau contenant des types primitifs, vous devez utiliser le mot clé spécial elem.

Voici un extrait de l'exemple JSON précédent. Ici, le champ u est un tableau d'éléments de type primitif :

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

L'exemple suivant interroge les résultats pour lesquels au moins un des éléments du champ u est "list-element-1" :

# ORGANIZATION_ID=organization-id
# SOURCE_ID="source-id"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="contains(my_property.outer_object.u, elem = \"list-element-1\")"

Pour obtenir des exemples pratiques utilisant la fonction contains(), consultez la section Résultats contenant des valeurs de tableau spécifiques.

Sous-filtre spécifique

Voici un extrait de l'exemple JSON précédent. Ici, le champ list_middle_object est un tableau d'objets. Les objets de ce tableau contiennent un tableau imbriqué.

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

L'exemple suivant interroge les résultats pour lesquels les deux conditions suivantes sont remplies dans le même élément list_middle_object :

  • La valeur du sous-champ v est supérieure ou égale à 321.
  • Le sous-champ w ne contient pas d'élément dont la propriété a est égale à 3.
# ORGANIZATION_ID=organization-id
# SOURCE_ID="source-id"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --filter="contains(my_property.outer_object.list_middle_object, v  >= 321 AND -contains(w, a = 3))"

Pour obtenir des exemples pratiques utilisant la fonction contains(), consultez la section Résultats contenant des valeurs de tableau spécifiques.

Exemple de tri des résultats

Vous pouvez trier les résultats par sous-champs stricts de type primitif : chaînes, nombres et booléens. Supposons que l'exemple JSON précédent est un attribut de résultat nommé my_property. L'exemple suivant inclut des requêtes permettant de trier les champs de résultats. Le mot clé DESC indique que le champ suivant doit être trié par ordre décroissant. L'ordre par défaut est croissant.

# ORGANIZATION_ID=organization-id
# SOURCE_ID="source-id"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --order-by="my_property.outer_object.middle_object.deeply_nested_object.x DESC"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --order-by="my_property.outer_object.middle_object.deeply_nested_object.x"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --order-by="my_property.outer_object.middle_object.y DESC"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --order-by="my_property.outer_object.middle_object.y"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --order-by="my_property.outer_object.z DESC"

gcloud scc findings list $ORGANIZATION_ID --source=$SOURCE_ID \
  --order-by="my_property.outer_object.z"

Exemples de filtres

Les sections suivantes présentent des exemples pratiques de filtres de résultats.

Filtrer les résultats générés après un moment précis

Ces exemples de filtres correspondent aux résultats les plus récents obtenus après le mercredi 5 juin 2019 à 22:12:05 GMT. Avec le filtre event_time, vous pouvez exprimer le temps en utilisant les formats et types suivants :

  • Epoch Unix (en millisecondes) sous forme de littéral entier

    "event_time > 1559772725000"
    
  • RFC 3339 en tant que littéral de chaîne

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

Filtrer les champs de type tableau

L'exemple suivant décrit l'utilisation d'une correspondance de chaîne partielle sur un champ de type tableau dans un filtre :

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

L'API Security Command Center renvoie tous les résultats avec une chaîne partielle website.com dans le tableau. Par exemple, il fait correspondre un résultat avec indicator.domains = [\"onewebsite.com\"], car "website.com" est une sous-chaîne dans un élément du tableau.

Dans les sections suivantes, les exemples de filtres montrent certaines options d'utilisation d'un filtre complet de type tableau à l'aide de la fonction contains().

Filtrer le champ vulnerability.cve.references

L'exemple suivant renvoie les résultats pour lesquels au moins un élément du tableau vulnerability.cve.references possède une propriété source égale à SOURCE_OF_REFERENCE et une propriété uri contenant FILTERED_URI.

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

Remplacez les éléments suivants :

Filtrer le champ indicator.domains

L'exemple suivant renvoie les résultats pour lesquels au moins un domaine d'indicateur contient à la fois mycompanyprefix et .ca.

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

Filtrer le champ indicator.ip_addresses

L'exemple suivant renvoie les résultats pour lesquels au moins un élément du tableau indicator.ip_addresses est égal à IP_ADDRESS.

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

Remplacez IP_ADDRESS par une adresse IP associée aux résultats que vous recherchez.

Filtrer les personnes responsables des systèmes externes

L'exemple suivant renvoie les résultats pour lesquels au moins un élément du tableau external_systems.EXTERNAL_SYSTEM_NAME.assignees est égal à ASSIGNEE.

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

Remplacez les éléments suivants :

  • EXTERNAL_SYSTEM_NAME : nom d'un système SIEM/SOAR tiers, par exemple demisto.
  • ASSIGNEE : personne responsable d'un système externe.

Filtrer le champ resource.folders.resource_folder

L'exemple suivant renvoie les résultats pour lesquels au moins un élément du tableau resource.folders.resource_folder n'est pas égal à FOLDER_NAME.

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

Filtrer le champ resource.folders.resource_folder_display_name

L'exemple suivant renvoie les résultats pour lesquels au moins un élément du tableau resource.folders.resource_folder_display_name est égal à DISPLAY_NAME.

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

Remplacez DISPLAY_NAME par le nom défini par l'utilisateur pour le dossier associé aux résultats que vous recherchez.

Le filtre n'inclut que des comptes de service spécifiques

L'exemple suivant ne renvoie des résultats que lorsque la valeur de membre de chaque entrée iam_bindings est égale à l'un des comptes de service fournis.

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

Remplacez SERVICE_ACCOUNT1, SERVICE_ACCOUNT2 et SERVICE_ACCOUNT3 par les adresses e-mail des comptes de service.

Pour savoir comment utiliser les fonctions contains() et containsOnly() dans un filtre de résultats, consultez la section Filtrer sur des champs de type tableau.

Étapes suivantes

En savoir plus sur la configuration des notifications de résultats.