רשימת נכסים באמצעות Security Command Center API

נכסים הם המשאבים של הארגון, כמו מכונות ב-Compute Engine או קטגוריות של Cloud Storage. Google Cloud

במדריך הזה מוסבר איך להשתמש בספריות לקוח של Security Command Center כדי לגשת לרשומות שהוצאו משימוש ושנשמרות ב-Security Command Center עבור הנכסים בפרויקט או בארגון.

‫Security Command Center שומר רשומות רק לגבי קבוצת משנה של הנכסים ב-מאגר משאבי ענן. כדי לקבל את הרשימה המלאה ביותר של הנכסים בסביבה שלכם, צריך להשתמש במאגר משאבי הענן כדי לרשום את הנכסים.

למידע נוסף, קראו את המאמרים הבאים:

רמות הרשאה לתפקידי IAM

אפשר להעניק את תפקידי ה-IAM של Security Command Center ברמת הארגון, התיקייה או הפרויקט. היכולת שלכם להציג, לערוך, ליצור או לעדכן ממצאים, נכסים ומקורות אבטחה תלויה ברמת הגישה שניתנה לכם. מידע נוסף על תפקידים ב-Security Command Center זמין במאמר בקרת גישה.

לפני שמתחילים

לפני שמגדירים מקור, צריך לבצע את הפעולות הבאות:

גודל דף

כל ממשקי ה-API של רשימות ב-Security Command Center מחולקים לדפים. כל תגובה מחזירה דף של תוצאות ואסימון להחזרת הדף הבא. אפשר להגדיר את גודל הדף. ערך ברירת המחדל של pageSize הוא 10, אפשר להגדיר אותו למינימום של 1 ולמקסימום של 1, 000.

סוגי המשאבים

המאפיין resourceType ב-Security Command Center פועל לפי מוסכמת מתן שמות שונה מזו של מאגר משאבי ענן. רשימה של פורמטים של סוגי משאבים זמינה במאמר סוגי נכסים נתמכים ב-Security Command Center.

הצגת רשימה של כל הנכסים

בדוגמאות האלה אפשר לראות איך מפרטים את כל הנכסים:

gcloud

כדי להציג את כל הנכסים בפרויקט, בתיקייה או בארגון, מריצים את הפקודה הבאה:

gcloud scc assets list PARENT_ID

מחליפים את PARENT_ID באחד מהערכים הבאים:

  • מזהה הארגון בפורמט הבא: ORGANIZATION_ID (המזהה המספרי בלבד)
  • מזהה תיקייה בפורמט הבא: folders/FOLDER_ID
  • מזהה פרויקט בפורמט הבא: projects/PROJECT_ID

כדי לראות עוד דוגמאות, מריצים את הפקודה:

 gcloud scc assets list --help

דוגמאות לתיעוד מופיעות במאמר gcloud scc assets list.

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)

Java

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 אפשר להשתמש במסנני נכסים כדי לקבל מידע על נכסים ספציפיים. מסננים דומים לסעיפי WHERE בהצהרות SQL, אבל במקום עמודות, הם חלים על האובייקטים שמוחזרים על ידי ה-API.

בדוגמה של הפלט למעלה מוצגים כמה שדות ותתי-שדות, והמאפיינים שלהם, שאפשר להשתמש בהם במסנני נכסים. ‫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 (המזהה המספרי בלבד)
    • מזהה תיקייה בפורמט הבא: folders/FOLDER_ID
    • מזהה פרויקט בפורמט הבא: projects/PROJECT_ID

כדי לראות עוד דוגמאות, מריצים את הפקודה:

gcloud scc assets list --help

דוגמאות לתיעוד מופיעות במאמר gcloud scc assets list.

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)

Java

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 (המזהה המספרי בלבד)
    • מזהה פרויקט בפורמט הבא: projects/PROJECT_ID
    • מזהה תיקייה בפורמט הבא: folders/FOLDER_ID

כדי לראות עוד דוגמאות, מריצים את הפקודה:

gcloud scc assets list --help

דוגמאות לתיעוד מופיעות במאמר gcloud scc assets list.

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)

Java

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: הנכס היה קיים גם בתחילת התקופה וגם בסופה, כפי שהוגדר על ידי compareDuration ו-readTime.

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 (המזהה המספרי בלבד)
    • מזהה פרויקט בפורמט הבא: projects/PROJECT_ID
    • מזהה תיקייה בפורמט הבא: folders/FOLDER_ID
  • READ_TIME עם השעה שבה הנכסים יופיעו. משתמשים בפורמט הבא: YYYY-MM-DDThh:mm:ss.ffffffZ. לדוגמה:
    --read-time="2022-12-21T07:00:06.861Z"
    כדי לראות עוד דוגמאות, מריצים את הפקודה:
gcloud scc assets list --help

דוגמאות לתיעוד מופיעות במאמר gcloud scc assets list.

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)

Java

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();

דוגמאות למסננים

הנה עוד כמה מסננים שימושיים של נכסים. אפשר להשתמש ב-AND וב-OR במסננים כדי לשלב פרמטרים ולהרחיב או לצמצם את התוצאות.

חיפוש נכס של פרויקט עם בעלים ספציפי

"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 שהשמות שלהן מכילים מחרוזת מסוימת

המסנן הזה מחזיר תמונות של Compute Engine שמכילות את מחרוזת המשנה Debia:

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

משאבים שהמאפיינים שלהם מכילים צמדי מפתח/ערך

המסנן הזה מחזיר קטגוריות של Cloud Storage שבהן האפשרות bucketPolicyOnly מושבתת. הערך של resourceProperties.iamConfiguration מקודד כמחרוזת. משתמשים בתו \ כדי לסמן בתו בריחה (escape) תווים מיוחדים במחרוזות, כולל האופרטור : בין שם המפתח לערך.

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

חיפוש נכסי פרויקט שנוצרו בשעה מסוימת או לפני כן

מסנני הדוגמה האלה תואמים לנכסים שנוצרו בתאריך 18 ביולי 2019 או לפניו בשעה 20:26:21 GMT. בעזרת המסנן create_time, אפשר לציין זמן בפורמטים ובסוגים הבאים:

  • זמן יוניקס (באלפיות השנייה) כמספר שלם

    "create_time <= 1563481581000"
    
  • RFC 3339 כמחרוזת ליטרלית

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

אי הכללת נכסים בתוצאות

כדי להחריג נכס מהתוצאות, משתמשים בשלילה על ידי הצבת התו - לפני פרמטר. הפעולה דומה לשימוש באופרטור NOT בהצהרת SQL.

המסנן הזה מחזיר את כל משאבי הפרויקט מלבד Debia:

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

המאמרים הבאים

מידע נוסף על גישה ל-Security Command Center באמצעות ספריית לקוח