通知構成の作成と管理

このページでは、次に挙げる例など、Security Command Center API の通知機能を使用する方法について説明します。

  • NotificationConfig を作成する
  • NotificationConfig の取得
  • NotificationConfig の更新
  • NotificationConfig の削除
  • NotificationConfig の一覧表示
  • Pub/Sub 通知の受信

また、Security Command Center Premium のお客様には、Security Command Center で Pub/Sub の継続的エクスポートを設定する方法もあります。

始める前に

このページの例を使用するには、検出通知の設定のガイドを完了する必要があります。

以降の例を実行するには、適切な権限を持つ Identity and Access Management(IAM)ロールが必要です。

  • NotificationConfig の作成: セキュリティ センター通知構成編集者(roles/securitycenter.notificationConfigEditor
  • NotificationConfig の取得と一覧表示: セキュリティ センター通知構成閲覧者(roles/securitycenter.notificationConfigViewer)またはセキュリティ センター通知構成編集者(roles/securitycenter.notificationConfigEditor
  • NotificationConfig の更新と削除: セキュリティ センター通知の編集者(roles/securitycenter.notificationConfigEditor

notificationConfig にアクセスするプリンシパルに適切なロールを付与するには、次のいずれかの IAM ロールが必要です。

  • 組織管理者(roles/resourcemanager.organizationAdmin
  • フォルダ IAM 管理者(roles/resourcemanager.folderIamAdmin
  • プロジェクト IAM 管理者(roles/resourcemanager.projectIamAdmin

Security Command Center の IAM ロールは、組織レベル、フォルダレベル、またはプロジェクト レベルで付与できます。検出結果、アセット、セキュリティ ソースを表示、編集、作成、更新する権限は、アクセス権が付与されているレベルによって異なります。Security Command Center のロールの詳細については、アクセス制御をご覧ください。

データ所在地と通知

Security Command Center でデータ所在地が有効になっている場合、Pub/Sub(notificationConfig リソース)への継続的なエクスポートを定義する構成はデータの対象であり、Security Command Center のロケーションに保存されます。

Security Command Center のロケーションの検出結果を Pub/Sub にエクスポートするには、検出結果と同じ Security Command Center のロケーションに継続的なエクスポートを構成する必要があります。

継続的なエクスポートで使用されるフィルタには、所在地管理の対象となるデータが含まれる可能性があるため、作成する前に正しいロケーションを指定していることを確認してください。Security Command Center では、エクスポートを作成するロケーションは制限されません。

継続的エクスポートは作成場所にのみ保存され、他のロケーションで表示や編集はできません。

継続的なエクスポートを作成した後に、そのロケーションを変更することはできません。ロケーションを変更するには、継続的なエクスポートを削除して、新しいロケーションに再作成する必要があります。

API 呼び出しを使用して継続的なエクスポートを取得するには、notificationConfig の完全なリソース名でロケーションを指定する必要があります。次に例を示します。

GET https://securitycenter.googleapis.com/v2/organizations/123/locations/eu/notificationConfigs/my-pubsub-export-01

同様に、gcloud CLI を使用して継続的なエクスポートを取得するには、--location フラグを使用してロケーションを指定する必要があります。次に例を示します。

gcloud scc notifications describe myContinuousExport --organization=123 \
    --location=us

NotificationConfig の作成

NotificationConfig を作成するには、以下が必要です。

  • 通知の送信先にする既存の Pub/Sub トピック。
  • notificationConfig を作成するプリンシパルに必要な IAM ロール。

詳細については、検出通知の設定ガイドの Pub/Sub トピックを設定する手順をご覧ください。

NotificationConfig を作成する前に、各組織で保持できる NotificationConfig ファイルの数に上限があることを確認してください。詳細については、割り当てと上限をご覧ください。

NotificationConfig には、通知を有用なイベントに限定する filter フィールドが含まれています。このフィールドは、Security Command Center API の findings.list メソッドで使用できるすべてのフィルタを受け入れます。

NotificationConfig を作成する場合は、Google Cloud リソース階層(組織、フォルダ、プロジェクトのいずれか)から NotificationConfig の親を指定します。後で NotificationConfig を取得、更新、削除する必要がある場合は、参照時に親の組織、フォルダ、またはプロジェクトの数値 ID を指定する必要があります。

Google Cloud コンソールで、一部の NotificationConfig リソースに [Legacy] ラベルが付いている場合があります。これは、v1 Security Command Center API で作成されたことを示します。これらの NotificationConfig リソースは、Google Cloud コンソール、gcloud CLI、v1 Security Command Center API、または Security Command Center の v1 クライアント ライブラリで管理できます。

これらの NotificationConfig リソースを gcloud CLI で管理するには、gcloud CLI コマンドを実行するときにロケーションを指定しないでください。

任意の言語やプラットフォームを使用して NotificationConfig を作成するには:

gcloud

gcloud scc notifications create NOTIFICATION_NAME \
  --PARENT=PARENT_ID \
  --location=LOCATION
  --description="NOTIFICATION_DESCRIPTION" \
  --pubsub-topic=PUBSUB_TOPIC \
  --filter="FILTER"

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

  • NOTIFICATION_NAME: 通知の名前。 1 ~ 128 文字で、英数字、アンダースコア、ハイフンのみを使用できます。
  • PARENT: 通知が適用されるリソース階層内の範囲(organizationfolder、または project)。
  • PARENT_ID: 親組織、フォルダ、またはプロジェクトの ID で、organizations/123folders/456、または projects/789 の形式で指定されます。
  • LOCATION: データ所在地が有効になっている場合は、NotificationConfig を作成する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。
  • NOTIFICATION_DESCRIPTION: 通知の説明(最大 1,024 文字)。
  • PUBSUB_TOPIC: 通知を受信する Pub/Sub トピック。形式は projects/PROJECT_ID/topics/TOPIC です。
  • FILTER: Pub/Sub に送信する検出結果を選択するために定義する式。例: state=\"ACTIVE\"

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
)

func createNotificationConfig(w io.Writer, orgID string, pubsubTopic string, notificationConfigID string) error {
	// orgID := "your-org-id"
	// pubsubTopic := "projects/{your-project}/topics/{your-topic}"
	// notificationConfigID := "your-config-id"

	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)

	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close()

	req := &securitycenterpb.CreateNotificationConfigRequest{
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}/locations/global"
		//		"projects/{projectId}/locations/global"
		//		"folders/{folderId}/locations/global"
		Parent:   fmt.Sprintf("organizations/%s/locations/global", orgID),
		ConfigId: notificationConfigID,
		NotificationConfig: &securitycenterpb.NotificationConfig{
			Description: "Go sample config",
			PubsubTopic: pubsubTopic,
			NotifyConfig: &securitycenterpb.NotificationConfig_StreamingConfig_{
				StreamingConfig: &securitycenterpb.NotificationConfig_StreamingConfig{
					Filter: `state = "ACTIVE"`,
				},
			},
		},
	}

	notificationConfig, err := client.CreateNotificationConfig(ctx, req)
	if err != nil {
		return fmt.Errorf("Failed to create notification config: %w", err)
	}
	fmt.Fprintln(w, "New NotificationConfig created: ", notificationConfig)

	return nil
}

Java


package vtwo.notifications;

import com.google.cloud.securitycenter.v2.LocationName;
import com.google.cloud.securitycenter.v2.NotificationConfig;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import java.io.IOException;

public class CreateNotification {

  public static void main(String[] args) throws IOException {
    // parentId: must be in one of the following formats:
    //    "organizations/{organization_id}"
    //    "projects/{project_id}"
    //    "folders/{folder_id}"
    String parentId = "{parent-id}";
    String topicName = "{your-topic}";
    String notificationConfigId = "{your-notification-id}";
    // Specify the location of the notification config.
    String location = "global";

    createNotificationConfig(parentId, location, topicName, notificationConfigId);
  }

  // Crete a notification config.
  // Ensure the ServiceAccount has the "pubsub.topics.setIamPolicy" permission on the new topic.
  public static NotificationConfig createNotificationConfig(
      String parentId, String location, String topicName, String notificationConfigId)
      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. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources.
    try (SecurityCenterClient client = SecurityCenterClient.create()) {

      String pubsubTopic = String.format("projects/%s/topics/%s", parentId, topicName);

      NotificationConfig notificationConfig = NotificationConfig.newBuilder()
          .setDescription("Java notification config")
          .setPubsubTopic(pubsubTopic)
          .setStreamingConfig(
              NotificationConfig.StreamingConfig.newBuilder().setFilter("state = \"ACTIVE\"")
                  .build())
          .build();

      NotificationConfig response = client.createNotificationConfig(
          LocationName.of(parentId, location), notificationConfig, notificationConfigId);

      System.out.printf("Notification config was created: %s%n", response);
      return response;
    }
  }
}

Node.js

// npm install '@google-cloud/security-center'
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;
const uuidv1 = require('uuid').v1;

const client = new SecurityCenterClient();
/*
 *  Required. Resource name of the new notification config's parent. Its format
 *  is "organizations/[organization_id]/locations/[location_id]",
 *  "folders/[folder_id]/locations/[location_id]", or
 *  "projects/[project_id]/locations/[location_id]".
 */
const parent = `projects/${projectId}/locations/${location}`;

/**
 *  Required.
 *  Unique identifier provided by the client within the parent scope.
 *  It must be between 1 and 128 characters and contain alphanumeric
 *  characters, underscores, or hyphens only.
 */
const configId = 'notif-config-test-node-create-' + uuidv1();

// pubsubTopic = "projects/{your-project}/topics/{your-topic}";
const pubsubTopic = `projects/${projectId}/topics/${topicName}`;

/**
 *  Required. The notification config being created. The name and the service
 *  account will be ignored as they are both output only fields on this
 *  resource.
 */
const notificationConfig = {
  description: 'Sample config for node v2',
  pubsubTopic: pubsubTopic,
  streamingConfig: {filter: 'state = "ACTIVE"'},
};

// Build the request.
const createNotificationRequest = {
  parent: parent,
  configId: configId,
  notificationConfig: notificationConfig,
};

async function createNotificationConfig() {
  const [response] = await client.createNotificationConfig(
    createNotificationRequest
  );
  console.log('Notification configuration creation successful: %j', response);
}

await createNotificationConfig();

Python

def create_notification_config(
    parent_id, location_id, pubsub_topic, notification_config_id
) -> NotificationConfig:
    """
    This method is used to create the Notification Config.
    Args:
        parent_id: must be in one of the following formats:
            "organizations/{organization_id}"
            "projects/{project_id}"
            "folders/{folder_id}"
        location_id: "global"
        pubsub_topic: "projects/{your-project-id}/topics/{your-topic-id}"
        notification_config_id: "your-config-id"


    Ensure this ServiceAccount has the "pubsub.topics.setIamPolicy" permission on the new topic.
    """
    from google.cloud import securitycenter_v2 as securitycenter_v2

    client = securitycenter_v2.SecurityCenterClient()
    parent_id = parent_id + "/locations/" + location_id
    response = client.create_notification_config(
        request={
            "parent": parent_id,
            "config_id": notification_config_id,
            "notification_config": {
                "description": "Notification for active findings",
                "pubsub_topic": pubsub_topic,
                "streaming_config": {"filter": 'state = "ACTIVE"'},
            },
        }
    )
    print(f"create notification config response:{response}")
    return response

これで、指定した Pub/Sub トピックに通知がパブリッシュされるようになりました。

通知をパブリッシュするため、サービス アカウントが service-org-ORGANIZATION_ID@gcp-sa-scc-notification.iam.gserviceaccount.com の形式で作成されます。このサービス アカウントは、最初の NotificationConfig を作成するときに作成され、通知構成の作成時に PUBSUB_TOPIC の IAM ポリシーに対する securitycenter.notificationServiceAgent ロールが自動的に付与されます。通知が機能するには、このサービス アカウントのロールが必要です。

NotificationConfig の取得

NotificationConfig を取得するには、securitycenter.notification.get 権限を含む IAM ロールが必要です。

gcloud

gcloud scc notifications describe NOTIFICATION_NAME \
  --PARENT_TYPE=PARENT_ID \
  --location=LOCATION

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

  • NOTIFICATION_NAME: 通知構成の名前。
  • PARENT_TYPE 構成が指定されているリソース階層のレベル。organizationfolder、または project を使用します。
  • PARENT_ID: 親リソースの数値 ID。
  • LOCATION: データ所在地が有効になっている場合は、NotificationConfig を取得する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。

NotificationConfig の更新

NotificationConfig を更新するには、securitycenter.notification.update 権限を含む IAM ロールが必要です。

フィールド マスクを使用して更新する場合、指定したフィールドのみが更新されます。フィールド マスクを使用しない場合は、NotificationConfig 内のすべての変更可能なフィールドが新しい値に置き換えられます。フィールド マスクを使用することで、Pub/Sub のトピックと説明文を更新できます。

この例を完了するには、新しいトピックに登録されていることと、通知のサービス アカウントにそのトピックに対する pubsub.topics.setIamPolicy 権限が付与されている必要があります。

必要な権限を付与したら、任意の言語を使用して NotificationConfig の説明、Pub/Sub トピック、フィルタを更新します。

gcloud

gcloud scc notifications update NOTIFICATION_NAME \
  --PARENT_TYPE=PARENT_ID \
  --location=LOCATION \
  --description="NOTIFICATION_DESCRIPTION" \
  --pubsub-topic=PUBSUB_TOPIC \
  --filter="FILTER"

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

  • NOTIFICATION_NAME: 通知構成の名前。
  • PARENT_TYPE 構成が指定されているリソース階層のレベル。organizationfolder、または project を使用します。
  • PARENT_ID: 親リソースの数値 ID。
  • LOCATION: データ所在地が有効になっている場合は、NotificationConfig を更新する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。
  • NOTIFICATION_DESCRIPTION: 通知の説明(最大 1,024 文字)。
  • PUBSUB_TOPIC: 通知を受信する Pub/Sub トピック。形式は projects/PROJECT_ID/topics/TOPIC です。
  • FILTER: Pub/Sub に送信する検出結果を選択するために定義する式。例: state="ACTIVE"

NotificationConfig の削除

NotificationConfig を削除するには、securitycenter.notification.delete 権限を含む IAM ロールが必要です。

NotificationConfig を削除しても、securitycenter.notificationServiceAgent ロールは Pub/Sub トピックに残ります。他のどの NotificationConfig でもその Pub/Sub トピックを使用していない場合は、トピックからロールを削除します。詳細については、アクセス制御をご覧ください。

任意の言語を使用して、NotificationConfig を削除します。

gcloud

gcloud scc notifications delete NOTIFICATION_NAME \
  --PARENT_TYPE=PARENT_ID \
  --location=LOCATION

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

  • NOTIFICATION_NAME: 通知構成の名前。
  • PARENT_TYPE 構成が指定されているリソース階層のレベル。organizationfolder、または project を使用します。
  • PARENT_ID: 親リソースの数値 ID。
  • LOCATION: データ所在地が有効になっている場合は、NotificationConfig を削除する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。

NotificationConfig の一覧表示

NotificationConfigs を一覧表示するには、securitycenter.notification.list 権限を含む IAM ロールが必要です。

Security Command Center API のすべてのリストはページ分けされます。各レスポンスでは、結果のページと次のページを返すためのトークンが戻されます。デフォルトの pageSize は 10 です。ページサイズは最小値の 1 から最大値の 1,000 まで構成できます。

任意の言語を使用して、NotificationConfigs を一覧表示します。

gcloud

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

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

  • PARENT_TYPE 構成が指定されているリソース階層のレベル。organizationsfolders、または projects を使用します。
  • PARENT_ID: 親リソースの数値 ID。
  • LOCATION: データ所在地が有効になっている場合は、NotificationConfig リソースを一覧表示する Security Command Center のロケーション。データ所在地が有効になっていない場合は、値 global を使用します。

Pub/Sub 通知の受信

このセクションでは、サンプルの通知メッセージと、検出結果を含む NotificationMessage に Pub/Sub メッセージを変換する方法の例について説明します。

通知は JSON 形式で Pub/Sub に発行されます。次に示しているのは、通知メッセージの例です。

{
   "notificationConfigName": "organizations/ORGANIZATION_ID/notificationConfigs/CONFIG_ID",
   "finding": {
     "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID",
     "parent": "organizations/ORGANIZATION_ID/sources/SOURCE_ID",
     "state": "ACTIVE",
     "category": "TEST-CATEGORY",
     "securityMarks": {
       "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID/securityMarks"
     },
     "eventTime": "2019-07-26T07:32:37Z",
     "createTime": "2019-07-29T18:45:27.243Z"
   }
 }

任意の言語を使用して Pub/Sub メッセージを NotificationMessage に変換します。

gcloud

gcloud CLI を使用して、Pub/Sub メッセージを NotificationMessage に変換することはできません。gcloud CLI を使用して NotificationMessage を取得し、ターミナルで直接 JSON を出力できます。

  # The subscription used to receive published messages from a topic
  PUBSUB_SUBSCRIPTION="projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID"

  gcloud pubsub subscriptions pull $PUBSUB_SUBSCRIPTION

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

  • PROJECT_ID: プロジェクト ID。
  • SUBSCRIPTION_ID はサブスクリプション ID に置き換えます。

Go

import (
	"bytes"
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/pubsub"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"github.com/golang/protobuf/jsonpb"
)

func receiveMessages(w io.Writer, projectID string, subscriptionName string) error {
	// projectID := "your-project-id"
	// subsriptionName := "your-subscription-name"

	ctx := context.Background()

	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	sub := client.Subscription(subscriptionName)
	cctx, cancel := context.WithCancel(ctx)
	err = sub.Receive(cctx, func(ctx context.Context, msg *pubsub.Message) {
		var notificationMessage = new(securitycenterpb.NotificationMessage)
		jsonpb.Unmarshal(bytes.NewReader(msg.Data), notificationMessage)

		fmt.Fprintln(w, "Got finding: ", notificationMessage.GetFinding())
		msg.Ack()
		cancel()
	})
	if err != nil {
		return fmt.Errorf("Receive: %w", err)
	}

	return nil
}

次のステップ