Secret Manager のイベント通知

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

概要

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

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

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

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_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 と gcloud コマンドライン ツールでのみ使用できます。

始める前に

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

  • Secret Manager:

    • Secret Manager リソースを保持するプロジェクトを作成するか、既存のプロジェクトを使用します。
    • 必要に応じて、Secret Manager クイックスタートの Secret Manager の構成セクションの手順を完了します。
  • Pub/Sub:

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

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

$ gcloud auth login --update-adc

サービス エージェント ID の作成

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

Cloud SDK でサービス 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 クイックスタートに従って、Cloud Console の Pub/Sub プロジェクトにトピックを作成します。または、次の例のように gcloud コマンドライン ツールを使用してトピックを作成することもできます。

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

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

サービス アカウントに Secret Manager の権限を付与し、作成したトピックで公開します。これは、Cloud Console または gcloud コマンドライン ツールで実行できます。次のコマンドは、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 クイックスタートに従って、Cloud Console の Pub/Sub プロジェクトでサブスクリプションを作成します。または、次の例のように gcloud コマンドライン ツールを使用してサブスクリプションを作成することもできます。

$ 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 をコマンドラインで使用するには、まず Cloud SDK のバージョン 338.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 トピックを変更します。gcloud コマンドライン ツールを使用すると、シークレットへの 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 のドキュメントをご覧ください。次のサンプルコードは、UPDATE_SECRET イベントがトピックに公開されるたびにシークレット メタデータを出力する Cloud Functions 用です。

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
    {
        public Task HandleAsync(CloudEvent cloudEvent, MessagePublishedData data, CancellationToken cancellationToken)
        {
            if (data.Message.Attributes["eventType"] == "SECRET_UPDATE") {
                string secretId = data.Message.Attributes["secretId"];
                string secretMetadata = data.Message.TextData;
                Console.WriteLine($"Secret {secretId} was updated. Its new metadata is: {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

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

package com.example;

import com.example.Example.PubSubMessage;
import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import java.util.Base64;
import java.util.Map;
import java.util.logging.Logger;

// 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).
public class Example implements BackgroundFunction {
  private static final Logger logger = Logger.getLogger(Example.class.getName());

  @Override
  public void accept(PubSubMessage message, Context context) {
    if (message.attributes.get("eventType").equals("SECRET_UPDATE")) {
      String secretId = message.attributes.get("secretId");
      String data = new String(Base64.getDecoder().decode(message.data));
      logger.info(String.format("Secret %s was updated. Its new metadata is: %s", secretId, data));
    }
  }

  public static class PubSubMessage {
    String data;
    Map attributes;
    String messageId;
    String publishTime;
  }
}

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) => {
  event_type = event.attributes.eventType;
  if (event_type == 'SECRET_UPDATE') {
    const secretID = event.attributes.secretId;
    const secretMetadata = Buffer.from(event.data, 'base64').toString();
    console.log(`Secret ${secretID} was updated. Its new metadata is: ${secretMetadata}`);
  }
};

Python

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

def consume_event_notification(event, unused_context):
    """
    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")
    return f"Received {event_type} for {secret_id}. New metadata: {secret_metadata}"

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"]
  if message["attributes"]["eventType"] == "SECRET_UPDATE"
    secret_id = message["attributes"]["secretId"]
    message_data = Base64.decode64 message["data"]
    FunctionsFramework.logger.info "Secret %s was updated. Its new metadata is: %s" % [secret_id, message_data]
  end
end

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

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

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

次のステップ