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

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:

  • Get and List NotificationConfig: Security Center Notification Viewer or Editor
  • Update and Delete NotificationConfig: Security Center Notification Editor

Learn more about Security Command Center roles.

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 your service account or the account you're using to run gcloud tool commands.

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 the following:

  • Each organization can have a limited number of NotificationConfig files. For more information, see Quotas and limits.
  • You must have the Organization Administrator IAM role so that you can grant appropriate roles to the notifications service account or gcloud tool account.

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.

To grant the account the Security Center Notifications Configurations Editor IAM role using the gcloud command-line tool:

  1. Set environment variables:

    1. Set your organization name:

        export ORGANIZATION_ID=organization-id
      
    2. Set the email of the service account that you created when you set up finding notifications or the account you're using to run gcloud tool commands:

      • Set the email of the account used to run gcloud tool commands:

        export EMAIL=your-username@email.com
        
      • Or set the email of the service account:

        export EMAIL=service-account-name@$CONSUMER_PROJECT.iam.gserviceaccount.com
        
  2. Grant the necessary role to the service account or the account you used with gcloud tool commands:

    • Grant the role to the account used to run gcloud tool commands:

         gcloud organizations add-iam-policy-binding \
           $ORGANIZATION_ID \
           --member="user:$EMAIL" \
           --role='roles/securitycenter.notificationConfigEditor'
      
    • Or grant the role to the service account:

         gcloud organizations add-iam-policy-binding \
           $ORGANIZATION_ID \
           --member="serviceAccount:$EMAIL" \
           --role='roles/securitycenter.notificationConfigEditor'
      

After you grant the service account or gcloud tool account permissions, create the NotificationConfig using the language or platform of your choice:

gcloud

  # The numeric ID of the organization
  ORGANIZATION_ID=organization-id

  # The topic to which the notifications are published
  PUBSUB_TOPIC="projects/project-id/topics/topic-id"

  # The description for the NotificationConfig
  DESCRIPTION="Notifies for active findings"

  # Filters for active findings
  FILTER="state=\"ACTIVE\""

  gcloud scc notifications create notification-name \
    --organization "$ORGANIZATION_ID" \
    --description "$DESCRIPTION" \
    --pubsub-topic $PUBSUB_TOPIC \
    --filter "$FILTER"

Python

from google.cloud import securitycenter as securitycenter

client = securitycenter.SecurityCenterClient()

# TODO: organization_id = "your-org-id"
# TODO: notification_config_id = "your-config-id"
# TODO: pubsub_topic = "projects/{your-project-id}/topics/{your-topic-ic}"
# Ensure this ServiceAccount has the "pubsub.topics.setIamPolicy" permission on the new topic.

org_name = "organizations/{org_id}".format(org_id=organization_id)

created_notification_config = client.create_notification_config(
    request={
        "parent": org_name,
        "config_id": notification_config_id,
        "notification_config": {
            "description": "Notification for active findings",
            "pubsub_topic": pubsub_topic,
            "streaming_config": {"filter": 'state = "ACTIVE"'},
        },
    }
)

print(created_notification_config)

Java

import com.google.cloud.securitycenter.v1.CreateNotificationConfigRequest;
import com.google.cloud.securitycenter.v1.NotificationConfig;
import com.google.cloud.securitycenter.v1.NotificationConfig.StreamingConfig;
import com.google.cloud.securitycenter.v1.SecurityCenterClient;
import java.io.IOException;
  public static NotificationConfig createNotificationConfig(
      String organizationId, String notificationConfigId, String projectId, String topicName)
      throws IOException {
    // String organizationId = "{your-org-id}";
    // String notificationConfigId = {"your-unique-id"};
    // String projectId = "{your-project}"";
    // String topicName = "{your-topic}";

    String orgName = String.format("organizations/%s", organizationId);

    // Ensure this ServiceAccount has the "pubsub.topics.setIamPolicy" permission on the topic.
    String pubsubTopic = String.format("projects/%s/topics/%s", projectId, topicName);

    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      CreateNotificationConfigRequest request =
          CreateNotificationConfigRequest.newBuilder()
              .setParent(orgName)
              .setConfigId(notificationConfigId)
              .setNotificationConfig(
                  NotificationConfig.newBuilder()
                      .setDescription("Java notification config")
                      .setPubsubTopic(pubsubTopic)
                      .setStreamingConfig(
                          StreamingConfig.newBuilder().setFilter("state = \"ACTIVE\"").build())
                      .build())
              .build();

      NotificationConfig response = client.createNotificationConfig(request);
      System.out.println(String.format("Notification config was created: %s", response));
      return response;
    }
  }

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

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: %v", err)
	}
	defer client.Close()

	req := &securitycenterpb.CreateNotificationConfigRequest{
		Parent:   fmt.Sprintf("organizations/%s", 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: %v", err)
	}
	fmt.Fprintln(w, "New NotificationConfig created: ", notificationConfig)

	return nil
}

Node.js

// npm install @google-cloud/security-center/
const {SecurityCenterClient} = require('@google-cloud/security-center');

const client = new SecurityCenterClient();

// organizationId = "your-org-id";
// configId = "your-config-name";
// pubsubTopic = "projects/{your-project}/topics/{your-topic}";
// Ensure this Service Account has the "pubsub.topics.setIamPolicy" permission on this topic.

const orgName = client.organizationPath(organizationId);

async function createNotificationConfig() {
  const [response] = await client.createNotificationConfig({
    parent: orgName,
    configId: configId,
    notificationConfig: {
      description: 'Sample config for node.js',
      pubsubTopic: pubsubTopic,
      streamingConfig: {filter: 'state = "ACTIVE"'},
    },
  });
  console.log('Notification config creation succeeded: ', response);
}

createNotificationConfig();

PHP

use Google\Cloud\SecurityCenter\V1\SecurityCenterClient;
use Google\Cloud\SecurityCenter\V1\NotificationConfig;
use Google\Cloud\SecurityCenter\V1\NotificationConfig\StreamingConfig;

/** Uncomment and populate these variables in your code */
// $organizationId = "{your-org-id}";
// $notificationConfigId = {"your-unique-id"};
// $projectId = "{your-project}"";
// $topicName = "{your-topic}";

$securityCenterClient = new SecurityCenterClient();
$organizationName = $securityCenterClient::organizationName($organizationId);
$pubsubTopic = $securityCenterClient::topicName($projectId, $topicName);

$streamingConfig = (new StreamingConfig())->setFilter("state = \"ACTIVE\"");
$notificationConfig = (new NotificationConfig())
    ->setDescription('A sample notification config')
    ->setPubsubTopic($pubsubTopic)
    ->setStreamingConfig($streamingConfig);

$response = $securityCenterClient->createNotificationConfig(
    $organizationName,
    $notificationConfigId,
    $notificationConfig
);
printf('Notification config was created: %s' . PHP_EOL, $response->getName());

Ruby

require "google/cloud/security_center"

# Your organization id. e.g. for "organizations/123", this would be "123".
# org_id = "YOUR_ORGANZATION_ID"

# Your notification config id. e.g. for
# "organizations/123/notificationConfigs/my-config" this would be "my-config".
# config_id = "YOUR_CONFIG_ID"

# The PubSub topic where notifications will be published.
# pubsub_topic = "YOUR_TOPIC"

client = Google::Cloud::SecurityCenter.security_center

org_path = client.organization_path organization: org_id

notification_config = {
  description:      "Sample config for Ruby",
  pubsub_topic:     pubsub_topic,
  streaming_config: { filter: 'state = "ACTIVE"' }
}

response = client.create_notification_config(
  parent:              org_path,
  config_id:           config_id,
  notification_config: notification_config
)
puts "Created notification config #{config_id}: #{response}."

C#


using Google.Api.Gax.ResourceNames;
using Google.Cloud.SecurityCenter.V1;
using System;

///<summary> Create NotificationConfig Snippet. </summary>
public class CreateNotificationConfigSnippets
{
    public static NotificationConfig CreateNotificationConfig(
        string organizationId, string notificationConfigId, string projectId, string topicName)
    {
        OrganizationName orgName = new OrganizationName(organizationId);
        TopicName pubsubTopic = new TopicName(projectId, topicName);

        SecurityCenterClient client = SecurityCenterClient.Create();
        CreateNotificationConfigRequest request = new CreateNotificationConfigRequest
        {
            ParentAsOrganizationName = orgName,
            ConfigId = notificationConfigId,
            NotificationConfig = new NotificationConfig
            {
                Description = ".Net notification config",
                PubsubTopicAsTopicName = pubsubTopic,
                StreamingConfig = new NotificationConfig.Types.StreamingConfig { Filter = "state = \"ACTIVE\"" }
            }
        };

        NotificationConfig response = client.CreateNotificationConfig(request);
        Console.WriteLine($"Notification config was created: {response}");
        return response;
    }
}

Notifications are now published to the Pub/Sub topic you specified. To publish notifications, Security Command Center uses an organization-level service account in the form of service-org-organization-id@gcp-sa-scc-notification.iam.gserviceaccount.com with the role securitycenter.notificationServiceAgent. This organization-level 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

  # The numeric ID of the organization and the name of the notification that you want to get
  NOTIFICATION="organizations/organization-id/notificationConfigs/notification-name"

  gcloud scc notifications describe $NOTIFICATION

Python

from google.cloud import securitycenter as securitycenter

client = securitycenter.SecurityCenterClient()

# TODO: organization_id = "your-org-id"
# TODO: notification_config_id = "your-config-id"

notification_config_name = "organizations/{org_id}/notificationConfigs/{config_id}".format(
    org_id=organization_id, config_id=notification_config_id
)

notification_config = client.get_notification_config(
    request={"name": notification_config_name}
)
print("Got notification config: {}".format(notification_config))

Java

import com.google.cloud.securitycenter.v1.NotificationConfig;
import com.google.cloud.securitycenter.v1.NotificationConfigName;
import com.google.cloud.securitycenter.v1.SecurityCenterClient;
import java.io.IOException;
  public static NotificationConfig getNotificationConfig(
      String organizationId, String notificationConfigId) throws IOException {

    // String organizationId = "{your-org-id}";
    // String notificationConfigId = "{config-id}";

    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      NotificationConfig response =
          client.getNotificationConfig(
              NotificationConfigName.newBuilder()
                  .setOrganization(organizationId)
                  .setNotificationConfig(notificationConfigId)
                  .build());

      System.out.println(String.format("Notification config: %s", response));
      return response;
    }
  }

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

func getNotificationConfig(w io.Writer, orgID string, notificationConfigID string) error {
	// orgID := "your-org-id"
	// notificationConfigID := "your-config-id"

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

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

	req := &securitycenterpb.GetNotificationConfigRequest{
		Name: fmt.Sprintf("organizations/%s/notificationConfigs/%s", orgID, notificationConfigID),
	}

	notificationConfig, err := client.GetNotificationConfig(ctx, req)
	if err != nil {
		return fmt.Errorf("Failed to retrieve notification config: %v", err)
	}
	fmt.Fprintln(w, "Received config: ", notificationConfig)

	return nil
}

Node.js

// npm install @google-cloud/security-center/
const {SecurityCenterClient} = require('@google-cloud/security-center');

const client = new SecurityCenterClient();

// organizationId = "your-org-id";
// configId = "your-config-id";
const formattedConfigName = client.notificationConfigPath(
  organizationId,
  configId
);

async function getNotificationConfg() {
  const [response] = await client.getNotificationConfig({
    name: formattedConfigName,
  });
  console.log('Notification config: ', response);
}

getNotificationConfg();

PHP

use Google\Cloud\SecurityCenter\V1\SecurityCenterClient;

/** Uncomment and populate these variables in your code */
// $organizationId = '{your-org-id}';
// $notificationConfigId = {'your-unique-id'};

$securityCenterClient = new SecurityCenterClient();
$notificationConfigName = $securityCenterClient::notificationConfigName(
    $organizationId,
    $notificationConfigId
);

$response = $securityCenterClient->getNotificationConfig($notificationConfigName);
printf('Notification config was retrieved: %s' . PHP_EOL, $response->getName());

Ruby

require "google/cloud/security_center"

# Your organization id. e.g. for "organizations/123", this would be "123".
# org_id = "YOUR_ORGANZATION_ID"

# Your notification config id. e.g. for
# "organizations/123/notificationConfigs/my-config" this would be "my-config".
# config_id = "YOUR_CONFIG_ID"

client = Google::Cloud::SecurityCenter.security_center

config_path = client.notification_config_path organization:        org_id,
                                              notification_config: config_id

response = client.get_notification_config name: config_path
puts "Notification config fetched: #{response}"

C#


using Google.Cloud.SecurityCenter.V1;
using System;

/// <summary>Snippet for GetNotificationConfig</summary>
public class GetNotificationConfigSnippets
{
    public static NotificationConfig GetNotificationConfig(string organizationId, string configId)
    {
        SecurityCenterClient client = SecurityCenterClient.Create();
        NotificationConfigName notificationConfigName = new NotificationConfigName(organizationId, configId);

        NotificationConfig response = client.GetNotificationConfig(notificationConfigName);
        Console.WriteLine($"Notification config: {response}");
        return response;
    }
}

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. To grant an appropriate role:

  1. Set environment variables:

    1. Set the topic ID:

        export TOPIC_ID=topic-id
      
    2. Set the project ID for the project in which you enabled the notifications API:

        export CONSUMER_PROJECT=project-id
      
    3. Set the email of the service account that you created in the previous steps:

        export SERVICE_ACCOUNT_EMAIL=service-account-name@$CONSUMER_PROJECT.iam.gserviceaccount.com
      
  2. Grant the notifications service account a role with the pubsub.topics.setIamPolicy permission:

       gcloud pubsub topics add-iam-policy-binding \
         projects/$CONSUMER_PROJECT/topics/$TOPIC_ID \
         --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
         --role='roles/pubsub.admin'
    

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

gcloud

  # The topic to which the notifications are published
  PUBSUB_TOPIC="projects/project-id/topics/topic-id"

  # The description for the NotificationConfig
  DESCRIPTION="description"
  # The numeric ID of the organization and the name of the notification that you want to update
  NOTIFICATION="organizations/organization-id/notificationConfigs/notification-name"

  gcloud scc notifications update $NOTIFICATION
    --description "$DESCRIPTION" \
    --pubsub-topic $PUBSUB_TOPIC \
    --filter       $FILTER  

Python

from google.cloud import securitycenter as securitycenter
from google.protobuf import field_mask_pb2

client = securitycenter.SecurityCenterClient()

# TODO organization_id = "your-org-id"
# TODO notification_config_id = "config-id-to-update"
# TODO pubsub_topic = "projects/{new-project}/topics/{new-topic}"
# If updating a pubsub_topic, ensure this ServiceAccount has the
# "pubsub.topics.setIamPolicy" permission on the new topic.

notification_config_name = "organizations/{org_id}/notificationConfigs/{config_id}".format(
    org_id=organization_id, config_id=notification_config_id
)

updated_description = "New updated description"
updated_filter = 'state = "INACTIVE"'

# Only description and pubsub_topic can be updated.
field_mask = field_mask_pb2.FieldMask(
    paths=["description", "pubsub_topic", "streaming_config.filter"]
)

updated_notification_config = client.update_notification_config(
    request={
        "notification_config": {
            "name": notification_config_name,
            "description": updated_description,
            "pubsub_topic": pubsub_topic,
            "streaming_config": {"filter": updated_filter},
        },
        "update_mask": field_mask,
    }
)

print(updated_notification_config)

Java

import com.google.cloud.securitycenter.v1.NotificationConfig;
import com.google.cloud.securitycenter.v1.NotificationConfig.StreamingConfig;
import com.google.cloud.securitycenter.v1.SecurityCenterClient;
import com.google.protobuf.FieldMask;
import java.io.IOException;
  public static NotificationConfig updateNotificationConfig(
      String organizationId, String notificationConfigId, String projectId, String topicName)
      throws IOException {
    // String organizationId = "{your-org-id}";
    // String notificationConfigId = "{your-config-id}";
    // String projectId = "{your-project}";
    // String topicName = "{your-topic}";

    String notificationConfigName =
        String.format(
            "organizations/%s/notificationConfigs/%s", organizationId, notificationConfigId);

    // Ensure this ServiceAccount has the "pubsub.topics.setIamPolicy" permission on the topic.
    String pubsubTopic = String.format("projects/%s/topics/%s", projectId, topicName);

    NotificationConfig configToUpdate =
        NotificationConfig.newBuilder()
            .setName(notificationConfigName)
            .setDescription("updated description")
            .setPubsubTopic(pubsubTopic)
            .setStreamingConfig(StreamingConfig.newBuilder().setFilter("state = \"ACTIVE\""))
            .build();
    FieldMask fieldMask =
        FieldMask.newBuilder()
          .addPaths("description")
          .addPaths("pubsub_topic")
          .addPaths("streaming_config.filter").build();

    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      NotificationConfig updatedConfig = client.updateNotificationConfig(configToUpdate, fieldMask);

      System.out.println(String.format("Notification config: %s", updatedConfig));
      return updatedConfig;
    }
  }

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
	"google.golang.org/genproto/protobuf/field_mask"
)

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

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

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

	updatedDescription := "Updated sample config"
	updatedFilter := `state = "INACTIVE"`
	req := &securitycenterpb.UpdateNotificationConfigRequest{
		NotificationConfig: &securitycenterpb.NotificationConfig{
			Name:        fmt.Sprintf("organizations/%s/notificationConfigs/%s", orgID, notificationConfigID),
			Description: updatedDescription,
			PubsubTopic: updatedPubsubTopic,
			NotifyConfig: &securitycenterpb.NotificationConfig_StreamingConfig_{
				StreamingConfig: &securitycenterpb.NotificationConfig_StreamingConfig{
					Filter: updatedFilter,
				},
			},
		},
		UpdateMask: &field_mask.FieldMask{
			Paths: []string{"description", "pubsub_topic", "streaming_config.filter"},
		},
	}

	notificationConfig, err := client.UpdateNotificationConfig(ctx, req)
	if err != nil {
		return fmt.Errorf("Failed to update notification config: %v", err)
	}

	fmt.Fprintln(w, "Updated NotificationConfig: ", notificationConfig)

	return nil
}

Node.js

// npm install @google-cloud/security-center/
const {SecurityCenterClient} = require('@google-cloud/security-center');

const client = new SecurityCenterClient();

// organizationId = "your-org-id";
// configId = "your-config-id";
const formattedConfigName = client.notificationConfigPath(
  organizationId,
  configId
);

// pubsubTopic = "projects/{your-project}/topics/{your-topic}";
// Ensure this Service Account has the "pubsub.topics.setIamPolicy" permission on this topic.

async function updateNotificationConfig() {
  const [response] = await client.updateNotificationConfig({
    updateMask: {
      paths: ['description', 'pubsub_topic', 'streaming_config.filter'],
    },
    notificationConfig: {
      name: formattedConfigName,
      description: 'Updated config description',
      pubsubTopic: pubsubTopic,
      streamingConfig: {filter: 'state = "INACTIVE"'},
    },
  });
  console.log('notification config update succeeded: ', response);
}

updateNotificationConfig();

PHP

use Google\Cloud\SecurityCenter\V1\SecurityCenterClient;
use Google\Cloud\SecurityCenter\V1\NotificationConfig;
use Google\Cloud\SecurityCenter\V1\NotificationConfig\StreamingConfig;
use Google\Protobuf\FieldMask;

/** Uncomment and populate these variables in your code */
// $organizationId = '{your-org-id}';
// $notificationConfigId = {'your-unique-id'};
// $projectId = '{your-project}';
// $topicName = '{your-topic}';

$securityCenterClient = new SecurityCenterClient();

// Ensure this ServiceAccount has the 'pubsub.topics.setIamPolicy' permission on the topic.
// https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/setIamPolicy
$pubsubTopic = $securityCenterClient::topicName($projectId, $topicName);
$notificationConfigName = $securityCenterClient::notificationConfigName($organizationId, $notificationConfigId);

$streamingConfig = (new StreamingConfig())->setFilter("state = \"ACTIVE\"");
$fieldMask = (new FieldMask())->setPaths(['description', 'pubsub_topic', 'streaming_config.filter']);
$notificationConfig = (new NotificationConfig())
    ->setName($notificationConfigName)
    ->setDescription('Updated description.')
    ->setPubsubTopic($pubsubTopic)
    ->setStreamingConfig($streamingConfig);

$response = $securityCenterClient->updateNotificationConfig($notificationConfig, [$fieldMask]);
printf('Notification config was updated: %s' . PHP_EOL, $response->getName());

Ruby

require "google/cloud/security_center"

# Your organization id. e.g. for "organizations/123", this would be "123".
# org_id = "YOUR_ORGANZATION_ID"

# Your notification config id. e.g. for
# "organizations/123/notificationConfigs/my-config" this would be "my-config".
# config_id = "YOUR_CONFIG_ID"

# Updated description of the notification config.
# description = "YOUR_DESCRIPTION"

# The PubSub topic where notifications will be published.
# pubsub_topic = "YOUR_TOPIC"

# Updated filter string for Notification config.
# filter = "UPDATED_FILTER"

client = Google::Cloud::SecurityCenter.security_center

config_path = client.notification_config_path organization:        org_id,
                                              notification_config: config_id
notification_config = { name: config_path }
notification_config[:description] = description unless description.nil?
notification_config[:pubsub_topic] = pubsub_topic unless pubsub_topic.nil?
notification_config[:streaming_config][:filter] = filter unless filter.nil?

paths = []
paths.push "description" unless description.nil?
paths.push "pubsub_topic" unless pubsub_topic.nil?
paths.push "streaming_config.filter" unless filter.nil?
update_mask = { paths: paths }

response = client.update_notification_config(
  notification_config: notification_config,
  update_mask:         update_mask
)
puts response

C#


using Google.Cloud.SecurityCenter.V1;
using static Google.Cloud.SecurityCenter.V1.NotificationConfig.Types;
using Google.Protobuf.WellKnownTypes;
using System;

/// <summary>Snippet for UpdateNotificationConfig</summary>
public class UpdateNotificationConfigSnippets
{
    public static NotificationConfig UpdateNotificationConfig(
        string organizationId, string notificationConfigId, string projectId, string topicName)
    {
        NotificationConfigName notificationConfigName = new NotificationConfigName(organizationId, notificationConfigId);
        TopicName pubsubTopic = new TopicName(projectId, topicName);

        NotificationConfig configToUpdate = new NotificationConfig
        {
            NotificationConfigName = notificationConfigName,
            Description = "updated description",
            PubsubTopicAsTopicName = pubsubTopic,
            StreamingConfig = new StreamingConfig { Filter = "state = \"INACTIVE\"" }
        };

        FieldMask fieldMask = new FieldMask { Paths = { "description", "pubsub_topic", "streaming_config.filter" } };
        SecurityCenterClient client = SecurityCenterClient.Create();
        NotificationConfig updatedConfig = client.UpdateNotificationConfig(configToUpdate, fieldMask);

        Console.WriteLine($"Notification config updated: {updatedConfig}");
        return updatedConfig;
    }
}

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

  # The numeric ID of the organization and the name of the notification that you want to delete
  NOTIFICATION="organizations/organization-id/notificationConfigs/notification-name"

  gcloud scc notifications delete $NOTIFICATION

Python

from google.cloud import securitycenter as securitycenter

client = securitycenter.SecurityCenterClient()

# TODO: organization_id = "your-org-id"
# TODO: notification_config_id = "your-config-id"

notification_config_name = "organizations/{org_id}/notificationConfigs/{config_id}".format(
    org_id=organization_id, config_id=notification_config_id
)

client.delete_notification_config(request={"name": notification_config_name})
print("Deleted notification config: {}".format(notification_config_name))

Java

import com.google.cloud.securitycenter.v1.NotificationConfigName;
import com.google.cloud.securitycenter.v1.SecurityCenterClient;
import java.io.IOException;
  public static boolean deleteNotificationConfig(String organizationId, String notificationConfigId)
      throws IOException {
    // String organizationId = "{your-org-id}";
    // String notificationConfigId = "{config-id}";

    NotificationConfigName notificationConfigName =
        NotificationConfigName.newBuilder()
            .setOrganization(organizationId)
            .setNotificationConfig(notificationConfigId)
            .build();

    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      client.deleteNotificationConfig(notificationConfigName);

      System.out.println(String.format("Deleted Notification config: %s", notificationConfigName));
    }

    return true;
  }

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

func deleteNotificationConfig(w io.Writer, orgID string, notificationConfigID string) error {
	// orgID := "your-org-id"
	// notificationConfigID := "config-to-delete"

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

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

	name := fmt.Sprintf("organizations/%s/notificationConfigs/%s", orgID, notificationConfigID)
	req := &securitycenterpb.DeleteNotificationConfigRequest{
		Name: name,
	}

	if err = client.DeleteNotificationConfig(ctx, req); err != nil {
		return fmt.Errorf("Failed to retrieve notification config: %v", err)
	}
	fmt.Fprintln(w, "Deleted config: ", name)

	return nil
}

Node.js

// npm install @google-cloud/security-center/
const {SecurityCenterClient} = require('@google-cloud/security-center');

const client = new SecurityCenterClient();

// organizationId = "your-org-id";
// configId = "your-config-id";
const formattedConfigName = client.notificationConfigPath(
  organizationId,
  configId
);

async function deleteNotificationConfg() {
  await client.deleteNotificationConfig({name: formattedConfigName});
  console.log('Notification config deleted: ', formattedConfigName);
}

deleteNotificationConfg();

PHP

use Google\Cloud\SecurityCenter\V1\SecurityCenterClient;

/** Uncomment and populate these variables in your code */
// $organizationId = '{your-org-id}';
// $notificationConfigId = {'your-unique-id'};

$securityCenterClient = new SecurityCenterClient();
$notificationConfigName = $securityCenterClient::notificationConfigName(
    $organizationId,
    $notificationConfigId
);

$response = $securityCenterClient->deleteNotificationConfig($notificationConfigName);
print('Notification config was deleted' . PHP_EOL);

Ruby

require "google/cloud/security_center"

# Your organization id. e.g. for "organizations/123", this would be "123".
# org_id = "YOUR_ORGANZATION_ID"

# Your notification config id. e.g. for
# "organizations/123/notificationConfigs/my-config" this would be "my-config".
# config_id = "YOUR_CONFIG_ID"

client = Google::Cloud::SecurityCenter.security_center

config_path = client.notification_config_path organization:        org_id,
                                              notification_config: config_id

response = client.delete_notification_config name: config_path
puts "Deleted notification config #{config_id} with response: #{response}"

C#


using Google.Cloud.SecurityCenter.V1;
using System;

/// <summary>Snippet for DeleteNotificationConfig</summary>
public class DeleteNotificationConfigSnippets
{
    public static bool DeleteNotificationConfig(string organizationId, string notificationConfigId)
    {
        NotificationConfigName notificationConfigName = new NotificationConfigName(organizationId, notificationConfigId);
        SecurityCenterClient client = SecurityCenterClient.Create();

        client.DeleteNotificationConfig(notificationConfigName);
        Console.WriteLine($"Deleted Notification config: {notificationConfigName}");
        return true;
    }
}

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

  # The numeric ID of the organization
  ORGANIZATION=organization-id

  gcloud scc notifications list $ORGANIZATION

Python

from google.cloud import securitycenter as securitycenter

client = securitycenter.SecurityCenterClient()

# TODO: organization_id = "your-org-id"
org_name = "organizations/{org_id}".format(org_id=organization_id)

notification_configs_iterator = client.list_notification_configs(
    request={"parent": org_name}
)
for i, config in enumerate(notification_configs_iterator):
    print("{}: notification_config: {}".format(i, config))

Java

import com.google.cloud.securitycenter.v1.NotificationConfig;
import com.google.cloud.securitycenter.v1.OrganizationName;
import com.google.cloud.securitycenter.v1.SecurityCenterClient;
import com.google.cloud.securitycenter.v1.SecurityCenterClient.ListNotificationConfigsPagedResponse;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
  public static ImmutableList<NotificationConfig> listNotificationConfigs(String organizationId)
      throws IOException {
    // String organizationId = "{your-org-id}";

    OrganizationName orgName =
        OrganizationName.newBuilder().setOrganization(organizationId).build();

    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      ListNotificationConfigsPagedResponse response = client.listNotificationConfigs(orgName);

      ImmutableList<NotificationConfig> notificationConfigs =
          ImmutableList.copyOf(response.iterateAll());
      System.out.println(
          String.format("List notifications response: %s", response.getPage().getValues()));
      return notificationConfigs;
    }
  }

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"google.golang.org/api/iterator"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

func listNotificationConfigs(w io.Writer, orgID string) error {
	// orgId := "your-org-id"

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

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

	req := &securitycenterpb.ListNotificationConfigsRequest{
		Parent: fmt.Sprintf("organizations/%s", orgID),
	}
	it := client.ListNotificationConfigs(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}

		if err != nil {
			return fmt.Errorf("it.Next: %v", err)
		}

		fmt.Fprintln(w, "NotificationConfig: ", result)
	}

	return nil
}

Node.js

// npm install @google-cloud/security-center/
const {SecurityCenterClient} = require('@google-cloud/security-center');

const client = new SecurityCenterClient();

// organizationId = "your-org-id";
const orgName = client.organizationPath(organizationId);

async function listNotificationConfigs() {
  const [resources] = await client.listNotificationConfigs({parent: orgName});
  console.log('Received Notification configs: ');
  for (const resource of resources) {
    console.log(resource);
  }
}

listNotificationConfigs();

PHP

use Google\Cloud\SecurityCenter\V1\SecurityCenterClient;

/** Uncomment and populate these variables in your code */
// $organizationId = '{your-org-id}';

$securityCenterClient = new SecurityCenterClient();
$organizationName = $securityCenterClient::organizationName($organizationId);

foreach ($securityCenterClient->listNotificationConfigs($organizationName) as $element) {
    printf('Found notification config %s' . PHP_EOL, $element->getName());
}

print('Notification configs were listed' . PHP_EOL);

Ruby

require "google/cloud/security_center"

# Your organization id. e.g. for "organizations/123", this would be "123".
# org_id = "YOUR_ORGANZATION_ID"

client = Google::Cloud::SecurityCenter.security_center

org_path = client.organization_path organization: org_id

client.list_notification_configs(parent: org_path).each_page do |page|
  page.each do |element|
    puts element
  end
end

C#


using Google.Api.Gax.ResourceNames;
using Google.Api.Gax;
using Google.Cloud.SecurityCenter.V1;
using System;

/// <summary>Snippet for ListNotificationConfig</summary>
public class ListNotificationConfigSnippets
{
    public static PagedEnumerable<ListNotificationConfigsResponse, NotificationConfig> ListNotificationConfigs(string organizationId)
    {
        OrganizationName orgName = new OrganizationName(organizationId);
        SecurityCenterClient client = SecurityCenterClient.Create();
        PagedEnumerable<ListNotificationConfigsResponse, NotificationConfig> notificationConfigs = client.ListNotificationConfigs(orgName);

        // Print Notification Configuration names.
        foreach (var config in notificationConfigs)
        {
            Console.WriteLine(config.NotificationConfigName);
        }
        return notificationConfigs;
    }
}

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 tool doesn't support converting a Pub/Sub message into a NotificationMessage. You can use the gcloud tool 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

Python

# Requires https://cloud.google.com/pubsub/docs/quickstart-client-libraries#pubsub-client-libraries-python
import concurrent

from google.cloud import pubsub_v1
from google.cloud.securitycenter_v1 import NotificationMessage

# TODO: project_id = "your-project-id"
# TODO: subscription_name = "your-subscription-name"

def callback(message):
    print("Received message")

    notification_msg = NotificationMessage.from_json(message.data)

    print(
        "Notification config name: {}".format(
            notification_msg.notification_config_name
        )
    )
    print("Finding: {}".format(notification_msg.finding))

    # Ack the message to prevent it from being pulled again
    message.ack()

subscriber = pubsub_v1.SubscriberClient()
subscription_path = subscriber.subscription_path(project_id, subscription_name)

streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)

print("Listening for messages on {}...\n".format(subscription_path))
try:
    streaming_pull_future.result(timeout=1)  # Block for 1 second
except concurrent.futures.TimeoutError:
    streaming_pull_future.cancel()

Java


import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.cloud.securitycenter.v1.NotificationMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.PubsubMessage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class NotificationReceiver {
  private NotificationReceiver() {}

  static class NotificationMessageReceiver implements MessageReceiver {

    @Override
    public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
      NotificationMessage.Builder notificationMessageBuilder = NotificationMessage.newBuilder();

      try {
        String jsonString = message.getData().toStringUtf8();
        JsonFormat.parser().merge(jsonString, notificationMessageBuilder);

        NotificationMessage notificationMessage = notificationMessageBuilder.build();
        System.out.println(
            String.format("Config id: %s", notificationMessage.getNotificationConfigName()));
        System.out.println(String.format("Finding: %s", notificationMessage.getFinding()));
      } catch (InvalidProtocolBufferException e) {
        System.out.println("Could not parse message: " + e);
      } finally {
        consumer.ack();
      }
    }
  }

  public static void receiveNotificationMessages(String projectId, String subscriptionId) {
    // String projectId = "{your-project}";
    // String subscriptionId = "{your-subscription}";
    ProjectSubscriptionName subscriptionName =
        ProjectSubscriptionName.of(projectId, subscriptionId);

    try {
      Subscriber subscriber =
          Subscriber.newBuilder(subscriptionName, new NotificationMessageReceiver()).build();
      subscriber.startAsync().awaitRunning();

      // This sets the timeout value of the subscriber to 10s.
      subscriber.awaitTerminated(10_000, TimeUnit.MILLISECONDS);
    } catch (IllegalStateException | TimeoutException e) {
      System.out.println("Subscriber stopped: " + e);
    }
  }
}

Go

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

	"cloud.google.com/go/pubsub"
	"github.com/golang/protobuf/jsonpb"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
)

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: %v", 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: %v", err)
	}

	return nil
}

Node.js

const {PubSub} = require('@google-cloud/pubsub');
const {StringDecoder} = require('string_decoder');

// projectId = 'your-project-id'
// subscriptionId = 'your-subscription-id'

const subscriptionName =
  'projects/' + projectId + '/subscriptions/' + subscriptionId;
const pubSubClient = new PubSub();

function listenForMessages() {
  const subscription = pubSubClient.subscription(subscriptionName);

  // message.data is a buffer array of json
  // 1. Convert buffer to normal string
  // 2. Convert json to NotificationMessage object
  const messageHandler = message => {
    const jsonString = new StringDecoder('utf-8').write(message.data);
    const parsedNotificationMessage = JSON.parse(jsonString);

    console.log(parsedNotificationMessage);
    console.log(parsedNotificationMessage.finding);

    // ACK when done with message
    message.ack();
  };

  subscription.on('message', messageHandler);

  // Set timeout to 10 seconds
  setTimeout(() => {
    subscription.removeListener('message', messageHandler);
  }, 10000);
}

listenForMessages();

What's next