啟用 Pub/Sub 發現項目通知

本頁面說明如何使用 Security Command Center API,為 Pub/Sub 啟用發現項目通知。

您可以設定通知,自動將新發現項目和發現項目更新內容近乎即時地傳送至 Pub/Sub 主題。您可以使用這些通知觸發自動化動作,例如叫用 Cloud Run 函式進行回應、擴充或補救。如需範例解決方案,請參閱 Security Command Center 的 Cloud Run 函式程式碼開放原始碼存放區。

如要使用 Google Cloud 控制台簡化設定程序,而非使用 API,請參閱「持續匯出」。持續匯出作業與 API 通知提供相同的功能。

或者,您也可以將發現項目匯出至 BigQuery 進行分析。

事前準備

啟用尋找通知功能前,您必須取得特定的 Identity and Access Management (IAM) 角色和權限、啟用 Security Command Center API,並熟悉資料落地限制。

必要的角色

如要取得設定及配置 Security Command Center API 通知所需的權限,請要求管理員授予您下列 IAM 角色:

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

啟用 Security Command Center API

啟用 Security Command Center API:

啟用 API 時所需的角色

您必須具備 serviceusage.services.enable 權限,才能啟用 API。如果您建立了專案,可能已透過「擁有者」角色 (roles/owner) 取得這項權限。否則,您可以透過「服務使用情形管理員」角色 (roles/serviceusage.serviceUsageAdmin) 取得這項權限。瞭解如何授予角色

gcloud services enable securitycenter.googleapis.com

資料落地與通知

如果 Security Command Center 已啟用資料落地控管機制,定義持續匯出至 Pub/Sub 的設定 (notificationConfig 資源) 會受到資料落地控管機制限制,並儲存在Security Command Center 位置

如要將 Security Command Center 位置中的發現項目匯出至 Pub/Sub,您必須在與發現項目相同的 Security Command Center 位置中,設定持續匯出功能。

由於持續匯出功能使用的篩選器可能包含受落地控管機制約束的資料,因此請務必先指定正確位置,再建立篩選器。Security Command Center 不會限制您建立匯出作業的位置。

持續匯出作業只會儲存在建立時使用的位置,無法在其他位置查看或編輯。

建立連續匯出作業後,您就無法變更位置。如要變更位置,請刪除持續匯出作業,然後在新位置重新建立。

如要瞭解啟用資料落地設定後如何使用 Security Command Center,請參閱「Security Command Center 區域端點」。

設定 Pub/Sub 主題。

在這項工作中,您要建立並訂閱要傳送通知的 Pub/Sub 主題。

步驟 1:設定 Pub/Sub

如要設定及訂閱 Pub/Sub 主題,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台。

    前往 Google Cloud 控制台

  2. 選取您啟用 Security Command Center API 的專案。

  3. 按一下「啟用 Cloud Shell」

  4. 選用:如要建立新的 Pub/Sub 主題,請執行下列指令:

    gcloud pubsub topics create TOPIC_ID
    

    TOPIC_ID 替換為主題名稱。

  5. 為主題建立訂閱:

    gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID
    

    更改下列內容:

    • SUBSCRIPTION_ID:訂閱 ID
    • TOPIC_ID:主題 ID

如要進一步瞭解如何設定 Pub/Sub,請參閱「管理主題和訂閱項目」。

步驟 2:授予 Pub/Sub 主題的角色

如要建立 NotificationConfig,您必須在已建立訂閱項目的 Pub/Sub 主題上,擁有 Pub/Sub 管理員角色 (roles/pubsub.admin)。

請按照下列步驟操作來授予這個角色:

  1. 前往 Google Cloud 控制台。

    前往 Google Cloud 控制台

  2. 選取您已啟用 Security Command Center API 的專案。

  3. 按一下「啟用 Cloud Shell」

  4. 在 Pub/Sub 主題上,將必要角色授予您的 Google 帳戶:

    gcloud pubsub topics add-iam-policy-binding \
        projects/PUBSUB_PROJECT/topics/TOPIC_ID \
        --member="user:GOOGLE_ACCOUNT" \
        --role="roles/pubsub.admin"
    

    更改下列內容:

    • PUBSUB_PROJECT:包含 Pub/Sub 主題的專案 Google Cloud
    • TOPIC_ID:主題 ID
    • GOOGLE_ACCOUNT:Google 帳戶的電子郵件地址

建立 NotificationConfig

建立NotificationConfig前,請注意每個機構的NotificationConfig檔案數量有限。詳情請參閱「配額與限制」。

NotificationConfig 包含 filter 欄位,可將通知限制為實用事件。這個欄位接受 Security Command Center API findings.list 方法中提供的所有篩選器。

建立 NotificationConfig 時,您會從 Google Cloud 資源階層指定 NotificationConfig 的上層,可以是組織、資料夾或專案。如要稍後擷取、更新或刪除 NotificationConfig,請在參照時一併提供父項機構、資料夾或專案的數值 ID。

如要使用所選語言或平台建立 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:通知適用的資源階層範圍,即 organizationfolderproject
  • PARENT_ID:父項機構、資料夾或專案的 ID,格式為 organizations/123folders/456projects/789
  • LOCATION: 設定及設定 Security Command Center API 通知的Security Command Center 位置;如果已啟用資料落地功能,請使用 eusaus;否則請使用 global 值。
  • NOTIFICATION_DESCRIPTION:通知說明,最多 1,024 個字元。
  • PUBSUB_TOPIC:接收通知的 Pub/Sub 主題。格式為 projects/PROJECT_ID/topics/TOPIC
  • FILTER:您定義的運算式,用於選取要傳送至 Pub/Sub 的調查結果。例如:state=\"ACTIVE\"

Terraform

為機構建立 NotificationConfig

resource "google_pubsub_topic" "scc_v2_organization_notification_config" {
  name = "my-topic"
}

resource "google_scc_v2_organization_notification_config" "custom_organization_notification_config" {
  config_id    = "my-config"
  organization = "123456789"
  location     = "global"
  description  = "My custom Cloud Security Command Center Finding Organization Notification Configuration"
  pubsub_topic = google_pubsub_topic.scc_v2_organization_notification_config.id

  streaming_config {
    filter = "category = \"OPEN_FIREWALL\" AND state = \"ACTIVE\""
  }
}

為資料夾建立 NotificationConfig

resource "google_folder" "folder" {
  parent       = "organizations/123456789"
  display_name = "folder-name"
}

resource "google_pubsub_topic" "scc_v2_folder_notification_config" {
  name = "my-topic"
}

resource "google_scc_v2_folder_notification_config" "custom_notification_config" {
  config_id    = "my-config"
  folder       = google_folder.folder.folder_id
  location     = "global"
  description  = "My custom Cloud Security Command Center Finding Notification Configuration"
  pubsub_topic =  google_pubsub_topic.scc_v2_folder_notification_config.id

  streaming_config {
    filter = "category = \"OPEN_FIREWALL\" AND state = \"ACTIVE\""
  }
}

為專案建立 NotificationConfig

resource "google_pubsub_topic" "scc_v2_project_notification" {
  name = "my-topic"
}

resource "google_scc_v2_project_notification_config" "custom_notification_config" {
  config_id    = "my-config"
  project      = "my-project-name"
  description  = "My custom Cloud Security Command Center Finding Notification Configuration"
  pubsub_topic =  google_pubsub_topic.scc_v2_project_notification.id

  streaming_config {
    filter = "category = \"OPEN_FIREWALL\" AND 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 時,系統會建立這個服務帳戶,並在建立通知設定時,自動將 securitycenter.notificationServiceAgent 角色授予 PUBSUB_TOPIC 的 IAM 政策。通知功能需要這個服務帳戶角色才能運作。

在 VPC Service Controls 中授予 perimeter 存取權

如果您使用 VPC Service Controls,且 Pub/Sub 主題屬於服務範圍內的專案,則必須授予專案存取權,才能建立通知。

如要授予專案存取權,請為用於建立通知的主體和專案建立輸入和輸出規則。這些規則可允許存取受保護的資源,並讓 Pub/Sub 驗證使用者是否具備 Pub/Sub 主題的 setIamPolicy 權限。

建立 NotificationConfig 前

完成「建立 NotificationConfig」一文中的步驟前,請先完成下列步驟。

控制台

  1. 前往 Google Cloud 控制台的「VPC Service Controls」頁面。

    前往 VPC Service Controls

  2. 選取您的機構。
  3. 在下拉式清單中,選取包含要授予存取權的服務範圍的存取權政策。

    清單中會顯示與存取權政策相關聯的 service perimeter。

  4. 按一下要更新的服務安全防護範圍名稱。

    如要找出需要修改的服務邊界,請檢查記錄檔中顯示 RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 違規事項的項目。在這些項目中,檢查 servicePerimeterName 欄位:

    accessPolicies/ACCESS_POLICY_ID/servicePerimeters/SERVICE_PERIMETER_NAME
  5. 按一下「Edit」(編輯)

新增 egress 規則

  1. 按一下「輸出政策」
  2. 按一下「Add an egress rule」(新增輸出規則)
  3. 在「From」部分,設定下列詳細資料:

    1. 在「身分」>「身分」部分,選取「選取身分和群組」
    2. 按一下「Add identities」(新增身分)
    3. 輸入用來呼叫 Security Command Center API 的主體電子郵件地址。
    4. 選取主體或按下 ENTER 鍵,然後按一下「新增身分」
  4. 在「To」部分,設定下列詳細資料:

    1. 依序選取「資源」>「專案」>「所有專案」
    2. 在「作業或 IAM 角色」中,選取「選取作業」
    3. 按一下「新增作業」,然後新增下列作業:

      • 新增 pubsub.googleapis.com 服務。
        1. 按一下「所有方法」
        2. 按一下「新增所有方法」

新增 ingress 規則

  1. 按一下「輸入政策」
  2. 按一下「Add an ingress rule」(新增輸入規則)
  3. 在「From」部分,設定下列詳細資料:

    1. 在「身分」>「身分」部分,選取「選取身分和群組」
    2. 按一下「Add identities」(新增身分)
    3. 輸入用來呼叫 Security Command Center API 的主體電子郵件地址。
    4. 選取主體或按下 ENTER 鍵,然後按一下「新增身分」
  4. 在「To」部分,設定下列詳細資料:

    1. 依序選取「資源」>「專案」>「選取專案」
    2. 按一下「新增專案」,然後新增包含 Pub/Sub 主題的專案。
    3. 在「作業或 IAM 角色」中,選取「選取作業」
    4. 按一下「新增作業」,然後新增下列作業:

      • 新增 pubsub.googleapis.com 服務。
        1. 按一下「所有方法」
        2. 按一下「新增所有方法」
  5. 按一下 [儲存]

gcloud

  1. 如果尚未設定配額專案,請設定配額專案。選擇已啟用 Access Context Manager API 的專案。

    gcloud config set billing/quota_project QUOTA_PROJECT_ID

    QUOTA_PROJECT_ID 替換為您要用於帳單和配額的專案 ID。

  2. 建立名為 egress-rule.yaml 的檔案,並在當中加入下列內容:

    - egressFrom:
        identities:
        - PRINCIPAL_ID
      egressTo:
        operations:
        - serviceName: pubsub.googleapis.com
          methodSelectors:
          - method: '*'
        resources:
        - '*'

    PRINCIPAL_ID 替換為用於呼叫 Security Command Center API 的主體 ID。

  3. 建立名為 ingress-rule.yaml 的檔案,並在當中加入下列內容:

    - ingressFrom:
        identities:
        - PRINCIPAL_ID
        sources:
        - accessLevel: '*'
      ingressTo:
        operations:
        - serviceName: pubsub.googleapis.com
          methodSelectors:
          - method: '*'
        resources:
        - '*'

    PRINCIPAL_ID 替換為用於呼叫 Security Command Center API 的主體 ID。

  4. 將輸出規則新增至範圍:

    gcloud access-context-manager perimeters update PERIMETER_NAME \
        --set-egress-policies=egress-rule.yaml

    更改下列內容:

    • PERIMETER_NAME:perimeter 的名稱。例如: accessPolicies/1234567890/servicePerimeters/example_perimeter

      如要找出需要修改的服務周邊,請檢查記錄檔中顯示 RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 違規事項的項目。在這些項目中,檢查 servicePerimeterName 欄位:

      accessPolicies/ACCESS_POLICY_ID/servicePerimeters/SERVICE_PERIMETER_NAME
  5. 將輸入規則新增至範圍:

    gcloud access-context-manager perimeters update PERIMETER_NAME \
        --set-ingress-policies=ingress-rule.yaml

    更改下列內容:

    • PERIMETER_NAME:perimeter 的名稱。例如: accessPolicies/1234567890/servicePerimeters/example_perimeter

      如要找出需要修改的服務周邊,請檢查記錄檔中顯示 RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 違規事項的項目。在這些項目中,檢查 servicePerimeterName 欄位:

      accessPolicies/ACCESS_POLICY_ID/servicePerimeters/SERVICE_PERIMETER_NAME

詳情請參閱「輸入和輸出規則」。

為 NotificationConfig 建立 Ingress 規則

如要為 NotificationConfig 建立 Ingress 規則,請按照「建立 NotificationConfig」中的操作說明完成步驟,然後完成下列步驟。

控制台

  1. 重新開啟上一節中的服務安全防護範圍。

    前往 VPC Service Controls

新增 ingress 規則

  1. 按一下「輸入政策」
  2. 按一下「Add an ingress rule」(新增輸入規則)
  3. 在「From」部分,設定下列詳細資料:

    1. 在「身分」>「身分」部分,選取「選取身分和群組」
    2. 按一下「Add identities」(新增身分)
    3. 輸入可識別 NotificationConfig 服務代理人的電子郵件地址。這個地址的格式如下:

      service-org-ORGANIZATION_ID@gcp-sa-scc-notification.iam.gserviceaccount.com

      請將 ORGANIZATION_ID 替換成組織 ID。

    4. 選取服務代理或按下 ENTER 鍵,然後按一下「新增身分」
  4. 在「To」部分,設定下列詳細資料:

    1. 依序選取「資源」>「專案」>「選取專案」
    2. 按一下「新增專案」,然後新增包含 Pub/Sub 主題的專案。
    3. 在「作業或 IAM 角色」中,選取「選取作業」
    4. 按一下「新增作業」,然後新增下列作業:

      • 新增 pubsub.googleapis.com 服務。
        1. 按一下「所有方法」
        2. 按一下「新增所有方法」
  5. 按一下 [儲存]

gcloud

  1. 如果尚未設定配額專案,請設定配額專案。選擇已啟用 Access Context Manager API 的專案。

    gcloud config set billing/quota_project QUOTA_PROJECT_ID

    QUOTA_PROJECT_ID 替換為您要用於帳單和配額的專案 ID。

  2. 建立名為 ingress-rule.yaml 的檔案,並在當中加入下列內容:

    - ingressFrom:
        identities:
        - serviceAccount:service-org-ORGANIZATION_ID@gcp-sa-scc-notification.iam.gserviceaccount.com
        sources:
        - accessLevel: '*'
      ingressTo:
        operations:
        - serviceName: pubsub.googleapis.com
          methodSelectors:
          - method: '*'
        resources:
        - '*'

    請將 ORGANIZATION_ID 替換成組織 ID。

  3. 將輸入規則新增至範圍:

    gcloud access-context-manager perimeters update PERIMETER_NAME \
        --set-ingress-policies=ingress-rule.yaml

    更改下列內容:

    • PERIMETER_NAME:perimeter 的名稱。例如: accessPolicies/1234567890/servicePerimeters/example_perimeter

      如要找出需要修改的服務周邊,請檢查記錄檔中顯示 RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 違規事項的項目。在這些項目中,檢查 servicePerimeterName 欄位:

      accessPolicies/ACCESS_POLICY_ID/servicePerimeters/SERVICE_PERIMETER_NAME

詳情請參閱「輸入和輸出規則」。

選取的專案、使用者和服務帳戶現在可以存取受保護的資源,並建立通知。

如果按照本指南操作後,通知功能已正常運作,現在可以刪除下列項目:

  • 主體的輸入規則
  • 主體的輸出規則

這些規則僅用於設定 NotificationConfig。不過,如要讓通知功能繼續運作,您必須保留 NotificationConfig 的連入規則,讓通知發布至服務邊界後方的 Pub/Sub 主題。

後續步驟