Security Command Center API를 사용하여 애셋 나열

애셋은 Compute Engine 인스턴스 또는 Cloud Storage 버킷과 같은 조직의 Google Cloud 리소스입니다.

이 가이드에서는 Security Command Center 클라이언트 라이브러리를 사용하여 Security Command Center가 프로젝트 또는 조직에서 애셋에 대해 유지보수하는 지원 중단된 레코드에 액세스하는 방법을 보여줍니다.

Security Command Center는 Cloud 애셋 인벤토리의 애셋 하위 집합에 대해서만 레코드를 유지합니다. 환경에 있는 전체 애셋 목록을 보려면 Cloud 애셋 인벤토리를 사용해서 애셋을 나열합니다.

자세한 내용은 다음을 참조하세요.

IAM 역할의 부여 수준

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

시작하기 전에

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

페이지 크기

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

리소스 유형

Security Command Center의 resourceType 속성에서는 Cloud 애셋 인벤토리와 다른 이름 지정 규칙이 사용됩니다. 리소스 유형 형식 목록은 Security Command Center에서 지원되는 애셋 유형을 참조하세요.

모든 애셋 나열

이 예시에서는 모든 애셋을 나열하는 방법을 보여줍니다.

gcloud

프로젝트, 폴더 또는 조직의 모든 애셋을 나열하려면 다음 명령어를 실행하세요.

gcloud scc assets list PARENT_ID

PARENT_ID를 다음 값 중 하나로 바꿉니다.

  • ORGANIZATION_ID 형식의 조직 ID(숫자 ID만 해당)
  • folders/FOLDER_ID 형식의 폴더 ID
  • projects/PROJECT_ID 형식의 프로젝트 ID

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

 gcloud scc assets list --help

문서의 예시는 gcloud scc 애셋 목록을 참조하세요.

Python

from google.cloud import securitycenter

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

# Call the API and print results.
asset_iterator = client.list_assets(request={"parent": parent})
for i, asset_result in enumerate(asset_iterator):
    print(i, asset_result)

자바

static ImmutableList<ListAssetsResult> listAssets(OrganizationName organizationName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to search for all assets in an organization, project, or folder.
    //
    // Parent must be in one of the following formats:
    //    OrganizationName organizationName = OrganizationName.of("organization-id");
    //    ProjectName projectName = ProjectName.of("project-id");
    //    FolderName folderName = FolderName.of("folder-id");
    ListAssetsRequest.Builder request =
        ListAssetsRequest.newBuilder().setParent(organizationName.toString());

    // Call the API.
    ListAssetsPagedResponse response = client.listAssets(request.build());

    // This creates one list for all assets.  If your organization has a large number of assets
    // this can cause out of memory issues.  You can process them incrementally by returning
    // the Iterable returned response.iterateAll() directly.
    ImmutableList<ListAssetsResult> results = ImmutableList.copyOf(response.iterateAll());
    System.out.println("All assets:");
    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"
)

// listAllAssets prints every asset to w for orgID. orgID is the numeric
// Organization ID.
func listAllAssets(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.ListAssetsRequest{
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}"
		//		"projects/{projectId}"
		//		"folders/{folderId}"
		Parent: fmt.Sprintf("organizations/%s", orgID),
	}

	assetsFound := 0
	it := client.ListAssets(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("ListAssets: %w", err)
		}
		asset := result.Asset
		properties := asset.SecurityCenterProperties
		fmt.Fprintf(w, "Asset Name: %s,", asset.Name)
		fmt.Fprintf(w, "Resource Name %s,", properties.ResourceName)
		fmt.Fprintf(w, "Resource Type %s\n", properties.ResourceType)
		assetsFound++
	}
	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
 */
// parent: must be in one of the following formats:
//    `organizations/${organization_id}`
//    `projects/${project_id}`
//    `folders/${folder_id}`
const parent = `organizations/${organizationId}`;
// Call the API with automatic pagination.
async function listAssets() {
  const [response] = await client.listAssets({parent: parent});
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.asset.name} ${
        result.asset.securityCenterProperties.resourceName
      }`
    )
  );
}

listAssets();

각 애셋의 출력은 다음과 유사한 JSON 객체입니다.

asset:
  createTime: '2020-10-05T17:55:14.823Z'
  iamPolicy:
    policyBlob: '{"bindings":[{"role":"roles/owner","members":["serviceAccount:SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com","user:USER_EMAIL@gmail.com"]}]}'
  name: organizations/ORGANIZATION_ID/assets/ASSET_ID
  resourceProperties:
    createTime: '2020-10-05T17:36:17.915Z'
    lifecycleState: ACTIVE
    name: PROJECT_ID
    parent: '{"id":"ORGANIZATION_ID","type":"organization"}'
    projectId: PROJECT_ID
    projectNumber: 'PROJECT_NUMBER'
  securityCenterProperties:
    resourceDisplayName: PROJECT_ID
    resourceName: //cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER
    resourceOwners:
    - serviceAccount:SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com
    - user:USER_EMAIL@gmail.com
    resourceParent: //cloudresourcemanager.googleapis.com/organizations/ORGANIZATION_ID
    resourceParentDisplayName: ORGANIZATION_NAME
    resourceProject: //cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER
    resourceProjectDisplayName: PROJECT_ID
    resourceType: google.cloud.resourcemanager.Project
  securityMarks:
    name: organizations/ORGANIZATION_ID/assets/ASSET_ID/securityMarks
  updateTime: '2020-10-05T17:55:14.823Z'

애셋 필터링

프로젝트, 폴더 또는 조직에는 많은 애셋이 있을 수 있습니다. 앞의 예시에서는 필터를 사용하지 않으므로 모든 애셋이 반환됩니다. Security Command Center에서 애셋 필터를 사용하여 특정 애셋에 대한 정보를 가져올 수 있습니다. 필터는 열 대신 API에서 반환한 객체에 적용되는 것을 제외하고는 SQL 문의 'where' 절과 같습니다.

위의 예시에서 샘플 출력은 애셋 필터에 사용할 수 있는 일부 필드 및 하위 필드와 해당 속성을 보여줍니다. Security Command Center는 전체 JSON 배열 및 객체를 잠재적인 속성 유형으로 지원합니다. 다음을 기준으로 필터링할 수 있습니다.

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

하위 필드는 숫자, 문자열 또는 부울이어야 하며 필터 표현식에서 다음 비교 연산자를 사용해야 합니다.

  • 문자열:
    • 전체 같음 =
    • 부분 문자열 일치 :
  • 숫자:
    • 같지 않음 <, >, <=, >=
    • 같음 =
  • 부울:
    • 같음 =

다음 예시에서는 애셋을 필터링합니다.

gcloud

다음 명령어를 사용하여 애셋을 필터링합니다.

gcloud scc assets list PARENT_ID --filter="FILTER"

다음을 바꿉니다.

  • FILTER를 사용해야 하는 필터로 바꿉니다. 예를 들어 다음 필터는 프로젝트 리소스만 반환합니다.
    --filter="security_center_properties.resource_type=\"google.cloud.resourcemanager.Project\""
  • PARENT_ID를 다음 값 중 하나로 바꿉니다.
    • ORGANIZATION_ID 형식의 조직 ID(숫자 ID만 해당)
    • folders/FOLDER_ID 형식의 폴더 ID
    • projects/PROJECT_ID 형식의 프로젝트 ID

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

gcloud scc assets list --help

문서의 예시는 gcloud scc 애셋 목록을 참조하세요.

Python

from google.cloud import securitycenter

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

project_filter = (
    "security_center_properties.resource_type="
    + '"google.cloud.resourcemanager.Project"'
)
# Call the API and print results.
asset_iterator = client.list_assets(
    request={"parent": parent, "filter": project_filter}
)
for i, asset_result in enumerate(asset_iterator):
    print(i, asset_result)

자바

static ImmutableList<ListAssetsResult> listAssetsWithFilter(OrganizationName organizationName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to search for all assets in an organization, project, or folder.
    //
    // Parent must be in one of the following formats:
    //    OrganizationName organizationName = OrganizationName.of("organization-id");
    //    ProjectName projectName = ProjectName.of("project-id");
    //    FolderName folderName = FolderName.of("folder-id");
    ListAssetsRequest.Builder request =
        ListAssetsRequest.newBuilder()
            .setParent(organizationName.toString())
            .setFilter(
                "security_center_properties.resource_type=\"google.cloud.resourcemanager.Project\"");

    // Call the API.
    ListAssetsPagedResponse response = client.listAssets(request.build());

    // This creates one list for all assets.  If your organization has a large number of assets
    // this can cause out of memory issues.  You can process them incrementally by returning
    // the Iterable returned response.iterateAll() directly.
    ImmutableList<ListAssetsResult> results = ImmutableList.copyOf(response.iterateAll());
    System.out.println("Project assets:");
    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"
)

// listAllProjectAssets lists all current GCP project assets in orgID and
// prints out results to w. orgID is the numeric organization ID of interest.
func listAllProjectAssets(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.ListAssetsRequest{
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}"
		//		"projects/{projectId}"
		//		"folders/{folderId}"
		Parent: fmt.Sprintf("organizations/%s", orgID),
		Filter: `security_center_properties.resource_type="google.cloud.resourcemanager.Project"`,
	}

	assetsFound := 0
	it := client.ListAssets(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("ListAssets: %w", err)
		}
		asset := result.Asset
		properties := asset.SecurityCenterProperties
		fmt.Fprintf(w, "Asset Name: %s,", asset.Name)
		fmt.Fprintf(w, "Resource Name %s,", properties.ResourceName)
		fmt.Fprintf(w, "Resource Type %s\n", properties.ResourceType)
		assetsFound++
	}
	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";
const orgName = client.organizationPath(organizationId);

// Call the API with automatic pagination.
// You can also list assets in a project/ folder. To do so, modify the parent
// value and filter condition.
async function listFilteredAssets() {
  const [response] = await client.listAssets({
    parent: orgName,
    filter:
      'security_center_properties.resource_type="google.cloud.resourcemanager.Project"',
  });
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.asset.name} ${
        result.asset.securityCenterProperties.resourceName
      } ${result.stateChange}`
    )
  );
}

listFilteredAssets();

특정 시점에 나열

이전 예시에서는 현재 애셋 집합을 나열하는 방법을 보여줍니다. Security Command Center를 사용하면 애셋의 이전 스냅샷을 볼 수도 있습니다. 다음 예시에서는 특정 시점에 모든 애셋의 상태를 반환합니다. Security Command Center는 밀리초 시간 해결 방법을 지원합니다.

gcloud

다음 명령어를 사용하여 특정 시점을 기준으로 애셋을 나열합니다.

gcloud scc assets list PARENT_ID --read-time="READ_TIME"

다음을 바꿉니다.

  • READ_TIME을 애셋을 나열할 시간으로 바꿉니다. YYYY-MM-DDThh:mm:ss.ffffffZ 형식을 사용합니다. 예를 들면 다음과 같습니다.
    --read-time="2022-12-21T07:00:06.861Z"
  • PARENT_ID를 다음 값 중 하나로 바꿉니다.
    • ORGANIZATION_ID 형식의 조직 ID(숫자 ID만 해당)
    • projects/PROJECT_ID 형식의 프로젝트 ID
    • folders/FOLDER_ID 형식의 폴더 ID

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

gcloud scc assets list --help

문서의 예시는 gcloud scc 애셋 목록을 참조하세요.

Python

from datetime import datetime, timedelta, timezone

from google.cloud import securitycenter

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

project_filter = (
    "security_center_properties.resource_type="
    + '"google.cloud.resourcemanager.Project"'
)

# Lists assets as of yesterday.
read_time = datetime.now(tz=timezone.utc) - timedelta(days=1)

# Call the API and print results.
asset_iterator = client.list_assets(
    request={"parent": parent, "filter": project_filter, "read_time": read_time}
)
for i, asset_result in enumerate(asset_iterator):
    print(i, asset_result)

자바

static ImmutableList<ListAssetsResult> listAssetsAsOfYesterday(
    OrganizationName organizationName, Instant asOf) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to search for all assets in an organization, project, or folder.
    //
    // Parent must be in one of the following formats:
    //    OrganizationName organizationName = OrganizationName.of("organization-id");
    //    ProjectName projectName = ProjectName.of("project-id");
    //    FolderName folderName = FolderName.of("folder-id");
    // Initialize the builder with the parent and filter
    ListAssetsRequest.Builder request =
        ListAssetsRequest.newBuilder()
            .setParent(organizationName.toString())
            .setFilter(
                "security_center_properties.resource_type=\"google.cloud.resourcemanager.Project\"");

    // Set read time to either the instant passed in or one day ago.
    asOf = MoreObjects.firstNonNull(asOf, Instant.now().minus(Duration.ofDays(1)));
    request.getReadTimeBuilder().setSeconds(asOf.getEpochSecond()).setNanos(asOf.getNano());

    // Call the API.
    ListAssetsPagedResponse response = client.listAssets(request.build());

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

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"cloud.google.com/go/securitycenter/apiv1/securitycenterpb"
	"github.com/golang/protobuf/ptypes"
	"google.golang.org/api/iterator"
)

// listAllProjectAssets lists all GCP Projects in orgID at asOf time and prints
// out results to w. orgID is the numeric organization ID of interest.
func listAllProjectAssetsAtTime(w io.Writer, orgID string, asOf time.Time) 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.

	// Convert the time to a Timestamp protobuf
	readTime, err := ptypes.TimestampProto(asOf)
	if err != nil {
		return fmt.Errorf("TimestampProto(%v): %w", asOf, err)
	}

	// You can also list assets in a project/ folder. To do so, modify the parent and
	// filter condition.
	req := &securitycenterpb.ListAssetsRequest{
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}"
		//		"projects/{projectId}"
		//		"folders/{folderId}"
		Parent:   fmt.Sprintf("organizations/%s", orgID),
		Filter:   `security_center_properties.resource_type="google.cloud.resourcemanager.Project"`,
		ReadTime: readTime,
	}

	assetsFound := 0
	it := client.ListAssets(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("ListAssets: %w", err)
		}
		asset := result.Asset
		properties := asset.SecurityCenterProperties
		fmt.Fprintf(w, "Asset Name: %s,", asset.Name)
		fmt.Fprintf(w, "Resource Name %s,", properties.ResourceName)
		fmt.Fprintf(w, "Resource Type %s\n", properties.ResourceType)
		assetsFound++
	}
	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
 */
// parent: must be in one of the following formats:
//    `organizations/${organization_id}`
//    `projects/${project_id}`
//    `folders/${folder_id}`
const parent = `organizations/${organizationId}`;

const oneDayAgo = new Date();
oneDayAgo.setDate(oneDayAgo.getDate() - 1);

// Call the API with automatic pagination.
async function listAssetsAtTime() {
  const [response] = await client.listAssets({
    parent: parent,
    filter:
      'security_center_properties.resource_type="google.cloud.resourcemanager.Project"',
    // readTime must be in the form of a google.protobuf.Timestamp object
    // which takes seconds and nanoseconds.
    readTime: {
      seconds: Math.floor(oneDayAgo.getTime() / 1000),
      nanos: (oneDayAgo.getTime() % 1000) * 1e6,
    },
  });
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.asset.name} ${
        result.asset.securityCenterProperties.resourceName
      }`
    )
  );
}

listAssetsAtTime();

상태 변경이 있는 애셋 나열

Security Command Center를 사용하면 두 시점의 애셋을 비교하여 지정된 기간에 추가, 삭제 또는 표시된 애셋을 파악할 수 있습니다. 다음 예시에서는 READ_TIME에 존재하는 프로젝트를 COMPARE_DURATION의 의해 지정된 이전 시점과 비교합니다. COMPARE_DURATION은 초 단위로 제공됩니다.

COMPARE_DURATION이 설정되면 목록 애셋 결과의 stateChange 속성이 다음 값 중 하나로 업데이트됩니다.

  • ADDED: 애셋이 compareDuration의 시작 부분에는 없었으나 readTime에 있습니다.
  • REMOVED: 애셋이 compareDuration의 시작 부분에는 있었지만 readTime에는 없습니다.
  • ACTIVE: 애셋이 compareDurationreadTime에 의해 정의된 기간의 시작과 종료 시점 모두에 있습니다.

gcloud

다음 명령어를 사용하여 두 시점에 애셋의 상태를 비교합니다.

gcloud scc assets list PARENT_ID \
    --filter="FILTER" \
    --read-time=READ_TIME \
    --compare-duration=COMPARE_DURATION

다음을 바꿉니다.

  • COMPARE_DURATION--read-time 플래그에 지정된 시간 이전의 특정 시점을 정의하는 초 수로 바꿉니다. 예를 들면 다음과 같습니다.
    --compare-duration=84600s
  • FILTER를 사용해야 하는 필터로 바꿉니다. 예를 들어 다음 필터는 프로젝트 리소스만 반환합니다.
    --filter="security_center_properties.resource_type=\"google.cloud.resourcemanager.Project\""
  • PARENT_ID를 다음 값 중 하나로 바꿉니다.
    • ORGANIZATION_ID 형식의 조직 ID(숫자 ID만 해당)
    • projects/PROJECT_ID 형식의 프로젝트 ID
    • folders/FOLDER_ID 형식의 폴더 ID
  • READ_TIME을 애셋을 나열할 시간으로 바꿉니다. YYYY-MM-DDThh:mm:ss.ffffffZ 형식을 사용합니다. 예를 들면 다음과 같습니다.
    --read-time="2022-12-21T07:00:06.861Z"
    더 많은 예시를 보려면 다음을 실행하세요.
gcloud scc assets list --help

문서의 예시는 gcloud scc 애셋 목록을 참조하세요.

Python

from datetime import timedelta

from google.cloud import securitycenter

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}"
project_filter = (
    "security_center_properties.resource_type="
    + '"google.cloud.resourcemanager.Project"'
)

# List assets and their state change the last 30 days
compare_delta = timedelta(days=30)

# Call the API and print results.
asset_iterator = client.list_assets(
    request={
        "parent": parent,
        "filter": project_filter,
        "compare_duration": compare_delta,
    }
)
for i, asset in enumerate(asset_iterator):
    print(i, asset)

자바

static ImmutableList<ListAssetsResult> listAssetAndStatusChanges(
    OrganizationName organizationName, Duration timeSpan, Instant asOf) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {

    // Start setting up a request to search for all assets in an organization, project, or folder.
    //
    // Parent must be in one of the following formats:
    //    OrganizationName organizationName = OrganizationName.of("organization-id");
    //    ProjectName projectName = ProjectName.of("project-id");
    //    FolderName folderName = FolderName.of("folder-id");
    ListAssetsRequest.Builder request =
        ListAssetsRequest.newBuilder()
            .setParent(organizationName.toString())
            .setFilter(
                "security_center_properties.resource_type=\"google.cloud.resourcemanager.Project\"");
    request
        .getCompareDurationBuilder()
        .setSeconds(timeSpan.getSeconds())
        .setNanos(timeSpan.getNano());

    // Set read time to either the instant passed in or now.
    asOf = MoreObjects.firstNonNull(asOf, Instant.now());
    request.getReadTimeBuilder().setSeconds(asOf.getEpochSecond()).setNanos(asOf.getNano());

    // Call the API.
    ListAssetsPagedResponse response = client.listAssets(request.build());

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

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"cloud.google.com/go/securitycenter/apiv1/securitycenterpb"
	"github.com/golang/protobuf/ptypes"
	"google.golang.org/api/iterator"
)

// listAllProjectAssetsAndStateChange lists all current GCP project assets in
// orgID and prints the projects and there change from a day ago out to w.
// orgID is the numeric // organization ID of interest.
func listAllProjectAssetsAndStateChanges(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.ListAssetsRequest{
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}"
		//		"projects/{projectId}"
		//		"folders/{folderId}"
		Parent:          fmt.Sprintf("organizations/%s", orgID),
		Filter:          `security_center_properties.resource_type="google.cloud.resourcemanager.Project"`,
		CompareDuration: ptypes.DurationProto(24 * time.Hour),
	}

	assetsFound := 0
	it := client.ListAssets(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("ListAssets: %w", err)
		}
		asset := result.Asset
		properties := asset.SecurityCenterProperties
		fmt.Fprintf(w, "Asset Name: %s,", asset.Name)
		fmt.Fprintf(w, "Resource Name %s,", properties.ResourceName)
		fmt.Fprintf(w, "Resource Type %s", properties.ResourceType)
		fmt.Fprintf(w, "State Change %s\n", result.StateChange)
		assetsFound++
	}
	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
 */
// parent: must be in one of the following formats:
//    `organizations/${organization_id}`
//    `projects/${project_id}`
//    `folders/${folder_id}`
const parent = `organizations/${organizationId}`;
// Call the API with automatic pagination.
async function listAssetsAndChanges() {
  const [response] = await client.listAssets({
    parent: parent,
    compareDuration: {seconds: 30 * /*Second in Day=*/ 86400, nanos: 0},
    filter:
      'security_center_properties.resource_type="google.cloud.resourcemanager.Project"',
  });
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.asset.name} ${
        result.asset.securityCenterProperties.resourceName
      } ${result.stateChange}`
    )
  );
}

listAssetsAndChanges();

필터 예시

다음은 몇 가지의 다른 유용한 애셋 필터입니다. 필터에 ANDOR를 사용하여 매개변수를 결합하고 결과를 확장하거나 미세 조정할 수 있습니다.

특정 소유자가 있는 프로젝트 애셋 찾기

"security_center_properties.resource_type = \"google.cloud.resourcemanager.Project\" AND security_center_properties.resource_owners : \"$USER\""

$USER는 일반적으로 user:someone@domain.com 형식입니다. user 비교 시 하위 문자열 연산자 :를 사용하므로 일치검색은 필요하지 않습니다.

열린 HTTP 포트가 있는 방화벽 규칙

"security_center_properties.resource_type = \"google.compute.Firewall\" AND resource_properties.name =\"default-allow-http\""

특정 프로젝트에 속하는 리소스

"security_center_properties.resource_parent = \"$PROJECT_1_NAME\" OR security_center_properties.resource_parent = \"$PROJECT_2_NAME\""

$PROJECT_1_NAME$PROJECT_2_NAME//cloudresourcemanager.googleapis.com/projects/$PROJECT_ID 형식의 리소스 식별자입니다. 여기서 $PROJECT_ID는 프로젝트 번호입니다. 전체 예시는 //cloudresourcemanager.googleapis.com/projects/100090906와 같습니다.

이름에 특정 문자열이 포함된 Compute Engine 이미지 찾기

이 필터는 하위 문자열 'Debia'가 포함된 Compute Engine 이미지를 반환합니다.

"security_center_properties.resource_type = \"google.compute.Image\" AND resource_properties.name : \"Debia\""

속성에 키-값 쌍이 포함된 리소스

이 필터는 bucketPolicyOnly가 사용 중지된 Cloud Storage 버킷을 반환합니다. resourceProperties.iamConfiguration 값은 문자열로 인코딩됩니다. \ 문자를 사용하여 키 이름과 값 사이의 : 연산자를 포함한 문자열의 특수 문자를 이스케이프 처리합니다.

"resourceProperties.iamConfiguration:"\"bucketPolicyOnly\"\:{\"enabled\"\:false""

특정 시간 또는 이전에 생성된 프로젝트 애셋 찾기

이러한 예시 필터는 2019년 7월 18일 오후 8:26:21(GMT) 또는 그 이전에 생성된 애셋과 일치합니다. create_time 필터를 사용하면 다음 형식 및 유형을 사용하여 시간을 표시할 수 있습니다.

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

    "create_time <= 1563481581000"
    
  • 문자열 리터럴로서의 RFC 3339

    "create_time <= \"2019-07-18T20:26:21+00:00\""
    

검색결과에서 애셋 제외

결과에서 애셋을 제외하려면 매개변수 앞에 - 문자를 배치하여 부정을 사용합니다. 이 작업은 SQL 문에서 NOT 연산자를 사용하는 작업과 유사합니다.

이 필터는 Debia를 제외한 모든 프로젝트 리소스를 반환합니다.

"security_center_properties.resource_type = \"google.cloud.resourcemanager.Project\" AND -resource_properties.projectId = \"Debia\""

다음 단계

클라이언트 라이브러리를 사용하여 Security Command Center에 액세스 자세히 알아보기