Security Command Center API を使用したセキュリティ マークの管理

このガイドでは、Security Command Center の 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 を使用する場合、セキュリティ マークの追加と更新の操作は同じです。以下の例は、2 つの Key-Value ペア (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: アセットが配置されているリソース階層のレベル。organizationfolder、または project を使用します。
  • PARENT_ID: 親組織、フォルダ、プロジェクトの数値 ID、または親プロジェクトの英数字 ID。
  • LOCATION: データ所在地が有効になっている場合は、アセットのセキュリティ マークを更新する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。
  • SECURITY_MARKS: セキュリティ マークとその値を表すカンマ区切りの Key-Value ペア(例: 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

Security Health Analytics の検出機能専用のアセットマークについては、ポリシーの管理をご覧ください。

アセットのセキュリティ マークの削除

特定のセキュリティ マークの削除は、追加や削除と同様の方法で行うことができます。具体的には、対応する値を使用せずにフィールド マスクを使用して更新を呼び出します。以下の例では、キー key_akey_b を使用するセキュリティ マークが削除されます。

gcloud

gcloud scc assets update-marks ASSET_ID \
  --PARENT=PARENT_ID \
  --location=LOCATION \
  --update-mask=UPDATE_MASK
  • ASSET_ID: 更新するアセット。
  • PARENT: アセットが配置されているリソース階層のレベル。organizationfolder、または project を使用します。
  • PARENT_ID: 親組織、フォルダ、プロジェクトの数値 ID、または親プロジェクトの英数字 ID。
  • LOCATION: データ所在地が有効になっている場合は、アセットからセキュリティ マークを削除する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 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: アセットが配置されているリソース階層のレベル。organizationfolder、または project を使用します。
  • PARENT_ID: 親組織、フォルダ、プロジェクトの数値 ID、または親プロジェクトの英数字 ID。
  • LOCATION: データ所在地が有効になっている場合は、アセットのセキュリティ マークを更新および削除する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。
  • SECURITY_MARKS: 更新するセキュリティ マークを表すカンマ区切りの Key-Value ペア(例: 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 \
    PARENT/PARENT_ID/sources/SOURCE_ID/locations/LOCATION/findings/FINDING_NAME \
    --security-marks=SECURITY_MARKS \
    --update-mask=UPDATE_MASK

次のように置き換えます。

  • PARENT: 検出結果が存在するリソース階層のレベル。organizationsfolders、または projects を使用します。
  • PARENT_ID: 親組織、フォルダ、プロジェクトの数値 ID、または親プロジェクトの英数字 ID。
  • SOURCE_ID: ソース ID。
  • LOCATION: データ所在地が有効になっている場合は、検出結果のセキュリティ マークを更新する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。
  • FINDING_NAME: 更新する検出結果。
  • SECURITY_MARKS: セキュリティ マークとその値を表すカンマ区切りの Key-Value ペア(例: 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

セキュリティ マークは、リアルタイムにではなく、毎日 2 回実行されるバッチスキャン中に処理されます。セキュリティ マークが処理され、検出結果を解決または再オープンするポリシーが適用されるまで、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: 検出結果が存在するリソース階層のレベル。organizationsfolders、または projects を使用します。
  • PARENT_ID: 親組織、フォルダ、プロジェクトの数値 ID、または親プロジェクトの英数字 ID。
  • LOCATION: データ所在地が有効になっている場合は、検出結果を一覧表示する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 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

次のステップ