はじめに
株式会社AJA でバックエンドエンジニアをしている片山です。
AJA DSP では、Google Cloud や Kubernetes を中心とした技術スタックで、動画広告配信の DSP サーバーを開発しています。開発では AI エージェントの活用が進み、コードを書くところから調査、レビュー、オペレーションの補助へと、任せる範囲も少しずつ広がってきました。
AI エージェントに強い権限を与えるほど任せられる範囲は広がりますが、同時に誤操作が起きた際の影響範囲も大きくなります。AI エージェントが人間の認証情報を使って操作する場合、コマンドはその人が持つ権限の範囲で実行されます。そのため、対象プロジェクトの取り違えや判断ミスがあると、意図せず本番環境の破壊につながるリスクがあります。だからこそ、プロンプトだけでなく、実行権限も管理する必要性が高まりました。
そこで AJA DSP では、本番環境で定常的に付与していた強い権限を見直し、変更が必要なときだけ一時的に昇格する Google Cloud の Privileged Access Manager(PAM) へ移行しました。
今回は PAM への移行理由、権限設計、Terraform での管理方法、導入後にみえた課題を紹介します。
これまでの権限管理と課題
AJA DSP では、社内の ID・グループ管理基盤と Google Cloud の Identity and Access Management(IAM)を連携し、チームや職種ごとの Google グループに IAM ロールを紐づけていました。利用者は必要な Google グループへ参加することで、対応する権限を利用する仕組みです。
従来の本番環境では、Editor/Admin グループに roles/editor やサービスごとの Admin ロールを付与していました。ロールを取得した後は、参照と変更の両方を実行でき、操作ごとの申請は不要でした。
この運用は、人間が操作内容を判断し、自分でコマンドを実行することを前提としていました。AI エージェントに同じ認証情報を使わせると、IAM が許可する操作は変わらないまま、コマンドの選択と実行を AI エージェントに委ねる場面が生まれます。
AI エージェントの活用が浸透していく過程で、従来の権限設計には次の課題がありました。
- AI エージェントが人間の IAM 権限をそのまま利用できる
- プロンプトだけでは振る舞いを完全に制限できない
- 汎用的な Editor/Admin ロールでは、作業に不要な権限も利用でき、利用時間も作業単位で制限できない
また社内でも、ローカル環境で「不要なファイルを削除して」と依頼しただけなのに、意図より広い範囲の削除が走ってしまい、環境が壊れて復旧が必要になった例がありました。人間同士なら会話の補完で防げる場面でも、AI エージェントに実行まで委ねると「解釈のズレ」がそのまま実害になります。
さらに最近は、AI エージェントが意図に反して攻撃的・逸脱的な行動を取ってしまうリスクも指摘されています。提供側がどれだけ対策していてもゼロにはできない以上、利用する企業側でも「できてよい操作」を権限設計で明確に区切り、技術的なガードレールを敷く必要があります。
Privileged Access Manager とは
Google Cloud の PAM は、必要なときだけ一時的に権限を付与する Just-In-Time(JIT)権限昇格の仕組みです。
PAM では、付与する権限の単位を entitlement として定義し、申請できる利用者、IAM ロール、最大利用時間、申請理由、承認フロー、通知先を設定します。
利用者が grant を申請し、承認を得ると IAM ロールが一時的に付与されます。期限後は自動剥奪され、申請から付与までのイベントは Cloud Audit Logs に記録されます。
実際に利用する際は、コンソールから権限付与の期間と理由をセットで申請します。また、プレビュー機能ではありますが、将来の利用を見越した事前申請を「付与をスケジュール」から行うこともできます。

PAM 移行後の権限設計
利用者と承認者は従来どおり Google グループで管理し、書き込み・管理権限は作業目的ごとの entitlement として PAM から一時付与する構成にしました。作業に不要な権限を付与せず、必要な時間だけ利用できるようにするためです。
| 観点 | 移行前 | 移行後 |
|---|---|---|
| 利用者・承認者の管理 | Google グループ | Google グループ |
| 定常権限 | Editor/Admin とサービスごとの Admin ロール | Viewer+最低限必要な参照・実行権限 |
| 書き込み・管理権限 | グループにまとめて紐づけ | 作業目的ごとの PAM entitlement |
| 権限を持つ時間 | ロール利用中は継続 | 申請した時間だけ。最大24時間 |
| 強権限の利用開始 | 任意のタイミングで可能 | 理由を入力して申請し、管理者が承認 |
| 記録 | 各サービスの操作ログなど | 操作ログに加えて PAM の申請・承認履歴 |
全体の流れは以下のようになります。

Terraform で entitlement を管理する
AJA DSP では、PAM の entitlement も Terraform で管理しています。以下は、データベースのマイグレーション用 entitlement を簡略化した例です。
locals {
entitlements = {
spanner-migration = {
max_request_duration = "86400s" # 最大24時間
role_bindings = [
{ role = "roles/spanner.databaseAdmin" },
]
}
}
}
resource "google_privileged_access_manager_entitlement" "this" {
for_each = local.entitlements
entitlement_id = each.key
location = "global"
parent = "projects/${var.project_id}"
max_request_duration = each.value.max_request_duration
requester_justification_config {
unstructured {}
}
eligible_users {
principals = ["<group:engineers@example.com>"]
}
privileged_access {
gcp_iam_access {
resource = "//cloudresourcemanager.googleapis.com/projects/${var.project_id}"
resource_type = "cloudresourcemanager.googleapis.com/Project"
dynamic "role_bindings" {
for_each = each.value.role_bindings
content {
role = role_bindings.value.role
}
}
}
}
approval_workflow {
manual_approvals {
require_approver_justification = true
steps {
approvals_needed = 1
approver_email_recipients = ["pam-approvals@example.com"]
approvers {
principals = ["<group:platform-admins@example.com>"]
}
}
}
}
}
locals に最大利用時間と IAM ロールをまとめ、用途ごとの entitlement を追加できるようにしています。
approver_email_recipients には、Slack チャンネルのメールアドレスを設定しています。これによって Google Cloud から送信される承認依頼メールを Slack へ転送し、個人の受信トレイに分散することを防いでいます。
PAM への移行手順
強権限を先に削除すると、既存の運用に必要な操作まで実行できなくなる可能性があります。そこで、PAM で代替手段を用意した後に Editor/Admin 権限を外す順番で、段階的に移行しました。
1. PAM を有効化し、最初の entitlement を Terraform 管理にする
まず PAM API とサービスエージェントを設定し、手動で作成していたデータベースマイグレーション用の entitlement を Terraform へ import しました。この entitlement で、申請から自動剥奪までの動作を確認しました。
2. 既存の運用を作業目的ごとに棚卸しする
次に、データベースマイグレーション、BigQuery の更新、データ処理基盤のデプロイ、GKE の変更などに entitlement を分けました。既存の Admin ロールを一つの entitlement へ置き換えると権限範囲が変わらないため、作業ごとに必要な IAM ロールを見直しました。
3. チームへの説明会・勉強会を実施する
チーム(Backend/ML/DS)それぞれに説明会・勉強会を実施し、PAM の狙い(定常権限の縮小と JIT 昇格)と、申請〜承認〜自動剥奪までの一連の流れを共有しました。
そのうえで、「定常で必要な権限」を各チームとすり合わせて決めています。特に ML/DS などクラウド運用の経験が浅いメンバーでも、まずは調査・検証を自力で進められる状態を作ることを重視し、Viewer をベースに、日常的に必要な参照・実行権限(例:ログ閲覧、クエリ実行、ジョブ再実行など)を残し、環境変更・管理系の権限は PAM の entitlement に寄せる方針に揃えました。
4. 本番環境の定常権限を縮小する
各作業を PAM でカバーした後、Editor/Admin グループから強権限を外しました。Viewer、BigQuery のクエリ実行、Spanner の参照、ジョブの再実行などは定常権限に残し、環境の変更に必要な権限を PAM へ移しました。
PAM に移行して得られたこと
PAM 移行後は、もちろん書き込み・管理操作を定常権限では実行できません。目的と利用時間を申請し、管理者の承認を得た後だけ、強権限が付与されます。
entitlement 名によって申請者と承認者が作業目的を共有できます。これは単に「強い権限を止める」だけでなく、なぜその作業が必要なのかを申請フローの中で言語化し、チーム内で共通理解を作る効果もありました。
また、AI エージェントによる本番環境への一次調査が増えるにつれ、”調査はできるが変更はできない”という境界を明確にできたことは大きいです。これによって、誤操作で本番を壊してしまう不安が和らぎ、エンジニアが落ち着いて調査・判断できる状態(心理的な安全性)に繋がりました。
さらに、権限申請の際に「実はその作業に不要な権限を申請している」「申請せずとも別経路で目的を達成できる」ケースが可視化されます。特に、新しく参加したメンバーが権限体系や代替手段を把握しきれていない状態で過剰な申請をしてしまうのを、承認プロセスの中で止められるようになりました。結果として、申請理由・承認コメント・entitlement の粒度が、そのままナレッジとしてチームに蓄積されていきます。

Slack 通知が生んだ「承認競争」文化
PAM の承認依頼メールを Slack へ転送し、申請者、entitlement、IAM ロール、対象リソース、利用時間、承認画面へのリンクをチームで共有しています。
運用を始めると、通知に気づいたメンバーがすぐに反応し、いつの間にか「誰が一番早く承認するか」という謎の文化が生まれました。

導入後にみえた課題
以下の画像のように Slack 通知には申請理由が表示されず、確認と承認には Google Cloud Console への移動と認証が必要です。通知には気づきやすくなりましたが、承認判断に必要な情報と操作は Google Cloud Console に残っています。そのため、実際に運用する中で、Slack からブラウザへ遷移して操作するのが煩わしかったり、モバイル端末からは操作しにくいといった点が見えてきました。

まとめ
AJA DSP では、AI エージェントの活用拡大を見据え、定常的に付与していた強権限を PAM による JIT 権限昇格へ移行しました。強権限を作業目的ごとに分け、理由、承認、有効期限を設けることで、AI エージェントが実行できる操作に IAM の境界を設けています。また、AWS を利用している AJA SSP でも、TEAM (Temporary Elevated Access Management) による JIT 権限の導入を進めています。
また、運用を通して AI エージェントに自由を与えるほど、得られる便利さとリスクは表裏一体だと改めて感じました。安心して任せられる環境は、特別な裏技で突然手に入るものではなく、権限設計や運用ルールの整備といった「当たり前」を一つずつ積み重ねた先にあるのだと思います。権限管理に関しても、AI エージェントが登場したから必要になったというより、潜在的な課題が改めて顕在化したところが大きいです。
