Security Command Center API를 사용하여 보안 발견 항목 나열

Security Command Center 발견 항목은 프로젝트나 조직에 있는 애셋의 잠재적 보안 위험을 모델링합니다. 발견 항목은 항상 Security Command Center의 특정 애셋과 관련이 있습니다.

이 가이드에서는 Security Command Center 클라이언트 라이브러리를 사용하여 발견 항목에 액세스하는 방법을 설명합니다. 각 발견 항목은 소스에 속합니다. 대부분의 감지기나 발견 항목 제공업체는 동일한 소스 내에서 발견 항목을 생성합니다.

Security Command Center의 IAM 역할은 조직, 폴더, 프로젝트 수준에서 부여할 수 있습니다. 발견 항목, 애셋, 보안 소스를 보거나 수정하거나 만들거나 업데이트할 수 있는 기능은 액세스 권한이 부여된 수준에 따라 다릅니다. Security Command Center 역할에 대해 자세히 알아보려면 액세스 제어를 참조하세요.

시작하기 전에

소스를 설정하기 전에 다음을 완료해야 합니다.

페이지 크기

모든 Security Command Center 목록 API는 페이지로 나뉩니다. 각 응답은 결과 페이지와 다음 페이지를 반환하는 토큰을 반환합니다. 페이지 크기는 구성 가능합니다. 기본 페이지 크기는 10입니다. 최소 1에서 최대 1,000으로 설정할 수 있습니다.

발견 항목 보관

최소 13개월 동안 발견 항목을 나열하거나 쿼리할 수 있습니다.

Security Command Center는 각 발견 항목의 스냅샷을 저장합니다. 발견 항목 스냅샷은 최소 13개월 동안 보관됩니다. 발견 항목의 모든 스냅샷이 삭제되면 더 이상 발견 항목을 나열하거나 복구할 수 없습니다.

Security Command Center 데이터 보관에 대한 자세한 내용은 데이터 보관을 참조하세요.

모든 발견 항목 나열

gcloud

프로젝트, 폴더 또는 조직의 모든 발견 항목을 나열하려면 다음 명령어를 실행합니다.

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

다음을 바꿉니다.

  • PARENT_TYPE: 발견 항목을 나열할 리소스 계층 구조의 수준입니다. organizations, folders 또는 projects를 사용합니다.
  • PARENT_ID: 조직, 폴더 또는 프로젝트의 숫자 ID 또는 영숫자 프로젝트 ID입니다.
  • LOCATION: 데이터 상주가 사용 설정된 경우 발견 항목을 나열할 Security Command Center 위치입니다. 데이터 상주가 사용 설정되지 않았으면 global 값을 사용합니다.

더 많은 예시를 보려면 다음을 실행하세요.

gcloud scc findings list --help

문서의 예시는 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
}

자바


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

각 발견 항목의 출력은 다음과 비슷합니다.

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

발견 항목 필터링

프로젝트, 폴더 또는 조직에는 많은 발견 항목이 있을 수 있습니다. 앞의 예시에서는 필터를 사용하지 않으므로 모든 발견 항목 레코드가 반환됩니다.

원하는 필드에 대한 정보만 가져오려면 검색 필터를 사용하세요. 이러한 필터는 SQL 문의 'where' 절과 같지만 열 대신 API에서 반환한 객체에 적용됩니다.

다음 예시에서는 'MEDIUM_RISK_ONE' 카테고리가 있는 발견 항목만 나열합니다. 발견 항목 제공업체(보안 소스라고도 함)마다 서로 다른 카테고리 집합을 사용합니다. 필터에서 사용할 수 있는 카테고리를 확인하려면 발견 항목 제공업체의 문서를 참조하세요.

gcloud

다음 명령어를 사용하여 발견 항목을 필터링합니다.

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

다음을 바꿉니다.

  • PARENT_TYPE: 발견 항목을 나열할 리소스 계층 구조의 수준입니다. organizations, folders 또는 projects를 사용합니다.
  • PARENT_ID: 조직, 폴더 또는 프로젝트의 숫자 ID 또는 영숫자 프로젝트 ID입니다.
  • LOCATION: 데이터 상주가 사용 설정된 경우 필터로 발견 항목을 나열할 Security Command Center 위치입니다. 데이터 상주가 사용 설정되지 않았으면 global 값을 사용합니다.
  • SOURCE_ID: 발견 항목 유형을 제공하는 보안 소스의 ID입니다.
  • FILTER: 사용해야 하는 필터입니다. 예를 들어 다음 필터는 MEDIUM_RISK_ONE 카테고리의 발견 항목만 반환합니다.
    --filter="category=\"MEDIUM_RISK_ONE\""

더 많은 예시를 보려면 다음을 실행하세요.

gcloud scc findings list --help

문서의 예시는 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
}

자바


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는 전체 JSON 배열 및 객체를 잠재적인 속성 유형으로 지원합니다. 다음을 기준으로 필터링할 수 있습니다.

  • 배열 요소
  • 객체 내에서 부분 문자열이 일치하는 전체 JSON 객체
  • JSON 객체 하위 필드

지원되는 연산자

Security Command Center 발견 항목의 쿼리 문은 대부분의 Google Cloud API에서 지원하는 연산자를 지원합니다.

다음 목록은 다양한 연산자의 사용을 보여줍니다.

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

다음 목록은 발견 항목의 쿼리 문에서 지원되는 모든 연산자와 함수를 보여줍니다.

  • 문자열:
    • 전체 같음: =
    • 부분 문자열 일치: :
  • 숫자:
    • 같지 않음: <, >, <=, >=
    • 같음: =, !=
  • 불리언:
    • 같음: =
  • 논리적 관계:
    • AND
    • OR
    • NOT 또는 -
  • 그룹화 표현식:
    • (, )(괄호)
  • 배열:
    • contains() - 지정된 필터와 일치하는 요소가 최소 하나 이상 포함된 배열 필드가 있는 발견 항목을 쿼리하는 함수입니다.
    • containsOnly() - 지정된 필터와 일치하는 요소만 포함된 배열 필드가 있는 발견 항목을 쿼리하는 함수입니다.
  • IP 주소:
    • inIpRange() - 지정된 CIDR 범위 내의 IP 주소를 쿼리하는 함수입니다.

IP 주소 필터링

특정 발견 항목 속성에는 IP 주소가 포함됩니다. 특정 IP 주소나 IP 주소 범위를 기준으로 발견 항목을 필터링할 수 있습니다.

IP 주소는 다음을 포함한 다양한 발견 항목 및 발견 항목 속성에서 문자열로 표시됩니다.

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

특정 IP 주소를 필터링하려면 다음 예시와 같이 등호 연산자를 사용하면 됩니다.

access.caller_ip="192.0.2.0"

IP 주소 범위를 기준으로 발견 항목을 필터링하려면 inIpRange 함수를 사용합니다. inIpRange 함수를 사용하면 지정된 CIDR 범위 내의 IP 주소가 포함된 발견 항목으로만 발견 항목을 필터링할 수 있습니다. inIpRange와 함께 NOT을 사용하면 지정된 CIDR 범위 밖에 있는 IP 주소가 포함된 발견 항목으로만 발견 항목을 필터링할 수 있습니다.

다음 예시에서는 inIpRange 함수의 구문을 보여줍니다.

inIpRange(IP_FINDING_FIELD, "CIDR_RANGE")

IP 주소가 배열이 포함된 발견 항목 필드의 배열 요소에 있으면 contains 함수 및 inIpRange 함수와 함께 다음 구문을 사용합니다.

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

다음 예시에서 inIpRange 함수는 192.0.2.0/24로 정의된 CIDR 범위에 있는 IP 주소의 connections 발견 항목 필드에 포함된 배열의 각 destination_ip 요소를 평가합니다.

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

다음 예시에서는 inIpRange 함수를 사용하여 다른 범위가 아닌 한 범위 내에 있는 IP 주소가 connections.source_ip 필드에 있는 발견 항목을 필터링하는 gcloud CLI 명령어를 보여줍니다. connections 필드는 배열 유형 필드이므로 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\"))"

JSON 객체 예시

이 페이지 뒷부분에 예시에서는 다음 JSON 객체가 발견 항목 속성이라고 가정합니다.

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

발견 항목 필터링 예시

이전 JSON 예시my_property라는 발견 항목 속성이라고 가정합니다. 다음 예시에는 객체를 속성으로 가진 발견 항목에 대한 쿼리가 포함되어 있습니다. 쿼리에서 ANDOR를 사용하여 이러한 필터를 다른 필터와 함께 사용할 수도 있습니다.

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

배열 유형 필드의 하위 필터

ListFindings를 호출할 때 배열의 전체 콘텐츠에서 부분 문자열 일치를 한 번 확인하는 하위 문자열 일치 :를 사용할 수 있습니다. 또는 다음 함수 중 하나를 사용하여 배열의 요소와 하위 필드에 직접 하위 필터를 실행할 수 있습니다.

  • 배열의 요소에 지정된 값이 포함되면 발견 항목을 반환하는 contains() 함수

  • 배열의 모든 요소가 하위 필터와 일치하는 경우에만 발견 항목을 반환하는 containsOnly() 함수

두 함수 모두 다음과 같은 하위 필터 쿼리 기능을 지원합니다.

  • 정확한 요소 일치: 정확한 문자열 "example"이 포함된 배열 요소를 일치시킵니다.
  • 특정 숫자 연산: 100보다 크거나 같은 배열 요소를 일치시킵니다.
  • 배열 구조에 대한 복잡한 필터링: x 속성이 포함된 배열 요소를 해당 값 y와 일치시킵니다.

contains() 함수 형식

contains() 함수 형식은 다음과 같습니다.

contains(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

다음을 바꿉니다.

  • ARRAY_ATTRIBUTE_NAME: 유형 배열 (목록)인 필드나 하위 필드입니다.
  • SUBFILTER: 배열에서 찾을 값을 정의하는 표현식입니다. 하위 필터 형식은 ARRAY_ATTRIBUTE_NAME객체 배열인지 또는 기본 유형 요소의 배열인지 여부에 따라 달라집니다. ARRAY_ATTRIBUTE_NAME가 중첩된 배열이 있는 객체의 배열인 경우 범위가 지정된 하위 필터를 사용하여 모든 조건이 동일한 ARRAY_ATTRIBUTE_NAME 요소 내에서 충족되도록 지정할 수 있습니다.

Security Command Center API는 ARRAY_ATTRIBUTE_NAMESUBFILTER를 충족하는 요소가 하나 이상 포함된 발견 항목을 반환합니다.

containsOnly() 함수 형식

containsOnly() 함수 형식은 다음과 같습니다.

containsOnly(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

다음을 바꿉니다.

  • ARRAY_ATTRIBUTE_NAME: 유형 배열 (목록)인 필드나 하위 필드입니다. Security Command Center API를 사용하여 쿼리를 실행할 때는 사용 가능한 배열 속성에 containsOnly() 함수를 사용할 수 있습니다.
  • SUBFILTER: 배열에서 찾을 값을 정의하는 표현식입니다. 하위 필터 형식은 ARRAY_ATTRIBUTE_NAME객체 배열인지 또는 기본 유형 요소의 배열인지 여부에 따라 달라집니다. ARRAY_ATTRIBUTE_NAME가 중첩된 배열이 있는 객체의 배열인 경우 범위가 지정된 하위 필터를 사용하여 모든 조건이 동일한 ARRAY_ATTRIBUTE_NAME 요소 내에서 충족되도록 지정할 수 있습니다.

Security Command Center API는 모든 ARRAY_ATTRIBUTE_NAME 요소가 SUBFILTER와 일치하는 발견 항목을 반환합니다.

객체 배열의 하위 필터

다음은 이전 JSON 예시의 일부입니다. 여기서 list_middle_object 필드는 객체 배열입니다.

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

다음 예시에서는 list_middle_object 필드의 요소 중 최소 하나 이상에 값이 321보다 크거나 같은 v 하위 필드가 있는 발견 항목을 쿼리합니다.

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

contains()containsOnly() 함수를 사용하는 실제 예시는 특정 배열 값이 포함된 발견 항목을 참조하세요.

기본 유형 요소가 포함된 배열의 하위 필터

기본 유형은 문자열, 숫자, 부울입니다. 기본 유형이 포함된 배열에 contains() 함수를 사용하려면 특수 키워드 elem을 사용합니다.

다음은 이전 JSON 예시의 일부입니다. 여기서 u 필드는 기본 유형 요소의 배열입니다.

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

다음 예시에서는 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\")"

contains() 함수를 사용하는 실제 예시는 특정 배열 값이 포함된 발견 항목을 참조하세요.

범위가 지정된 하위 필터

다음은 이전 JSON 예시의 일부입니다. 여기서 list_middle_object 필드는 객체의 배열이며 이 배열의 객체에는 중첩된 배열이 포함됩니다.

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

다음 예시에서는 동일한 list_middle_object 요소 내에서 다음 두 조건이 모두 충족하는 발견 항목을 쿼리합니다.

  • v 하위 필드 값은 321보다 크거나 같습니다.
  • w 하위 필드에는 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))"

contains() 함수를 사용하는 실제 예시는 특정 배열 값이 포함된 발견 항목을 참조하세요.

발견 항목 정렬 예시

기본 유형인 엄격한 하위 필드(문자열, 숫자, 부울)로 발견 항목을 정렬할 수 있습니다. 이전 JSON 예시my_property라는 발견 항목 속성이라고 가정합니다. 다음 예시에는 발견 항목 필드를 정렬하는 쿼리가 포함되어 있습니다. 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 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"

필터 예시

다음 섹션에서는 발견 항목 필터의 실제 예시를 보여줍니다.

특정 시점 이후에 발생한 발견 항목을 기준으로 필터링

이러한 필터 예시는 2019년 6월 5일 수요일 오후 10:12:05 GMT 이후 가장 최근에 발생한 결과와 일치합니다. event_time 필터를 사용하면 다음 형식과 유형을 사용하여 시간을 표현할 수 있습니다.

  • 정수 리터럴로서의 Unix epoch 시간(밀리초)

    "event_time > 1559772725000"
    
  • 문자열 리터럴로서의 RFC 3339

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

배열 유형 필드를 기준으로 필터링

다음 예시에서는 필터 내 배열 유형 필드에서 부분 문자열 일치를 사용하는 방법을 보여줍니다.

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

Security Command Center API는 배열 내에 website.com 부분 문자열이 있는 모든 발견 항목을 반환합니다. 예를 들어 'website.com'이 배열 요소의 하위 문자열이므로 발견 항목을 indicator.domains = [\"onewebsite.com\"]과 일치시킵니다.

다음 섹션의 예시 필터에서는 contains() 함수를 사용하여 다양한 배열 유형 필터링을 사용하기 위한 몇 가지 옵션을 보여줍니다.

vulnerability.cve.references 필드를 기준으로 필터링

다음 예에서는 vulnerability.cve.references 배열의 요소 중 최소 하나 이상에서 SOURCE_OF_REFERENCE와 동일한 source 속성과 FILTERED_URI가 있는 uri 속성이 모두 있는 발견 항목을 반환합니다.

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

다음을 바꿉니다.

indicator.domains 필드를 기준으로 필터링

다음 예시에서는 표시기 도메인 최소 하나 이상에서 mycompanyprefix.ca가 모두 있는 발견 항목을 반환합니다.

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

indicator.ip_addresses 필드를 기준으로 필터링

다음 예시에서는 indicator.ip_addresses 배열의 요소 중 최소 하나 이상이 IP_ADDRESS과 동일한 발견 항목을 반환합니다.

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

IP_ADDRESS를 검색 중인 발견 항목과 연결된 IP 주소로 바꿉니다.

외부 시스템 담당자를 기준으로 필터링

다음 예시에서는 external_systems.EXTERNAL_SYSTEM_NAME.assignees 배열의 요소 중 최소 하나 이상이 ASSIGNEE과 동일한 발견 항목을 반환합니다.

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

다음을 바꿉니다.

  • EXTERNAL_SYSTEM_NAME: 서드 파티 SIEM/SOAR 시스템의 이름입니다(예: demisto).
  • ASSIGNEE: 외부 시스템의 담당자입니다.

resource.folders.resource_folder 필드를 기준으로 필터링

다음 예시에서는 resource.folders.resource_folder 배열의 요소 중 최소 하나 이상이 FOLDER_NAME과 같지 않은 발견 항목을 반환합니다.

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

resource.folders.resource_folder_display_name 필드를 기준으로 필터링

다음 예시에서는 resource.folders.resource_folder_display_name 배열의 요소 중 최소 하나 이상이 DISPLAY_NAME과 동일한 발견 항목을 반환합니다.

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

DISPLAY_NAME를 검색 중인 발견 항목과 연결된 폴더의 사용자 정의 이름으로 바꿉니다.

필터에 특정 서비스 계정만 포함

다음 예시는 모든 iam_bindings 항목의 구성원 값이 제공된 서비스 계정 중 하나와 동일한 경우에만 발견 항목을 반환합니다.

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

SERVICE_ACCOUNT1, SERVICE_ACCOUNT2, SERVICE_ACCOUNT3을 서비스 계정의 이메일 주소로 바꿉니다.

발견 항목 필터에서 contains()containsOnly() 함수를 사용하는 방법은 배열 유형 필드의 하위 필터를 참고하세요.

다음 단계

발견 항목 알림 설정 자세히 알아보기