シークレットの通知を設定する

このトピックでは、Secret Manager でのイベント通知のサポートについて説明します。

概要

イベント通知は、シークレットとシークレット バージョンの変更に関する情報を Pub/Sub に送信します。これらの通知を使用して、任意のワークフローをトリガーできます。たとえば、新しいシークレット バージョンが追加されたときにアプリケーションを再起動したり、シークレットが削除されたときにセキュリティ エンジニアに通知したりできます。これらの通知を使用してワークフローをトリガーする方法の詳細については、Pub/Sub のドキュメントをご覧ください。

Secret Manager でのイベント通知の仕組み

シークレットは、最大 10 個の Pub/Sub トピックのリストで構成できます。シークレットまたはそのバージョンの 1 つを変更するオペレーションが実行されるたびに、Secret Manager はそのシークレットのそれぞれの Pub/Sub トピックにメッセージを自動的にパブリッシュします。GetListAccess の呼び出しでは、メッセージはパブリッシュされません

Pub/Sub メッセージには、イベントに関するメタデータを含む「属性」の Key-Value ペアのセットと、作成または更新された Secret または SecretVersion リソースの完全な JSON シリアル化が含まれます。この JSON は、UTF-8 でエンコードされた文字列です。この文字列は、Secret Manager の公開 API(proto3 JSON マッピングで指定された JSON でエンコードされている)によって指定された形式で Secret または SecretVersion リソースを厳密に表しています。

イベントの種類

Secret Manager でサポートされているイベントタイプのリストは次のとおりです。

イベントタイプ 説明
SECRET_CREATE 新しいシークレットが正常に作成されると送信されます。
SECRET_UPDATE 新しいシークレットが正常に更新されると送信されます。
SECRET_DELETE ユーザーによって開始されたリクエスト、またはシークレットの有効期限によってシークレットが削除されると送信されます。
SECRET_VERSION_ADD 新しいシークレット バージョンが正常に追加されると送信されます。
SECRET_VERSION_ENABLE シークレット バージョンを有効にすると送信されます。
SECRET_VERSION_DISABLE シークレット バージョンが有効になると送信されます。
SECRET_VERSION_DESTROY シークレット バージョンを破棄すると送信されます。
SECRET_VERSION_DESTROY_SCHEDULED シークレットに破棄の遅延期間が構成され、ユーザーがシークレット バージョンを破棄しようとすると送信されます。
SECRET_ROTATE シークレットをローテーションするタイミングになると送信されます。詳細については、シークレットのローテーション ポリシーの作成と管理をご覧ください。
TOPIC_CONFIGURED

これは、eventType: TOPIC_CONFIGURED 以外の本文や属性がないテスト メッセージです。これは、シークレットが Pub/Sub トピックのリストで作成または更新されるときに送信されますが、オペレーションが成功したことを示すものではありません。

オペレーションが成功した場合は、直後に SECRET_CREATE または SECRET_UPDATE メッセージが送信されます。

シークレットでトピックが更新されるたびに、すでに存在しているトピックを含むすべてのシークレットのトピックに TOPIC_CONFIGURED メッセージが送信されます。

通知形式

Pub/Sub トピックに送信される通知は、次の 2 つの部分で構成されます。

  • 属性: イベントを記述するキー値のペアのセット
  • データ: 変更されたオブジェクトのメタデータを含む文字列

属性

属性は、Secret Manager から Pub/Sub トピックに送信される通知に含まれる Key-Value ペアです。TOPIC_CONFIGURED テスト メッセージ以外のすべての通知には、通知のデータに関係なく、常に次の Key-Value ペアのセットが含まれます。

属性名 説明
eventType SECRET_CREATE 発生したイベントの種類。有効な値については、イベントの種類をご覧ください。
dataFormat JSON_API_V1 オブジェクト データの形式。
secretId projects/p/secrets/my-secret イベントが発生したシークレットの完全なリソース名。
timestamp 2021-01-20T11:17:45.081104-08:00 イベントの発生時間。

また、次の Key-Value ペアのセットが通知に含まれる場合もあります。

属性名 説明
versionId projects/p/secrets/my-secret/versions/456

イベントが発生したシークレット バージョンの名前。

これは SECRET_VERSION_ADDSECRET_VERSION_ENABLESECRET_VERSION_DISABLESECRET_VERSION_DESTROY のイベント通知にのみ存在します。

deleteType REQUESTED 削除がユーザーによりリクエストされた(REQUESTED)か、シークレットの有効期限(EXPIRATION)により削除されたかのどちらか。SECRET_DELETE イベント通知のみに表示されます。

データ

データ フィールドは、変更されたオブジェクトのメタデータを含む UTF-8 文字列です。データはシークレットまたはシークレット バージョンのいずれかです。

SECRET_DELETE 通知の場合、データ フィールドに含まれるメタデータは、削除前のオブジェクトのメタデータを表します。それ以外の通知では、データ フィールドに含まれるメタデータは、変更発生後のオブジェクトのメタデータを表します。

制限事項

イベント通知は、Secret Manager v1 API と Google Cloud CLI でのみ使用できます。

始める前に

すべてのリソースを同じプロジェクトに保存することも、シークレットと Pub/Sub トピックを別のプロジェクトに保存することもできます。Secret Manager と Pub/Sub を設定するには、次の前提条件を満たす必要があります。

  • Secret Manager:

    • Secret Manager リソースを保持するプロジェクトを作成するか、既存のプロジェクトを使用します。
    • 必要に応じて、Secret Manager ガイドの Secret Manager API を有効にするページに記載されている手順を完了します。
  • Pub/Sub:

    • Pub/Sub リソースを保持するプロジェクトを作成するか、既存のプロジェクトを使用します。
    • 必要に応じて、Pub/Sub API を有効にします

Google Cloud に対して認証を行います。

$ gcloud auth login --update-adc

サービス エージェント ID を作成する

イベント通知を使用するシークレットが必要なプロジェクトごとにサービス エージェント ID を作成する必要があります。

Google Cloud CLI でサービス ID を作成するには、次のコマンドを実行します。

$ gcloud beta services identity create \
    --service "secretmanager.googleapis.com" \
    --project "PROJECT_ID"

このコマンドは、次の形式でサービス アカウント名を返します。

service-PROJECT_NUMBER@gcp-sa-secretmanager.iam.gserviceaccount.com

シークレットに構成される Pub/Sub トピックに対してパブリッシュする権限を、このサービス アカウントに付与します。

サービス アカウント名を環境変数として保存します。

# This is from the output of the command above
$ export SM_SERVICE_ACCOUNT="service-...."

Secret Manager プロジェクト、Pub/Sub プロジェクト、Secret Manager サービス アカウントの環境変数は、この手順を完了するまで設定したままにする必要があります。

Pub/Sub トピックの作成

Pub/Sub クイックスタートに従って、Google Cloud Console の Pub/Sub プロジェクトにトピックを作成します。または、次の例のように Google Cloud CLI を使用してトピックを作成することもできます。

$ gcloud pubsub topics create "projects/PUBSUB_PROJECT_ID/topics/PUBSUB_TOPIC_NAME"

シークレットに複数の Pub/Sub トピックを作成する場合は、この手順を複数回繰り返します。

サービス アカウントに Secret Manager の権限を付与し、作成したトピックで公開します。これは Google Cloud Console または Google Cloud CLI から行うことができます。次のコマンドは、my-topic Pub/Sub トピックの Pub/Sub パブリッシャーのロール(roles/pubsub.publisher)をサービス アカウントに付与します。

$ gcloud pubsub topics add-iam-policy-binding PUBSUB_TOPIC_NAME \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/pubsub.publisher"

Pub/Sub サブスクリプションの作成

トピックに公開されたメッセージを表示するには、そのトピックへのサブスクリプションも作成する必要があります。Pub/Sub クイックスタートに従って、Google Cloud Console の Pub/Sub プロジェクトにサブスクリプションを作成します。または、次の例のように Google Cloud CLI を使用してサブスクリプションを作成することもできます。

$ gcloud pubsub subscriptions create "projects/PUBSUB_PROJECT_ID/subscriptions/PUBSUB_SUBSCRIPTION_NAME" \
    --topic "projects/PUBSUB_PROJECT_ID/topics/PUBSUB_TOPIC_NAME"

トピックが構成されたシークレットの作成

最大 10 個のトピックのリストを構成してシークレットを作成します。シークレットまたはシークレットのバージョンのいずれかが変更されると、シークレットで構成されているすべてのトピックがイベント通知を受信します。次のコマンドは、my-topic が構成されたシークレットを作成します。

gcloud

Secret Manager をコマンドラインで使用するには、まず Google Cloud CLI のバージョン 378.0.0 以降をインストールまたはアップグレードします。Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

$ gcloud secrets create SECRET_ID --topics TOPIC_NAME

API

次の例では、API の使用を示すために curl を使用します。gcloud auth print-access-token を使用してアクセス トークンを生成できます。Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

$ curl "https://secretmanager.googleapis.com/v1/projects/PROJECT_ID/secrets?secretId=SECRET_ID" \
    --request "POST" \
    --header "Content-Type: application/json" \
    --header "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @- <<EOF
{
  "replication":{
    "automatic":{}
  },
  "topics":{
    "name": "TOPIC_NAME"
  }
}
EOF

シークレット トピックを更新する

新しい Pub/Sub トピックのリソース名でシークレットを更新し、シークレットで構成されている Pub/Sub トピックを変更します。Google Cloud CLI を使用すると、シークレットへの 1 つ以上のトピックの追加、またはシークレットからトピックの削除に加えて、シークレットからすべてのトピックの消去を行うことができます。

トピックの追加

1 つ以上のトピックをシークレットに追加します。すでに存在するトピックを追加しても効果はありません。

$ gcloud secrets update "SECRET_ID" \
    --project "PROJECT_ID" \
    --add-topics "projects/PUBSUB_PROJECT_ID/topics/my-topic-2,projects/PUBSUB_PROJECT_ID/topics/PUBSUB_TOPIC_NAME"

トピックの削除

シークレットから 1 つ以上のトピックを削除します。存在しないトピックを削除しても効果はありません。

$ gcloud secrets update "SECRET_ID" \
    --project "PROJECT_ID" \
    --remove-topics "projects/PUBSUB_PROJECT_ID/topics/PUBSUB_TOPIC_NAME,projects/PUBSUB_PROJECT_ID/topics/PUBSUB_OTHER_TOPIC_NAME"

トピックのクリア

シークレットからすべてのトピックを削除します。

$ gcloud secrets update SECRET_ID \
    --project "PROJECT_ID" \
    --clear-topics

Cloud Functions でのイベント通知の使用

イベント通知を使用すると、Pub/Sub メッセージを使用する Cloud Functions を作成し、任意のワークフローをトリガーできます。完全なガイドについては、Cloud Functions のドキュメントをご覧ください。次のサンプルコードは、イベントがトピックに公開されるたびに eventType、secretId、メタデータを出力する Cloud Functions の関数用です。Secret Manager のすべてのイベントタイプのリストについては、イベントタイプをご覧ください。

C#

このコードを実行するには、まず C# 開発環境を設定し、Secret Manager C# SDK をインストールします。 Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.PubSub.V1;
using System;
using System.Threading;
using System.Threading.Tasks;

// Triggered from a message on a Cloud Pub/Sub topic.
// The printed value will be visible in Cloud Logging
// (https://cloud.google.com/functions/docs/monitoring/logging).
namespace PubSubSample
{
    public class Function : ICloudEventFunction<MessagePublishedData>
    {
        public Task HandleAsync(CloudEvent cloudEvent, MessagePublishedData data, CancellationToken cancellationToken)
        {
          string eventType = data.Message.Attributes["eventType"];
          string secretId = data.Message.Attributes["secretId"];
          string secretMetadata = data.Message.TextData;
          Console.WriteLine($"Received {eventType} for {secretId}. New metadata: {secretMetadata}.");
          return Task.CompletedTask;
        }
    }
}

Go

このコードを実行するには、まず Go 開発環境を設定し、Secret Manager Go SDK をインストールします。 Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

import (
	"context"
	"fmt"
)

// PubSubMessage is the payload of a Pub/Sub event.
type PubSubMessage struct {
	Attributes PubSubAttributes `json:"attributes"`
	Data       []byte           `json:"data"`
}

// PubSubAttributes are attributes from the Pub/Sub event.
type PubSubAttributes struct {
	SecretId  string `json:"secretId"`
	EventType string `json:"eventType"`
}

// ConsumeEventNotification demonstrates how to consume and process the Pub/Sub
// notification from Secret Manager.
func ConsumeEventNotification(ctx context.Context, m PubSubMessage) (string, error) {
	// The printed value will be visible in Cloud Logging:
	//
	//     https://cloud.google.com/functions/docs/monitoring/logging
	//
	eventType := m.Attributes.EventType
	secretID := m.Attributes.SecretId
	data := m.Data

	return fmt.Sprintf("Received %s for %s. New metadata: %q.",
		eventType, secretID, data), nil
}

Java

Secret Manager 用のクライアント ライブラリをインストールして使用する方法については、Secret Manager クライアント ライブラリをご覧ください。

Secret Manager に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証を設定するをご覧ください。


import java.util.Base64;
import java.util.Map;
import java.util.logging.Logger;
import lombok.Data;

// Demonstrates how to consume and process a Pub/Sub notification from Secret Manager. Triggered
// by a message on a Cloud Pub/Sub topic.
// Ideally the class should implement a background function that accepts a Pub/Sub message.
// public class ConsumeEventNotification implements BackgroundFunction<PubSubMessage> { }
public class ConsumeEventNotification {

  // You can configure the logs to print the message in Cloud Logging.
  private static final Logger logger = Logger.getLogger(ConsumeEventNotification.class.getName());

  // Accepts a message from a Pub/Sub topic and writes it to logger.
  public static String accept(PubSubMessage message) {
    String eventType = message.attributes.get("eventType");
    String secretId = message.attributes.get("secretId");
    String data = new String(Base64.getDecoder().decode(message.data));
    String log = String.format("Received %s for %s. New metadata: %s", eventType, secretId, data);
    logger.info(log);
    return log;
  }

  // Event payload. Mock of the actual Pub/Sub message.
  @Data
  public static class PubSubMessage {

    byte[] data;
    Map<String, String> attributes;
    String messageId;
    String publishTime;
    String orderingKey;
  }
}

Node.js

このコードを実行するには、まず Node.js 開発環境を設定し、Secret Manager Node.js SDK をインストールします。 Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

/**
* Triggered from a message on a Cloud Pub/Sub topic.
* The printed value will be visible in Cloud Logging
* (https://cloud.google.com/functions/docs/monitoring/logging).
*
* @param {!Object} event Event payload.
* @param {!Object} context Metadata for the event.
*/
exports.smEventsFunction = (event, context) => {
  const eventType = event.attributes.eventType;
  const secretID = event.attributes.secretId;
  const secretMetadata = Buffer.from(event.data, 'base64').toString();
  console.log(`Received ${eventType} for ${secretID}. New metadata: ${secretMetadata}.`);
};

Python

このコードを実行するには、まず Python 開発環境を設定し、Secret Manager Python SDK をインストールします。 Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

import base64

def consume_event_notification(event: dict, unused_context: None) -> str:
    """
    consume_event_notification demonstrates how to consume and process a
    Pub/Sub notification from Secret Manager.
    Args:
          event (dict): Event payload.
          unused_context (google.cloud.functions.Context): Metadata for the event.
    """
    event_type = event["attributes"]["eventType"]
    secret_id = event["attributes"]["secretId"]
    secret_metadata = base64.b64decode(event["data"]).decode("utf-8")
    event_notification = (
        f"Received {event_type} for {secret_id}. New metadata: {secret_metadata}"
    )
    print(event_notification)
    return event_notification

Ruby

このコードを実行するには、まず Ruby 開発環境を設定し、Secret Manager Ruby SDK をインストールします。 Compute Engine または GKE では、cloud-platform スコープを使用して認証する必要があります。

require "functions_framework"
require "base64"

# Triggered from a message on a Cloud Pub/Sub topic.
# The printed value will be visible in Cloud Logging
# (https://cloud.google.com/functions/docs/monitoring/logging).
FunctionsFramework.cloud_event "sm_events_function" do |event|
  message = event.data["message"]
  event_type = message["attributes"]["eventType"]
  secret_id = message["attributes"]["secretId"]
  message_data = Base64.decode64 message["data"]
  FunctionsFramework.logger.info "Received %s for %s. New metadata: %s." % [event_type, secret_id, message_data]
end

正しく構成されていないトピック

作成または更新オペレーションで Pub/Sub トピックがシークレットに追加されたものの、構成ミスにより Secret Manager がトピックにメッセージをパブリッシュできない場合、パブリッシュ エラーの理由を示すエラー メッセージが表示され、オペレーションは失敗します。たとえば、トピックが存在しない場合や、Secret Manager のサービス アカウントにパブリッシュの権限がない場合などに、このエラーが発生することがあります。

Pub/Sub トピックをシークレットに追加し、その後、Secret Manager がメッセージをパブリッシュできないようにトピックが変更された場合(たとえば、トピックが削除された場合や、Secret Manager のサービス アカウントの権限が削除された場合など)、Secret Manager は Secret Manager の Secret リソースに、パブリッシュに失敗した理由を示すメッセージとともにログを書き込みます。

次のステップ