为 Pub/Sub 启用发现结果通知

本页面介绍了如何启用 Security Command Center API 通知。

通知会在几分钟内将发现结果和发现结果更新发送到 Pub/Sub 主题。Security Command Center API 通知包含 Security Command Center 在 Google Cloud 控制台中显示的所有发现结果信息。

您可以将 Pub/Sub 中的 Security Command Center 通知直接关联到 Cloud Run 函数操作。如需查看有助于响应、丰富和补救的示例函数,请参阅 Cloud Run 函数代码的 Security Command Center 开源代码库。代码库包含解决方案,可帮助您对安全发现结果采取自动操作。

或者,您可以将发现结果导出到 BigQuery,也可以在 Google Cloud 控制台中为 Pub/Sub 设置持续导出

准备工作

  1. 如需获得设置和配置 Security Command Center API 通知所需的权限,请让管理员向您授予以下 IAM 角色:

    • 已启用 Security Command Center 的组织或项目的 Security Center Admin (roles/securitycenter.admin)
    • 您要创建 Pub/Sub 主题的项目的 Project IAM Admin (roles/resourcemanager.projectIamAdmin)

    如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

    您也可以通过自定义角色或其他预定义角色来获取所需的权限。

  2. Enable the Security Command Center API:

    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 不会限制您在哪个位置创建导出内容。

持续导出内容仅存储在其创建的位置,无法在其他位置查看或修改。

创建持续导出后,您无法更改其位置。如需更改位置,您需要删除持续导出,然后在新位置重新创建。

如需使用 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

设置 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 Admin 角色 (roles/pubsub.admin)。

如需授予此角色,请执行以下操作:

  1. 转到 Google Cloud 控制台。

    转到 Google Cloud 控制台

  2. 选择启用了 Security Command Center API 的项目。

  3. 点击激活 Cloud Shell

  4. 向您的 Google 账号授予 Pub/Sub 主题所需的角色:

    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。

在 Google Cloud 控制台中,某些 NotificationConfig 资源可能带有旧版标签,这表示它们是使用 v1 Security Command Center API 创建的。您可以使用 Google Cloud 控制台、gcloud CLI、v1 Security Command Center API 或 Security Command Center 的 v1 客户端库管理这些 NotificationConfig 资源。

如需使用 gcloud CLI 管理这些 NotificationConfig 资源,您在运行 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:通知适用的资源层次结构中的范围,organizationfolderproject
  • PARENT_ID:父级组织、文件夹或项目的 ID,格式为 organizations/123folders/456projects/789
  • LOCATION:如果数据驻留已启用,则为存储数据的 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 角色。需要此服务账号角色才能接收通知。

在 VPC Service Controls 中授予边界访问权限

如果您使用 VPC Service Controls,并且 Pub/Sub 主题属于服务边界内的项目,则必须授予对项目的访问权限,以便创建通知。

如需授予对项目的访问权限,请为用于创建通知的主账号和项目创建入站和出站规则。这些规则允许访问受保护的资源,并可让 Pub/Sub 验证用户是否具有对 Pub/Sub 主题的 setIamPolicy 权限。

创建 NotificationConfig 之前

在完成创建 NotificationConfig 中的步骤之前,请执行以下操作:

  1. 转到 Google Cloud 控制台中的 VPC Service Controls 页面。

    转到 VPC Service Controls

  2. 如有必要,请选择您的组织。

  3. 点击要更改的服务边界的名称。

    如需查找您需要修改的服务边界,您可以查看日志中是否存在显示 RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 违规行为的条目。在这些条目中,检查 servicePerimeterName 字段:accessPolicies/ACCESS_POLICY_ID/servicePerimeters/SERVICE_PERIMETER_NAME

  4. 点击修改边界

  5. 在导航菜单中,点击入站流量政策

  6. 如需为用户或服务账号配置入站流量规则,请使用以下参数:

    • API 客户端的 FROM 特性
      • 来源下拉菜单中,选择所有来源
      • 身份下拉菜单中,选择选定的身份
      • 点击选择,然后输入用于调用 Security Command Center API 的主账号。
    • Google Cloud 服务/资源的 TO 属性
      • 项目下拉菜单中,选择选定的项目
      • 点击选择,然后输入 Pub/Sub 主题所属的项目。
      • 服务下拉菜单中,选择选定的服务,然后选择 Cloud Pub/Sub API
      • 方法下拉菜单中,选择所有操作
  7. 点击保存

  8. 在导航菜单中,点击出站流量政策

  9. 点击添加规则 (Add Rule)。

  10. 如需为用户或服务账号配置出站流量规则,请输入以下参数:

    • API 客户端的 FROM 特性
      • 身份下拉菜单中,选择选定的身份
      • 点击选择,然后输入用于调用 Security Command Center API 的主账号。
    • Google Cloud 服务/资源的 TO 属性
      • 项目下拉菜单中,选择所有项目
      • 服务下拉菜单中,选择选定的服务,然后选择 Cloud Pub/Sub API
      • 方法下拉菜单中,选择所有操作
  11. 点击保存

为 NotificationConfig 创建入站流量规则

如需为 NotificationConfig 创建入站规则,请执行以下操作:

  1. 按照创建 NotificationConfig 中的说明执行操作。
  2. 重新打开上一部分中的服务边界。
  3. 点击入站流量政策
  4. 点击添加规则 (Add Rule)。
  5. 如需为您创建的 NotificationConfig 服务账号配置入站规则,请输入以下参数:
    • API 客户端的 FROM 特性
      • 来源下拉菜单中,选择所有来源
      • 身份下拉菜单中,选择选定的身份
      • 点击选择,然后输入 NotificationConfig 服务账号的名称:service-org-ORGANIZATION_ID@gcp-sa-scc-notification.iam.gserviceaccount.com
    • GCP 服务/资源的 TO 特性
      • 项目下拉菜单中,选择选定的项目
      • 点击选择,然后选择 Pub/Sub 主题所属的项目。
      • 服务下拉菜单中,选择选定的服务,然后选择 Cloud Pub/Sub API
      • 方法下拉菜单中,选择所有操作
  6. 在导航菜单中,点击保存

选定的项目、用户和服务账号现在可以访问受保护的资源并创建通知。

如果您已按照本指南中的所有步骤操作,并且通知正常工作,您现在可以删除以下内容:

  • 主账号的入站规则
  • 主账号的出站规则

这些规则只需要配置 NotificationConfig。但是,若要使通知继续正常工作,您必须保留 NotificationConfig 的入站规则,该规则允许将通知发布到服务边界后面的 Pub/Sub 主题。

后续步骤