使用 Security Command Center API 管理安全標記

本指南說明如何使用 Security Command Center API 管理安全標記。安全標記 (或稱「標記」) 是 Security Command Center 中資產或發現結果的可自訂註解,可讓您為這些物件新增自己的業務背景資訊。

您只能在 Security Command Center 支援的資產上新增或更新安全標記。如需 Security Command Center 支援的資產清單,請參閱「Security Command Center 支援的資產類型」。

事前準備

您必須先設定服務帳戶和 SDK,才能使用安全標記。

如要新增或變更安全性標記,您必須具備包含權限的 Identity and Access Management 角色,才能使用所需類型的標記:

  • 資產標記:資產安全標記寫入者securitycenter.assetSecurityMarksWriter
  • 發現項目標記:發現項目安全標記寫入者securitycenter.findingSecurityMarksWriter

如要進一步瞭解 Security Command Center 中的 IAM 角色,請參閱存取權控管。如要瞭解如何有效使用安全標記,請參閱「使用 Security Command Center 安全標記」。

在資產上新增或更新安全標記

使用 Security Command Center API 時,新增和更新安全性標記是相同的作業。以下範例說明如何為鍵/值組合 (key_a, value_a)(key_b, value_b) 新增安全標記。

下列程式碼會使用欄位遮罩,確保只更新這些值。如果未提供欄位遮罩,系統會先清除所有安全標記,再新增指定的鍵和值。

gcloud

gcloud scc assets update-marks ASSET_ID \
    --PARENT=PARENT_ID \
    --location=LOCATION \
    --security-marks=SECURITY_MARKS \
    --update-mask=UPDATE_MASK

更改下列內容:

  • ASSET_ID:要更新的資產。
  • PARENT:資產所在的資源階層層級;請使用 organizationfolderproject
  • PARENT_ID:父項機構、資料夾或專案的數值 ID,或是父項專案的英數 ID。
  • LOCATION:要更新資產安全標記的 Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus,否則請使用值 global
  • SECURITY_MARKS:以半形逗號分隔的鍵/值組合,代表安全標記及其值,例如 key_a=value_a,key_b=value_b
  • UPDATE_MASK:以半形逗號分隔的安全性標記欄位清單,用於更新資產;例如 marks.key_a,marks.key_b

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"google.golang.org/genproto/protobuf/field_mask"
)

// addSecurityMarks adds/updates the security marks for the assetName.
// Specifically, it sets "key_a" and "key_b" to "value_a" and "value_b"
// respectively.  assetName is the resource path for an asset.
func addSecurityMarks(w io.Writer, assetName string) error {
	// Specify the value of 'assetName' in one of the following formats:
	// 		assetName := "organizations/{org_id}/locations/{location_id}/assets/{asset_id}"
	//		assetName := "projects/{project_id}/locations/{location_id}/assets/{asset_id}"
	//		assetName := "folders/{folder_id}/locations/{location_id}/assets/{asset_id}"
	// 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.UpdateSecurityMarksRequest{
		// If not set or empty, all marks would be cleared before
		// adding the new marks below.
		UpdateMask: &field_mask.FieldMask{
			Paths: []string{"marks.key_a", "marks.key_b"},
		},
		SecurityMarks: &securitycenterpb.SecurityMarks{
			Name: fmt.Sprintf("%s/securityMarks", assetName),
			// Note keys correspond to the last part of each path.
			Marks: map[string]string{"key_a": "value_a", "key_b": "value_b"},
		},
	}
	updatedMarks, err := client.UpdateSecurityMarks(ctx, req)
	if err != nil {
		return fmt.Errorf("UpdateSecurityMarks: %w", err)
	}

	fmt.Fprintf(w, "Updated marks: %s\n", updatedMarks.Name)
	for k, v := range updatedMarks.Marks {
		fmt.Fprintf(w, "%s = %s\n", k, v)
	}
	return nil

}

Python

def add_to_finding(organization_id, source_name, location_id, finding_name):
    """
    Adds security marks to a finding.
    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'
       finding_name: finding name to add security marks.

    Returns:
        Dict: returns the deleted security marks response.
    """
    from google.cloud import securitycenter_v2
    from google.protobuf import field_mask_pb2

    client = securitycenter_v2.SecurityCenterClient()
    finding_name = f"organizations/{organization_id}/sources/{source_name}/locations/{location_id}/findings/{finding_name}"
    finding_marks_name = f"{finding_name}/securityMarks"

    # Notice the suffix after "marks." in the field mask matches the keys
    # in marks.
    field_mask = field_mask_pb2.FieldMask(
        paths=["marks.finding_key_a", "marks.finding_key_b"]
    )
    marks = {"finding_key_a": "value_a", "finding_key_b": "value_b"}

    updated_marks = client.update_security_marks(
        request={
            "security_marks": {"name": finding_marks_name, "marks": marks},
            "update_mask": field_mask,
        }
    )
    return updated_marks, marks

如要瞭解安全狀態分析偵測器的專屬資產標記,請參閱「管理政策」。

刪除資產的安全標記

刪除特定安全標記的方式與新增或更新標記類似,具體來說,就是呼叫 update,並使用欄位遮罩,但不提供任何對應值。在這個範例中,系統會刪除含有 key_akey_b 鍵的安全標記。

gcloud

gcloud scc assets update-marks ASSET_ID \
  --PARENT=PARENT_ID \
  --location=LOCATION \
  --update-mask=UPDATE_MASK
  • ASSET_ID:要更新的資產。
  • PARENT:資產所在的資源階層層級;請使用 organizationfolderproject
  • PARENT_ID:父項機構、資料夾或專案的數值 ID,或是父項專案的英數 ID。
  • LOCATION: 要從資產中刪除安全標記的 Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus;否則請使用 global 值。
  • UPDATE_MASK:以半形逗號分隔的清單,列出要從資產中刪除的安全標記欄位,例如 marks.key_a,marks.key_b

Node.js

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

// Creates a new client.
const client = new SecurityCenterClient();

// Build the full resource path for the finding to update.
/*
 * TODO(developer): Update the following references for your own environment before running the sample.
 */
// const organizationId = 'YOUR_ORGANIZATION_ID';
// const sourceId = 'SOURCE_ID';
// const location = 'LOCATION_ID';
const findingName = `organizations/${organizationId}/sources/${sourceId}/locations/${location}/findings/${findingId}`;

// Construct the request to be sent by the client.
const updateSecurityMarksRequest = {
  securityMarks: {
    name: `${findingName}/securityMarks`,
    // Intentionally, not setting marks to delete them.
  },
  // Only delete marks for the following keys.
  updateMask: {paths: ['marks.key_a', 'marks.key_b']},
};

async function deleteSecurityMarks() {
  const [newMarks] = await client.updateSecurityMarks(
    updateSecurityMarksRequest
  );

  console.log('Updated marks: %j', newMarks);
}
deleteSecurityMarks();

Python

def delete_security_marks(organization_id, asset_name) -> Dict:
    """
    Removes security marks from an asset.
    Args:
       organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
       asset_name: is the resource path for an asset that exists in SCC

    Returns:
        Dict: returns the deleted security marks response.
    """
    # Make sure they are there first
    add_to_asset(organization_id, asset_name)
    from google.cloud import securitycenter_v2
    from google.protobuf import field_mask_pb2

    # Create a new client.
    client = securitycenter_v2.SecurityCenterClient()
    asset_name = f"organizations/{organization_id}/assets/{asset_name}"
    marks_name = f"{asset_name}/securityMarks"

    field_mask = field_mask_pb2.FieldMask(paths=["marks.key_a", "marks.key_b"])

    updated_marks = client.update_security_marks(
        request={
            "security_marks": {
                "name": marks_name
                # Note, no marks specified, so the specified values in
                # the fields masks will be deleted.
            },
            "update_mask": field_mask,
        }
    )
    print(updated_marks)
    return updated_marks

在同一個要求中新增及刪除安全標記

您可以在同一個要求中,同時新增、更新及刪除安全標記。在這個範例中,key_a 會更新,而 key_b 則會刪除。

gcloud

gcloud scc assets update-marks ASSET_ID \
    --PARENT=PARENT_ID \
    --location=LOCATION \
    --update-mask=UPDATE_MASK
  • ASSET_ID:要更新的資產。
  • PARENT:資產所在的資源階層層級;請使用 organizationfolderproject
  • PARENT_ID:父項機構、資料夾或專案的數值 ID,或是父項專案的英數 ID。
  • LOCATION: 要更新及刪除資產安全標記的Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus;否則請使用 global 值。
  • SECURITY_MARKS:以半形逗號分隔的鍵/值配對,代表要更新的安全標記,例如 key_a=value_a;如要刪除安全標記,請省略該標記
  • UPDATE_MASK:以半形逗號分隔的清單,列出要更新或刪除的安全標記欄位,例如 marks.key_a,marks.key_b

Node.js

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

// Creates a new client.
const client = new SecurityCenterClient();

// Build the full resource path for the finding to update.
/*
 * TODO(developer): Update the following references for your own environment before running the sample.
 */
// const organizationId = 'YOUR_ORGANIZATION_ID';
// const sourceId = 'SOURCE_ID';
const findingName = `organizations/${organizationId}/sources/${sourceId}/locations/${location}/findings/${findingId}`;

// Construct the request to be sent by the client.
const updateSecurityMarksRequest = {
  securityMarks: {
    name: `${findingName}/securityMarks`,
    marks: {key_a: 'new_value_for_a'},
  },
  // Set the update mask to specify which properties should be updated.
  // If empty, all mutable fields will be updated.
  // For more info on constructing field mask path, see the proto or:
  // https://cloud.google.com/java/docs/reference/protobuf/latest/com.google.protobuf.FieldMask.
  // Since no marks have been added, including "marks.key_b" in the update mask
  // will cause it to be deleted.
  updateMask: {paths: ['marks.key_a', 'marks.key_b']},
};

async function UpdateAndDeleteSecurityMarks() {
  const [newMarks] = await client.updateSecurityMarks(
    updateSecurityMarksRequest
  );

  console.log('New marks: %j', newMarks);
}
UpdateAndDeleteSecurityMarks();

Python

def delete_and_update_marks(organization_id, asset_name) -> Dict:
    """
    Updates and deletes security marks from an asset in the same call.
    Args:
       organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
       asset_name: is the resource path for an asset that exists in SCC

    Returns:
        Dict: returns the deleted security marks response.

    """
    # Make sure they are there first
    add_to_asset(organization_id, asset_name)
    from google.cloud import securitycenter_v2
    from google.protobuf import field_mask_pb2

    client = securitycenter_v2.SecurityCenterClient()
    asset_name = f"organizations/{organization_id}/assets/{asset_name}"
    marks_name = f"{asset_name}/securityMarks"

    field_mask = field_mask_pb2.FieldMask(paths=["marks.key_a", "marks.key_b"])
    marks = {"key_a": "new_value_for_a"}

    updated_marks = client.update_security_marks(
        request={
            "security_marks": {"name": marks_name, "marks": marks},
            "update_mask": field_mask,
        }
    )
    print(updated_marks)
    return updated_marks

為發現項目新增安全標記

新增、更新及刪除發現項目的安全標記,與更新資產安全標記的程序相同。唯一的變更是 API 呼叫中使用的資源名稱。您提供的是發現項目資源名稱,而非資產資源。

舉例來說,如要更新發現項目的安全標記,請使用下列程式碼:

gcloud

gcloud scc findings update-marks FINDING_NAME \
    --PARENT=PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --security-marks=SECURITY_MARKS \
    --update-mask=UPDATE_MASK

更改下列內容:

  • FINDING_NAME:要更新的發現項目。
  • PARENT:發現項目所在的資源階層層級;請使用 organizationfolderproject
  • PARENT_ID:父項機構、資料夾或專案的數值 ID,或是父項專案的英數 ID。
  • LOCATION: 要更新發現項目安全標記的 Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus;否則請使用 global 值。
  • SOURCE_ID:來源 ID。
  • SECURITY_MARKS:以半形逗號分隔的鍵/值組合,代表安全標記及其值,例如 key_a=value_a,key_b=value_b
  • UPDATE_MASK:以半形逗號分隔的安全性標記欄位清單,用於更新資產;例如 marks.key_a,marks.key_b

Java


import autovalue.shaded.com.google.common.collect.ImmutableMap;
import com.google.cloud.securitycenter.v2.FindingName;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import com.google.cloud.securitycenter.v2.SecurityMarks;
import com.google.cloud.securitycenter.v2.UpdateSecurityMarksRequest;
import com.google.protobuf.FieldMask;
import java.io.IOException;

public class AddMarkToFinding {

  public static void main(String[] args) throws IOException {
    // TODO: Replace the sample resource name
    // organizationId: Google Cloud Organization id.
    String organizationId = "{google-cloud-organization-id}";

    // Specify the source-id.
    String sourceId = "{source-id}";

    // Specify the finding-id.
    String findingId = "{finding-id}";

    // Specify the location.
    String location = "global";

    addMarksToFinding(organizationId, sourceId, location, findingId);
  }

  // Demonstrates adding security marks to findings.
  // To add or change security marks, you must have an IAM role that includes permission:
  // Finding marks: Finding Security Marks Writer, securitycenter.findingSecurityMarksWriter
  public static SecurityMarks addMarksToFinding(String organizationId, String sourceId,
      String location, String findingId) 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.
    SecurityCenterClient client = SecurityCenterClient.create();

    // Start setting up a request to add security marks for a finding.
    ImmutableMap markMap = ImmutableMap.of("key_a", "value_a", "key_b", "value_b");

    // Instead of using the FindingName, a plain String can also be used. E.g.:
    // String findingName = String.format("organizations/%s/sources/%s/locations/%s/findings/%s",
    // organizationId, sourceId, location, findingId);
    FindingName findingName = FindingName
        .ofOrganizationSourceLocationFindingName(organizationId, sourceId, location, findingId);

    // Add security marks and field mask for security marks.
    SecurityMarks securityMarks = SecurityMarks.newBuilder()
        .setName(findingName + "/securityMarks")
        .putAllMarks(markMap)
        .build();

    // Set the update mask to specify which properties should be updated.
    // If empty, all mutable fields will be updated.
    // For more info on constructing field mask path, see the proto or:
    // https://cloud.google.com/java/docs/reference/protobuf/latest/com.google.protobuf.FieldMask
    FieldMask updateMask = FieldMask.newBuilder()
        .addPaths("marks.key_a")
        .addPaths("marks.key_b")
        .build();

    UpdateSecurityMarksRequest request = UpdateSecurityMarksRequest.newBuilder()
        .setSecurityMarks(securityMarks)
        .setUpdateMask(updateMask)
        .build();

    // Call the API.
    SecurityMarks response = client.updateSecurityMarks(request);

    System.out.println("Security Marks:" + response);
    return response;
  }
}

Node.js

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

// Creates a new client.
const client = new SecurityCenterClient();

// Build the full resource path for the finding to update.
/*
 * TODO(developer): Update the following references for your own environment before running the sample.
 */
// const organizationId = 'YOUR_ORGANIZATION_ID';
// const sourceId = 'SOURCE_ID';
const findingName = `organizations/${organizationId}/sources/${sourceId}/locations/${location}/findings/${findingId}`;

// Construct the request to be sent by the client.
const updateSecurityMarksRequest = {
  securityMarks: {
    name: `${findingName}/securityMarks`,
    marks: {key_a: 'value_a', key_b: 'value_b'},
  },
  // Only update the marks with these keys.
  updateMask: {paths: ['marks.key_a', 'marks.key_b']},
};

async function addFindingSecurityMarks() {
  const [newMarks] = await client.updateSecurityMarks(
    updateSecurityMarksRequest
  );

  console.log('New marks: %j', newMarks);
}
addFindingSecurityMarks();

Python

def add_to_finding(organization_id, source_name, location_id, finding_name):
    """
    Adds security marks to a finding.
    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'
       finding_name: finding name to add security marks.

    Returns:
        Dict: returns the deleted security marks response.
    """
    from google.cloud import securitycenter_v2
    from google.protobuf import field_mask_pb2

    client = securitycenter_v2.SecurityCenterClient()
    finding_name = f"organizations/{organization_id}/sources/{source_name}/locations/{location_id}/findings/{finding_name}"
    finding_marks_name = f"{finding_name}/securityMarks"

    # Notice the suffix after "marks." in the field mask matches the keys
    # in marks.
    field_mask = field_mask_pb2.FieldMask(
        paths=["marks.finding_key_a", "marks.finding_key_b"]
    )
    marks = {"finding_key_a": "value_a", "finding_key_b": "value_b"}

    updated_marks = client.update_security_marks(
        request={
            "security_marks": {"name": finding_marks_name, "marks": marks},
            "update_mask": field_mask,
        }
    )
    return updated_marks, marks

安全標記是在批次掃描期間處理,批次掃描每天執行兩次,而非即時處理。系統可能需要 12 到 24 小時,才會處理安全性標記,並套用解決或重新開啟調查結果的強制執行政策。

列出含有安全標記篩選器的資產

在資產上設定安全標記後,即可在 ListAssets API 呼叫的篩選器引數中使用這些標記。舉例來說,如要查詢 key_a = value_a 的所有資產,請使用下列程式碼:

gcloud

  # ORGANIZATION=12344321
  FILTER="security_marks.marks.key_a = \"value_a\""

  gcloud scc assets list $ORGANIZATION \
      --filter="$FILTER"

Go

import (
	"context"
	"fmt"
	"io"

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

// listAssetsWithMarks prints assets that have a mark of key_a equal to value_a
// to w for orgID.  orgID is the numeric Organization ID.
func listAssetsWithMarks(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_marks.marks.key_a = "value_a"`,
	}

	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)
	}
	return nil
}

Java

static ImmutableList<ListAssetsResult> listAssetsWithQueryMarks(
    OrganizationName organizationName) {
  try (SecurityCenterClient client = SecurityCenterClient.create()) {
    // Start setting up a request to list all assets filtered by a specific security mark.
    // 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 request =
        ListAssetsRequest.newBuilder()
            .setParent(organizationName.toString())
            .setFilter("security_marks.marks.key_a = \"value_a\"")
            .build();

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

    // 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 batches by returning
    // the Iterable returned response.iterateAll() directly.
    ImmutableList<ListAssetsResult> results = ImmutableList.copyOf(response.iterateAll());
    System.out.println("Assets with security mark - key_a=value_a:");
    System.out.println(results);
    return results;
  } catch (IOException e) {
    throw new RuntimeException("Couldn't create client.", e);
  }
}

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 listAssetsWithSecurityMarks() {
  const [response] = await client.listAssets({
    parent: parent,
    filter: 'security_marks.marks.key_a="value_a"',
  });
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.asset.name} ${
        result.asset.securityCenterProperties.resourceName
      }`
    )
  );
}

listAssetsWithSecurityMarks();

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

marks_filter = 'security_marks.marks.key_a = "value_a"'
# Call the API and print results.
asset_iterator = client.list_assets(
    request={"parent": parent, "filter": marks_filter}
)
for i, asset_result in enumerate(asset_iterator):
    print(i, asset_result)

列出含有安全標記篩選器的發現項目

在發現項目上設定安全性標記後,即可在 ListFindings API 呼叫的篩選器引數中使用這些標記。舉例來說,如要查詢 key_a != value_a 的所有資產,請使用下列程式碼:

gcloud

gcloud scc findings list PARENT/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter=FILTER
  • PARENT:發現項目所在的資源階層層級;請使用 organizationsfoldersprojects
  • PARENT_ID:父項機構、資料夾或專案的數值 ID,或是父項專案的英數 ID。
  • LOCATION:要列出調查結果的Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus;否則請使用 global 值。
  • SOURCE_ID:來源 ID。
  • FILTER:要套用至發現項目的篩選器;舉例來說,如要排除含有安全標記 key_a=value_a 的發現項目,請使用 "NOT security_marks.marks.key_a=\"value_a\""

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"google.golang.org/api/iterator"
)

// listFindingsWithMarks prints findings that don't have a security mark
// key_a equal to value_a to w.  sourceName is the full resource name
// of the source to search for findings under.
func listFindingsWithMarks(w io.Writer, sourceName string) error {
	// sourceName := "{parent}/sources/{sourceId}"
	// 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: `NOT security_marks.marks.key_a="value_a"`,
	}
	it := client.ListFindings(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("it.Next: %w", err)
		}
		finding := result.Finding
		fmt.Fprintf(w, "Finding Name: %s, ", finding.Name)
		fmt.Fprintf(w, "Resource Name %s, ", finding.ResourceName)
		fmt.Fprintf(w, "Category: %s\n", finding.Category)
	}
	return nil
}

Java


import com.google.cloud.securitycenter.v2.Finding;
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;
import java.util.ArrayList;
import java.util.List;

public class ListFindingMarksWithFilter {

  public static void main(String[] args) throws IOException {
    // TODO: Replace the sample resource name
    // organizationId: Google Cloud Organization id.
    String organizationId = "{google-cloud-organization-id}";

    // Specify the source-id.
    String sourceId = "{source-id}";

    // Specify the location.
    String location = "global";

    listFindingsWithQueryMarks(organizationId, sourceId, location);
  }

  // Demonstrates how to filter and list findings by security mark.
  public static List<Finding> listFindingsWithQueryMarks(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.
    SecurityCenterClient client = SecurityCenterClient.create();

    // Start setting up a request to list all findings filtered by a specific security mark.
    // 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);

    // Lists findings where the 'security_marks.marks.key_a' field does not equal 'value_a'.
    String filter = "NOT security_marks.marks.key_a=\"value_a\"";

    ListFindingsRequest request = ListFindingsRequest.newBuilder()
        .setParent(parent)
        .setFilter(filter)
        .build();

    // Call the API.
    List<Finding> listFindings = new ArrayList<>();
    Iterable<ListFindingsResult> resultList = client.listFindings(request).iterateAll();
    resultList.forEach(result -> listFindings.add(result.getFinding()));

    for (Finding finding : listFindings) {
      System.out.println("List findings: " + finding);
    }
    return listFindings;
  }
}

Node.js

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

// Creates a new client.
const client = new SecurityCenterClient();
//  Build the full resource path for the source to search for findings.

// The source path supports mutliple formats:
// - `${parent}/sources/${sourceId}` without a location
// - `${parent}/sources/${sourceId}/locations/${location}` with a location
// where parent must be in one of the following formats:
// - `organizations/${organization_id}`
// - `folders/${folder_id}`
// - `projects/${project_id}`

/*
 * TODO(developer): Update the following references for your own environment before running the sample.
 */
// const organizationId = 'YOUR_ORGANIZATION_ID';
// const sourceId = 'SOURCE_ID';

const sourceName = `organizations/${organizationId}/sources/${sourceId}`;

// Construct the request to be sent by the client.
const listFindingsRequest = {
  // List findings across all sources.
  parent: sourceName,
  filter: 'NOT security_marks.marks.key_a="value_a"',
};

async function listFindingsWithSecurityMarks() {
  const [response] = await client.listFindings(listFindingsRequest);
  let count = 0;
  Array.from(response).forEach(result =>
    console.log(
      `${++count} ${result.finding.name} ${result.finding.resourceName}`
    )
  );
}
listFindingsWithSecurityMarks();

Python

def list_findings_with_security_marks(organization_id, source_name, location_id) -> int:
    """
    lists all filtered findings with security marks across an organization.
    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 filtered findings with security marks across the organization.
    """
    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}"
    # below filter is used to list active and unmuted findings without security marks acknowledgement as true.
    finding_result_iterator = client.list_findings(
        request={
            "parent": all_sources,
            "filter": 'NOT security_marks.marks.ACK="true" AND NOT mute="MUTED" AND state="ACTIVE"',
        }
    )
    # 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

後續步驟