Tempura ― Google Cloud PAMで構築する、複数プロバイダー対応の特権アクセス管理

2026-09-16

Tempura ― Google Cloud PAMで構築する、複数プロバイダー対応の特権アクセス管理

Tempura - A Cross-Provider Privileged Access Manager Built on Google Cloud PAMの日本語訳です。

EukaryaでSREをしているkekeです。

私たちは、ほぼすべてのシステムをGoogle Cloud上で運用しています。Google Cloud自体への特権アクセスには、Privileged Access Manager(PAM)を使っています。誰もロールを常時保持せず、必要なロールを必要な時間だけ申請し、承認者が確認する。そして時間が来れば、アクセス権は自動的になくなる仕組みです。

この記事では、その仕組みをGoogle Cloudの外にも広げた方法を紹介します。現在、データベースプロバイダーやGitHubなど、私たちが利用するSaaS製品へのアクセス申請は、Google Cloudのロール申請とまったく同じ手順で行えます。コンソールも承認フローも監査証跡も一つで、アクセス権には必ず有効期限があります。すべての申請は、今も人が確認して承認しています。自動化したのは承認後の処理、つまりアクセス権の作成と、さらに重要な、その削除です。

今回、Tempuraという小さなサービスを作りました。Cloud Run上のコンテナ一つと、数十行のYAMLで構成されています。名前は temporaryaccess を組み合わせ、天ぷらにちなんで付けました。魚介や野菜を薄く軽い衣でカラッと揚げた天ぷらは、揚げたてが一番で、いつまでも置いておくものではありません。アクセス権も同じです。必要なときに、必要な分だけ。その都度用意するのが、ちょうどいいのです。この記事では、既存の仕組みを拡張した理由、Tempuraの仕組み、そしてこの設計がセキュリティ的にもたらすものを説明します。

1. 申請窓口を一つにする

冒頭で述べたとおり、Google Cloud側の仕組みはすでに整っていました。申請、承認、利用期間、有効期限の管理はPAMに任せられ、その部分はうまく機能していました。

一方、Google Cloud以外ではそうはいきませんでした。申請方法自体はいつも同じで、Slackでメッセージを送るだけです。問題はその後でした。アクセス権を付与する人が手作業で対応しなければならず、しかも製品ごとにやり方が違ったのです。

  • データベースへのアクセス:プロバイダーのコンソールやCLIで、適切なロールを持つデータベースユーザーを作成する。
  • GitHub:Organizationの設定から、対象者を適切なチームに追加する。
  • IDプロバイダー:管理ダッシュボードから、テナントの管理者ロールを割り当てる。

それぞれ異なるコンソールと手順があり、後で元に戻すことも個別に覚えておかなければなりません。

この状況は、三つの立場の人たちに、それぞれ別の問題を生んでいました。

アクセス権を申請する人にとって

  • 申請できる権限の一覧がありません。必要なものを文章で説明し、その後は待つしかなく、申請が読まれたのか、承認されたのか、スレッドの中で忘れられたのかもわかりません。
  • 申請が面倒なので、一度得たアクセス権は手放さなくなります。こうして、強い権限が恒久的に積み重なっていきます。

申請を確認する人にとって

  • 申請はSlackのメッセージとして届き、そのたびに作業が中断されます。
  • 誰もが「追加してほしい」と頼みますが、「削除してほしい」と頼む人はいません。そのため、誰かが監査を行い、何か月も前に消えているべきだったアカウントを見つけるまで、削除は行われません。

セキュリティと監査の観点では

  • 承認の記録がSlackのスレッド、管理コンソール、メールの受信箱に散らばっています。会議でアクセスを認め、その場で付与してしまい、まったく記録が残らない場合もあります。
  • 「この人は先月、何にアクセスできたのか?」に答えるには、製品ごとに管理コンソールを開かなければなりません。

問題は三つですが、根本原因は一つです。製品ごとに申請窓口が別々だったのです。

そこで、窓口を一つにしました。Google CloudもSaaSも、すべてのアクセス申請をGoogle Cloud PAMに集約します。そうすることで、この三つの問題を同じ窓口で解決できます。

  • 手順が一つになる。 利用者はPAMの申請画面を一度覚えれば、どのアクセス申請にも使えます。
  • アクセス失効が自動になる。 多くのSaaS製品には、一時的なアクセスという概念がありません。データベースユーザーもチームへの所属も、誰かが削除するまで存在し続けるため、有効期限は外部から強制する必要があります。PAMの権限付与(grant)には、すでに必ず有効期限があります。SaaSへのアクセス権をPAMの権限付与に基づいて作れば、アクセス権の期限が切れた瞬間に削除でき、誰かが覚えておく必要はありません。
  • 監査証跡が一か所に集まる。 どの製品に対するものでも、すべての申請、承認、期限切れがCloud Audit Logsに記録されます。Google Cloud自体のためにすでに保存しているログと同じ場所です。

そして、付与されたアクセス権がすべて期限切れになるため、そもそも恒久的な権限が積み上がりません。アクセス権の棚卸しを速くしたのではなく、この経路では不要にしました。確認すべき残存権限がないからです。

2. 本当に必要だったもの

何かを作り始める前に、申請窓口を一つにするために必要なものを書き出しました。

  1. 誰が申請でき、誰が承認できるかを定めたポリシーを持つ承認ワークフロー
  2. 申請者の本人確認
  3. すべてのアクセス権に対する時間制限
  4. 監査ログ
  5. 外部製品でアクセス権を実際に作成・削除する仕組み

最初の四つは、Google Cloud PAMですでに満たせていました。本人確認はGoogle Cloud IAMと連携し、承認ポリシーがあり、付与されるすべてのアクセス権に利用期間が設定され、すべてがCloud Audit Logsに記録されます。足りなかったのは五つ目だけでした。

必要なもの担う仕組み
承認ワークフローとポリシーGoogle Cloud PAM
申請者の本人確認Google Cloud IAM
すべてのアクセス権に対する時間制限Google Cloud PAM
監査ログCloud Audit Logs
外部製品でのアクセス権の作成と削除未対応。この部分がTempuraになった

これに対応するために、全く新しいやり方を模索するのではなく、すでにある窓口を拡張することにしました。

3. Tempuraとは

Tempuraは、PAMの権限付与の承認やアクセス権の期限切れのイベントを受け取り、外部製品への変更に変換する小さなサービスです。

設計上、最も重要なのは責務の分離です。承認と実行は、別々のシステムが担当します。

責務担当
誰が申請できるか、誰が承認するか、最大利用期間Google Cloud PAM
申請者の本人確認Google Cloud IAM
外部製品でのアクセス権の作成と削除Tempura
外部製品の認証情報の保管Secret Manager

Tempuraは、自分で承認できません。利用期間を延長することも、PAMのポリシーを変更することもできません。PAMがすでに承認した権限付与に対して、その承認の範囲内でのみ動作します。

なぜTerraformプロバイダーなのか

SaaS製品ごとにAPIは異なります。私たちは、製品ごとにクライアントコードを実装して保守したくはありませんでした。Terraformプロバイダーはすでに5,000以上の製品向けに存在し、それぞれが「データベースユーザー」や「チームへの所属」といったリソースの作成、読み取り、削除の方法を知っています。

Tempuraは、Terraform CLIと同じプラグインプロトコルを使って、これらのプロバイダーと直接やり取りします。Terraform CLIは実行せず、Terraformのstateファイルもありません。権限付与が承認されると、Tempuraはプロバイダーにリソースの作成を依頼します。アクセス権の期限が切れると、削除を依頼します。

つまり、製品ごとのクライアントを実装・保守する必要がありません。また、Tempuraは、私たちがInfrastructure as Codeですでに使っている技術基盤の上で動きます。プロバイダー、リソースタイプ、引数は、チームがTerraformで使い慣れているものです。新しいクラウドプロバイダーやSaaS製品に対応したいときも、連携機能を自作してテストするのではなく、何千もの組織が利用するエコシステムから、成熟し、継続的に保守されているプロバイダーを利用できます。

4. 利用者から見た使い方

データベースへのアクセス申請は、Google Cloudプロジェクトへのアクセス申請と同じになりました。

  1. コンソールでGoogle Cloud PAMを開く。
  2. エンタイトルメントを選ぶ。たとえば mongodbatlas-read
  3. 利用期間を選び、申請理由を書く。
  4. 承認者が申請を確認し、承認するのを待つ。申請者にはメールが届く。
  5. 接続して作業する。時間が来れば、アクセス権はなくなる。

従来のSlack経由の手順と比べて、単に便利になっただけでなく、セキュリティも向上している点が二つあります。

利用者に認証情報を渡さない。 これは、私たちがすべてのサービスに適用しているルールに沿ったものです。すべてのサービスにはOAuth、OIDC、SAMLを通じてGoogleのIDでサインインし、固定のユーザー名とパスワードや、長期間有効なAPIキーを人が保持することはありません。Tempuraもこのルールを維持します。データベースプロバイダーでは、そのワークフォースID連携を利用しているため、Tempuraが作成するデータベースユーザーは申請者のGoogleアカウントにひも付き、利用者はGoogleログインで接続します。Slackで送ったり、パスワードマネージャーに保存したり、ローテーションを忘れたりするパスワードがありません。認証情報を保管するVaultが不要だったのもこのためです。保管するものがないのです。

承認者の操作は変わらず、人による承認も残る。 データベースへのアクセス申請も、Google Cloudのロール申請と同じ画面、同じ通知で、人が確認して承認します。Tempuraが動くのは、その承認の後だけです。

セキュリティ的にとってうれしい副次的な効果もあります。これらの製品で特権アクセスを得る経路が、PAMを通る一つだけになりました。誰がどの経路で何にアクセスできるのかを洗い出す必要はありません。経路が一つしかないからです。

5. 管理者から見た運用

新しい種類のアクセス権を追加するときは、ランブックに従って作業するのではなく、プルリクエストでレビューする設定変更として扱います。以下は、データベースへの読み取り専用アクセスを定義する設定の全体です。

providers: # Terraformのproviderブロックと同様
  - name: mongodbatlas
    source: mongodb/mongodbatlas
    version: "2.12.0"
    config:
      client_id: ${MONGODB_ATLAS_CLIENT_ID}
      client_secret: ${secret:projects/my-project/secrets/mongodb-atlas-client-secret/versions/latest}

entitlements:
  - id: "^mongodbatlas-read$"
    resources:
      - type: mongodbatlas_database_user # リソースを使ってユーザーを管理
        provider: mongodbatlas
        contexts: # データソースをコンテキストとして使用
          - id: project
            source: mongodbatlas_project
            config:
              name: reearth-dev
        config: 
          username: "<workforce-idp-id>/google-apps|{{.Grant.Requester}}"
          project_id: "{{.Context.project.project_id}}"
          auth_database_name: "$external"
          oidc_auth_type: USER
          roles:
            - role_name: readAnyDatabase
              database_name: admin

注目してほしい点がいくつかあります。

  • プロバイダーの認証情報は、Secret Managerへの参照です。ファイルに直接書かれることも、利用者に表示されることもありません。
  • エンタイトルメントIDは、先頭と末尾を固定した正規表現です。そのため、タイプミスによって意図より広い範囲のPAMエンタイトルメントに一致してしまうことを防げます。
  • 申請者のメールアドレスは、PAMの権限付与情報から埋め込まれます。ファイル内に特定の個人専用の設定はありません。

GitHubのチームへの追加も同じ形で、プロバイダーとリソースタイプが変わるだけです。一つ書けば、次は数分で書けます。

このファイルは、PAMのエンタイトルメント定義と並べてGitで管理しています。アクセス設計にも、他のインフラと同じ変更履歴、レビュー、CIが適用されます。

6. セキュリティ設計

6.1 常設権限を持たせないことを、ポリシーだけでなく構造で保証する

これは日々のセキュリティ対策にとどまらない重要な点です。監査、コンプライアンスの枠組み、内部統制では、いつも同じ二つのことが問われます。誰が何にアクセスでき、誰がそれを承認したのか。そして、もう必要のないアクセス権を持ち続けている人はいないか。誰も常時アクセス権を持たず、すべての権限付与が人によって承認・記録され、付与されたアクセス権が自動的に期限切れになるモデルなら、後から調査するのではなく、仕組みそのもので両方に答えられます。だからこそ私たちは、「常設権限を持たせない」ことを、設計全体で守るべき性質と位置付けています。

AIエージェントが私たちの環境で実際の仕事を始めた今、この重要性はさらに増しています。長期間有効な認証情報を持つコーディングエージェントや自動化パイプラインは、誰も確認していない入力に基づき、いつでも機械の速度でその認証情報を使えます。エージェントにふさわしいモデルは、人に求めるものと同じです。常時アクセス権を持たず、範囲を限定した権限付与を承認・記録したうえで、タスクに必要になった瞬間に取得し、タスクが終わったら手放す。アクセス権を持ち得る主体が増え、行動が速くなるほど、タスクのために権限を取得して終了後に手放すこと、そしてすべての権限付与を人や別のシステムが読める監査ログに残すことが重要になります。常設権限ゼロは、AI時代に向けた追加の強化策ではありません。そもそもエージェントを安全に受け入れるための前提です。

「作業が終わったらアクセス権を削除する」というポリシーは、人が覚えていることに依存します。私たちは、その保証をシステムから得たいと考えました。

  • アクセス権の期限が切れたときのデフォルトの動作は、権限を弱めることではなく、リソースを削除することです。データベースユーザーは降格するのではなく、削除します。
  • 有効期限なしでアクセス権を作成する設定項目はありません。恒久的なアクセス権を設定しようとしてもできません。
  • 多くの組織が残存権限を見つけるために行う定期的なアクセス権の棚卸しは、この経路では不要になります。見つけるべき残存権限がないからです。

6.2 障害が起きても、権限の取り消しを成功させる

この種のシステムで最も怖いのは、付与の失敗ではありません。付与に失敗すれば、利用者が気付いて再度依頼します。怖いのは、誰も気付かない取り消しの失敗です。何が壊れても権限の取り消しが行われるよう、複数の層で対策しました。

  • 配信の再試行。 期限切れイベントはPub/Sub経由で届きます。Tempuraが停止していれば、メッセージは待機し、再配信されます。
  • 繰り返しても安全。 同じイベントを二度処理しても問題ありません。リソースがすでに削除されていれば、二度目は何もしません。そのため、重複配信や再実行を安全に扱えます。
  • 自分の状態情報がなくても動く。 Tempuraは、作成したものをCloud Storageに記録します。その記録が欠落・破損していても、設定からリソース識別子を再構成して削除できます。状態の保存先を失っても、アクセス権が残ることはありません。
  • 失敗が見える。 処理できないイベントはデッドレターキュー(DLQ)に送られ、アラートが発生します。取り消しに失敗すれば、すぐに担当者が気付けます。アクセス権が黙って残り続けることはありません。

6.3 監査証跡を一つにする

申請、承認、Tempuraが作成したリソース、期限切れ時の削除まで、すべての段階がCloud Loggingに記録されます。PAMの権限付与と外部リソースはgrant ID(権限付与の識別子)でひも付いているため、「この人は先月、すべての製品を通じて何にアクセスできたのか?」という問いに、一つのログクエリで答えられます。

新しいログ基盤は必要ありませんでした。PAMは自動的にCloud Audit Logsへ書き込み、Tempuraは他のCloud Runサービスと同じようにCloud Loggingへ書き込みます。そのため、Google Cloud向けにすでに設定していた保持ポリシー、ログシンク、アラート、SIEMへの転送が、そのままSaaSへのアクセスもカバーします。追加や保守が必要なものはありません。

7. 特権アクセスをプラットフォームとして運用する

私たちはアクセス管理を、他のインフラと同じように扱っています。コードで定義し、レビューを通じて変更し、本番サービスと同じ信頼性のための実践を適用して運用し、開発者にはセルフサービスのプロダクトとして提供します。

開発者のためのセルフサービス。 私たちに頼まなくても使えてこそ、プラットフォームです。アクセス権が必要な開発者は、メニューからエンタイトルメントを選び、利用期間を指定して理由を書き、作業を進めます。そのアクセス権がどのコンソールにあるのか、どのAPIで作成されるのか、SREチームの誰に声をかけるべきかを知る必要はありません。Google Cloudのロールでも、データベースユーザーでも、GitHubのチームでも、画面は同じです。覚えることは一つだけで、次の申請まで記憶しておくこともありません。これは開発者体験の改善し、双方の認知負荷を下げます。申請者は製品ごとのアクセス管理方法を理解する必要がなくなり、その知識を頭の中に抱えていた運用担当者も、すべての申請に関わる必要がなくなります。

おわりに:新しいシステムではなく、足りない処理を作る

Tempuraを作ったのは、自分たちに必要だったからです。Google Cloudへのアクセスは以前から期限付きで承認制だったのに、同じくらい大きな被害につながり得るデータベースユーザーやGitHubのチームへの所属は、依然としてSlackで付与され、そのまま忘れられていました。それには違和感がありました。私たちは、すべてに同じルールを適用したかったのです。誰も常時アクセス権を持たず、すべての権限付与を人が承認し、付与されるすべてのアクセス権に期限があること。今ではSaaS製品へのアクセス申請も、Google Cloudのロール申請とまったく同じです。承認、本人確認、監査ログ、有効期限は、すべて既存の仕組みが担っています。Tempuraが加えるのは最後の処理だけです。権限付与が承認されたらアクセス権を作り、その有効期間が終了したら削除します。

根底にある考え方は小さなものですが、この記事で紹介したすべての判断を方向付けました。システムを追加する前に、すでにある仕組みを見て、本当に足りないものは何かを考える。私たちの場合、一つの申請窓口に必要な五つのうち、四つはすでにそろっていました。五つ目だけを作ることで、設計を小さく保ち、セキュリティ上の性質をすでに備えたシステムにその責任を委ねられました。そして、既存の監査証跡、サインインの流れ、Infrastructure as Codeのツールを変更せずに、新しいユースケースにも使えました。

このブログでは、私たちが開発しているレンダリングや地理空間データについて書くことが多いです。しかし、これらのサービスを運用しているのも同じ小さなチームであり、ごく少人数で安全に運用することも、同じくらい大切な課題です。今後も、作業を速くするだけでなく、適切な設計によって、ある種類の作業そのものをなくせる場所を探し続けていきます。

Japanese

Eukaryaでは様々な職種で採用を行っています!OSSにコントリビュートしていただける皆様からの応募をお待ちしております!

Eukarya 採用ページ

Eukarya is hiring for various positions! We are looking forward to your application from everyone who can contribute to OSS!

Eukarya Careers

Eukaryaは、Re:Earthと呼ばれるWebGISのSaaSの開発運営・研究開発を行っています。Web上で3Dを含むGIS(地図アプリの公開、データ管理、データ変換等)に関するあらゆる業務を完結できることを目指しています。ソースコードはほとんどOSSとしてGitHubで公開されています。

Re:Earth / ➔ Eukarya / ➔ note / ➔ GitHub

Eukarya is developing and operating a WebGIS SaaS called Re:Earth. We aim to complete all GIS-related tasks including 3D (such as publishing map applications, data management, and data conversion) on the web. Most of the source code is published on GitHub as OSS.

Re:Earth / ➔ Eukarya / ➔ Medium / ➔ GitHub