Creating and managing Notification Configs

This page describes how to use the Security Command Center API notifications feature, including the following examples:

  • Create a NotificationConfig
  • Get a NotificationConfig
  • Update a NotificationConfig
  • Delete a NotificationConfig
  • List NotificationConfig
  • Receive Pub/Sub notifications

Alternatively, Security Command Center Premium customers can set up Continuous Exports for Pub/Sub in Security Command Center.

Before you begin

To use the examples on this page, you need to complete the guide to set up finding notifications.

To execute the following examples, you need an Identity and Access Management (IAM) role with appropriate permissions:

  • Create NotificationConfig: Security Center Notification Configurations Editor (roles/securitycenter.notificationConfigEditor)
  • Get and List NotificationConfig: Security Center Notification Configurations Viewer (roles/securitycenter.notificationConfigViewer) or Security Center Notification Configurations Editor (roles/securitycenter.notificationConfigEditor)
  • Update and Delete NotificationConfig: Security Center Notification Configurations Editor (roles/securitycenter.notificationConfigEditor)

To grant appropriate roles to a principal that accesses a notificationConfig, you must have one of the following IAM roles:

  • Organization Administrator (roles/resourcemanager.organizationAdmin)
  • Folder IAM Admin (roles/resourcemanager.folderIamAdmin)
  • Project IAM Admin (roles/resourcemanager.projectIamAdmin)

The IAM roles for Security Command Center can be granted at the organization, folder, or project level. Your ability to view, edit, create, or update findings, assets, and security sources depends on the level for which you are granted access. To learn more about Security Command Center roles, see Access control.

Data residency and notifications

If data residency is enabled for Security Command Center, the configurations that define continuous exports to Pub/Sub—notificationConfig resources—are subject to data residency control and are stored in your Security Command Center location.

To export findings in a Security Command Center location to Pub/Sub, you must configure the continuous export in the same Security Command Center location as the findings.

Because the filters that are used in continuous exports can contain data that is subject to residency controls, make sure you specify the correct location before you create them. Security Command Center does not restrict which location you create exports in.

Continuous exports are stored only in the location in which they are created and cannot be viewed or edited in other locations.

After you create a continuous export, you can't change its location. To change the location, you need to delete the continuous export and recreate it in the new location.

To retrieve a continuous export by using API calls, you need to specify the location in the full resource name of the notificationConfig. For example:

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

Similarly, to retrieve a continuous export by using the gcloud CLI, you need to specify the location by using the --location flag. For example:

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

Creating a NotificationConfig

To create a NotificationConfig, you must have:

  • An existing Pub/Sub topic that you want to send notifications to.
  • Required IAM roles for the principal that creates the notificationConfig.

For more information, see the step to set up a Pub/Sub topic in the guide to set up finding notifications.

Before you create a NotificationConfig, note that each organization can have a limited number of NotificationConfig files. For more information, see Quotas and limits.

The NotificationConfig includes a filter field that limits notifications to useful events. This field accepts all of the filters that are available in the Security Command Center API findings.list method.

When you create a NotificationConfig, you specify a parent for the NotificationConfig from the Google Cloud resource hierarchy, either an organization, a folder, or a project. If you need to retrieve, update, or delete the NotificationConfig later, you need to include the numerical ID of the parent organization, folder, or project when you reference it.

In the Google Cloud console, some NotificationConfig resources might have a Legacy label, which indicates that they were created with the v1 Security Command Center API. You can manage these NotificationConfig resources with the Google Cloud console; the gcloud CLI; the v1 Security Command Center API; or the v1 client libraries for Security Command Center.

To manage these NotificationConfig resources with the gcloud CLI, you must not specify a location when you run the gcloud CLI command.

To create the NotificationConfig using the language or platform of your choice:

gcloud

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

Replace the following:

  • NOTIFICATION_NAME: the name of the notification. Must be between 1 and 128 characters and contain alphanumeric characters, underscores, or hyphens only.
  • PARENT: the scope in the resource hierarchy to which the notification applies, organization, folder, or project.
  • PARENT_ID: the ID of the parent organization, folder, or project, specified in the format of organizations/123, folders/456, or projects/789.
  • LOCATION: if data residency is enabled, the Security Command Center location in which to create a NotificationConfig; if data residency is not enabled, use the value global.
  • NOTIFICATION_DESCRIPTION: a description of the notification of no more than 1,024 characters.
  • PUBSUB_TOPIC: The Pub/Sub topic that will receive notifications. Its format is projects/PROJECT_ID/topics/TOPIC.
  • FILTER: the expression you define to select which findings get sent to Pub/Sub. For example, 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

Notifications are now published to the Pub/Sub topic you specified.

To publish notifications, a service account is created for you in the form of service-org-ORGANIZATION_ID@gcp-sa-scc-notification.iam.gserviceaccount.com. This service account is created when you create your first NotificationConfig and is automatically granted the securitycenter.notificationServiceAgent role on the IAM policy for PUBSUB_TOPIC when creating the notification config. This service account role is required for notifications to function.

Getting a NotificationConfig

To get a NotificationConfig, you must have an IAM role that includes the securitycenter.notification.get permission.

gcloud

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

Replace the following:

  • NOTIFICATION_NAME: the name of the notification configuration.
  • PARENT_TYPE the level of the resource hierarchy where the configuration is specified; use organization, folder, or project.
  • PARENT_ID: the numeric ID of the parent resource.
  • LOCATION: if data residency is enabled, the Security Command Center location in which to get the NotificationConfig; if data residency is not enabled, use the value global.

Updating a NotificationConfig

To update a NotificationConfig, you must have an IAM role that includes the securitycenter.notification.update permission.

When you update using a field mask, only the fields you specify are updated. If you don't use a field mask, all mutable fields in the NotificationConfig are replaced by the new values. You can use a field mask to update the Pub/Sub topic and description.

To complete this example, you must be subscribed to the new topic, and your notifications service account must have the pubsub.topics.setIamPolicy permission on the topic.

After you grant the necessary permissions, update the NotificationConfig description, Pub/Sub topic and filter using the language of your choice:

gcloud

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

Replace the following:

  • NOTIFICATION_NAME: the name of the notification configuration.
  • PARENT_TYPE the level of the resource hierarchy where the configuration is specified; use organization, folder, or project.
  • PARENT_ID: the numeric ID of the parent resource.
  • LOCATION: if data residency is enabled, the Security Command Center location in which to update the NotificationConfig; if data residency is not enabled, use the value global.
  • NOTIFICATION_DESCRIPTION: a description of the notification of no more than 1,024 characters.
  • PUBSUB_TOPIC: the Pub/Sub topic which will receive notifications. Its format is projects/PROJECT_ID/topics/TOPIC.
  • FILTER: the expression you define to select which findings get sent to Pub/Sub. For example, state="ACTIVE".

Deleting a NotificationConfig

To delete a NotificationConfig, you must have an IAM role that includes the securitycenter.notification.delete permission.

When you delete a NotificationConfig, the securitycenter.notificationServiceAgent role stays on the Pub/Sub topic. If you aren't using the Pub/Sub topic in any other NotificationConfig, remove the role from the topic. For more information, see access control.

Delete a NotificationConfig using the language of your choice:

gcloud

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

Replace the following:

  • NOTIFICATION_NAME: the name of the notification configuration.
  • PARENT_TYPE the level of the resource hierarchy where the configuration is specified; use organization, folder, or project.
  • PARENT_ID: the numeric ID of the parent resource.
  • LOCATION: if data residency is enabled, the Security Command Center location in which to delete the NotificationConfig; if data residency is not enabled, use the value global.

Listing NotificationConfigs

To list NotificationConfigs, you must have an IAM role that includes the securitycenter.notification.list permission.

All Security Command Center API lists are paginated. Each response returns a page of results and a token to return the next page. The default pageSize is 10. You can configure page size to a minimum of 1, and a maximum of 1000.

List NotificationConfigs using the language of your choice:

gcloud

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

Replace the following:

  • PARENT_TYPE the level of the resource hierarchy where the configuration is specified; use organizations, folders, or projects.
  • PARENT_ID: the numeric ID of the parent resource.
  • LOCATION: if data residency is enabled, the Security Command Center location in which to list NotificationConfig resources; if data residency is not enabled, use the value global.

Receiving Pub/Sub notifications

This section provides a sample notification message and examples that show how to convert a Pub/Sub message into a NotificationMessage that contains a finding.

Notifications are published to Pub/Sub in the JSON format. Following is an example of a notification message:

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

Convert a Pub/Sub message into a NotificationMessage using the language of your choice:

gcloud

The gcloud CLI doesn't support converting a Pub/Sub message into a NotificationMessage. You can use the gcloud CLI to get a NotificationMessage and print the JSON directly in your terminal:

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

  gcloud pubsub subscriptions pull $PUBSUB_SUBSCRIPTION

Replace the following:

  • PROJECT_ID with your project ID.
  • SUBSCRIPTION_ID with your subscription 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
}

What's next