🛡️

Gemini Enterprise Agent Platform の「Managed Agents」に Cloud Run を運用させてみる

に公開

はじめに

Google Cloud の Managed Agents API に、Cloud Run のサービスを運用させました。Managed Agent API は Gemini Enterprise Agent Platform の Preview 機能です。今回、ログとメトリクスを読ませ、チューニング案を推測させ、実際に再デプロイまでさせています。

モチベーションは、Antigravity による運用自動化で、どこまでいけるのかを知りたかったというのがあります。こちら検証日は 2026 年 9 月 14 日で、閲覧されたタイミングでは異なる機能になる可能性があります。

先に結論

観点 結果
自然言語だけの運用サイクル(観測 → 判断 → 再デプロイ → 比較) 完走。p95 が 307.9ms から 9.5ms へ
MCP 経由での運用 不可。mcp_server を宣言すると対話が内部エラーで落ちる
Egress の絞り込み 不可。allowlist は * のみ受理し、API が明示的に拒否する
対話時の environment 指定 base_environment を上書きし、ネットワークが黙って無効になる
MCP の資格情報 GET agent でも一覧 API でも平文で返る
実行結果の監査 保存レコードには残る。SSE ストリームには流れない
Google 提供スキルのマウント 可能。ただし場所を伝えないと読まれない
コスト 6 ターンで約 134 万トークン。暴走した 1 ターンだけで約 70 万
  • 実用的な運用まで行けそう。要件を渡せば、観測・原因推定・変更・検証まで自分で回す。
  • 安全な口と思われる MCP が塞がっているため、Google Cloud を触らせるには egress 全開放と資格情報の持ち込みしか残らない。
  • 事故はセキュリティよりコストの形で出やすい。暴走した対話を止める API が無い。

1. Managed Agents API とは

単一の API で、自律的にコード実行・ファイル操作・外部通信・外部ツール接続をするエージェントを立ち上げる仕組みです。実行環境は Google 管理の Linux サンドボックス(Antigravity ハーネス)です。

  • 2 つの API: Agents API(設定)と Interactions API(実行)
  • サンドボックス: bash とコード実行、gcloud / git / python / node のプリインストール、7 日 TTL、ネットワークは既定で無効
  • 組込ツール: code_execution / filesystem / google_search / url_context
  • 外部連携: MCP(Model Context Protocol)と Skill Registry

参照: Managed Agents API on Agent Platform sandbox environment

Agent Runtime(ADK などのコードファースト)との違いは、認証の作り込みにあります。Agent Identity と auth manager の対応サービスは、Agent Runtime・Gemini Enterprise・Cloud Run の 3 つです。Managed Agents は列挙に入っていません。

参照: Agent Identity overview


2. Cloud Run のサービスを運用させる

用意したもの

検証対象は、外部サービスの呼び出しを 300ms の待ち時間で模した小さな Web サービスです。環境変数 CACHE_ENABLED を true にすると結果をメモ化し、待ち時間を省きます。

対象アプリの中核部分
def fetch_upstream(seed):
    """外部サービスの呼び出しを模す。待ち時間が主で、CPU は少しだけ使う。"""
    time.sleep(UPSTREAM_MS / 1000.0)
    digest = hashlib.sha256(str(seed).encode()).digest()
    for _ in range(WORK_UNITS):
        digest = hashlib.sha256(digest).digest()
    return digest.hex()[:16]


def handle(seed):
    if CACHE_ENABLED:
        with _lock:
            if seed in _cache:
                return _cache[seed], True
    value = fetch_upstream(seed)
    if CACHE_ENABLED:
        with _lock:
            _cache[seed] = value
    return value, False

Cloud Run 側は既定値から外した設定でデプロイしました。並行数 4、CPU 1、メモリ 512Mi、最大インスタンス 3 です。負荷は 20 並列・600 リクエスト・8 種類のシードで、変更前と変更後に同じ条件で流します。

エージェントの定義はこうです。ツールには MCP を入れていません。 宣言すると対話そのものが失敗するためです。切り分けは 4 章に書きます。

運用エージェントの定義
{
  "id": "cloudrun-ops-gcloud",
  "base_agent": "antigravity-preview-05-2026",
  "description": "Cloud Run ops via gcloud in sandbox",
  "system_instruction": "あなたは Cloud Run のサービスを運用する SRE です。渡された資格情報で gcloud と curl を使います。観測した生の出力を要約せずに示してから結論を述べます。指示されたコマンド以外は実行せず、サンドボックス自体の調査もしません。",
  "tools": [{ "type": "code_execution" }, { "type": "filesystem" }],
  "base_environment": {
    "type": "remote",
    "network": { "allowlist": [{ "domain": "*" }] }
  }
}

資格情報は、最小権限のサービスアカウントから発行した短命トークンです。付与したロールは run.admin / monitoring.viewer / logging.viewer / artifactregistry.reader の 4 つだけです。これをプロンプトに書いて渡し、サンドボックス内で CLOUDSDK_AUTH_ACCESS_TOKEN として使わせます。

これらを使って検証します。

Turn 1: 観測

投げたプロンプトです。資格情報はプロンプトの冒頭に置き、以降のターンでは環境変数として引き継がせます。

Turn 1 のプロンプト
次のアクセストークンで Google Cloud を操作してください(最小権限の SA・1 時間で失効)。
export CLOUDSDK_AUTH_ACCESS_TOKEN=<トークン>
export CLOUDSDK_CORE_PROJECT=<プロジェクト ID>

Cloud Run のサービス ops-target(リージョン asia-northeast1)の状態を観測してください。
次の 4 つだけを実行し、生の出力をそのまま貼ってください。
1) gcloud run services describe ops-target --region=asia-northeast1 --format=yaml(spec.template)
2) 直近 30 分のリクエスト数とレイテンシ分布:
   curl -s -H "Authorization: Bearer $CLOUDSDK_AUTH_ACCESS_TOKEN" \
     'https://monitoring.googleapis.com/v3/projects/<プロジェクト ID>/timeSeries?filter=metric.type%3D%22run.googleapis.com%2Frequest_latencies%22%20AND%20resource.label.service_name%3D%22ops-target%22&interval.endTime='$(date -u +%Y-%m-%dT%H:%M:%SZ)'&interval.startTime='$(date -u -d '30 minutes ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30M +%Y-%m-%dT%H:%M:%SZ)
3) 同じ期間の run.googleapis.com/container/instance_count
4) gcloud logging read 'resource.labels.service_name="ops-target" severity>=WARNING' --limit=10 --freshness=1h

結論は書かず、数値だけを表にしてください。

返ってきたのは生の数値です。

Turn 1 で返ってきたレイテンシ分布(抜粋)
"points": [
  {
    "interval": { "startTime": "2026-09-14T15:00:00.001Z", "endTime": "2026-09-14T15:01:00Z" },
    "value": { "distributionValue": {
        "count": "269",
        "mean": 305.6301261391298,
        "sumOfSquaredDeviation": 56260.497680588975
    } }
  }
]

Turn 2: 判断

原因の推定とチューニング案だけを出させます。UPSTREAM_MS を「外部要因なので変更してはいけない」と縛ったのは、外部サービスの遅さを直接消す逃げ道を塞ぐためです。

Turn 2 のプロンプト
前のターンの数値をもとに、レイテンシが悪い原因を推定し、チューニング案を出してください。
このアプリは次の環境変数を読みます。
  - CACHE_ENABLED (true/false, 既定 false): 外部サービスの呼び出し結果をメモ化する
  - WORK_UNITS (整数, 既定 2000): 1 リクエストあたりの計算量
  - UPSTREAM_MS (整数, 既定 300): 外部サービス依存の応答時間。外部要因なので変更してはいけません
Cloud Run 側の設定(CPU・メモリ・並行数)も変更できます。
変更前と変更後を並べた表を出し、p95 がどう動くと予想するかを 1 行で書いてください。
このターンではコマンドを実行しないでください。

返ってきた診断がこちらです。

Turn 2 で返ってきた文章
平均レイテンシが約 298〜306 ms であるのに対し、外部依存の応答時間 `UPSTREAM_MS` が 300 ms に設定されています。現在 `CACHE_ENABLED` が `false` であるため、すべてのリクエストがこの 300 ms の上流待ち時間に直接影響を受けています。

キャッシュを有効化して I/O 待ちを解消した場合、1 リクエストあたり `WORK_UNITS=2000` の計算量が発生するため、1 CPU(最大並行数 4)の設定では CPU の枯渇や割り当て待ちが新たなボトルネック(テールレイテンシの悪化)になる可能性があります。

注目すべき提案は、CACHE_ENABLED を true、CPU を 2、メモリを 1Gi、並行数を 80 にするというものでした。待ち時間を消すと CPU 律速に変わるという二段目まで読んでいます。禁止した UPSTREAM_MS には手を付けていません。

Turn 3: 適用

手段だけを指定し、値は前のターンの案に任せます。

Turn 3 のプロンプト
前のターンの案を適用してください。gcloud run services update を使い、
変更は環境変数と Cloud Run の設定だけにとどめます。
完了したら gcloud run services describe で新しいリビジョン名と設定を確認し、
変更前後を報告してください。

1 回目は失敗しました。

Turn 3 で返ってきたエラー
ERROR: (gcloud.run.services.update) PERMISSION_DENIED:
Permission 'artifactregistry.repositories.downloadArtifacts' denied on resource
'//artifactregistry.googleapis.com/.../repositories/cloud-run-source-deploy'

注目したのはこの後の挙動です。エージェントは gcloud run services replace でも試し、どちらも失敗すると、describe で変更が入っていないことを確認してから報告しました。

Turn 3 で返ってきた内容
デプロイ失敗(PERMISSION_DENIED)により、新しいリビジョンは作成されず、設定値は変更されていません。

Cloud Run が新しいリビジョンをデプロイする際に要求される Artifact Registry のダウンロード権限(`artifactregistry.repositories.downloadArtifacts`)が不足しているため、チューニング案の変更を適用できませんでした。

成功を装わず、不足している権限まで特定しています。roles/run.admin だけでは Cloud Run を更新できない、という実務的な発見でもあります。

権限を足し、同じ会話の続きとして投げ直しました。

再適用のプロンプト
Artifact Registry の読み取り権限を追加しました。前のターンで失敗した変更をもう一度適用してください。
gcloud run services update を 1 回だけ実行し、成功したら gcloud run services describe で
新しいリビジョン名と env・cpu・memory・concurrency を確認して報告してください。
失敗したらエラーをそのまま貼って止めてください。

新しいリビジョンが出ました。

設定項目 変更前 変更後
リビジョン名 ops-target-00001-hbj ops-target-00002-5zd
CACHE_ENABLED false true
CPU 1 2
メモリ 512Mi 1Gi
並行数 4 80

Turn 4: 比較

同じ条件で負荷をかけ直し、リビジョン別の p95 を取らせました。

リビジョン別の p95(エージェントが取得した生の出力)
2026-09-14T15:11:33Z ops-target-00001-hbj 308.0
2026-09-14T15:10:33Z ops-target-00001-hbj 307.9
2026-09-14T15:26:33Z ops-target-00002-5zd 9.6
2026-09-14T15:25:33Z ops-target-00002-5zd 9.5

手元から測った値も並べます。こちらは日本のクライアントから asia-northeast1 を叩いた往復時間を含みます。

計測 変更前 変更後
p50 520.6ms 54.2ms
p95 786.1ms 148.2ms
スループット 35.1 rps 292.7 rps
600 リクエストの所要 17.1 秒 2.1 秒

ここまでで分かったこと

観測から変更・検証まで、指示は自然言語だけで通りました。判断の質も実用に足ります。外部サービスの待ち時間が支配的だと見抜き、それを消した後に CPU 律速へ移ることまで予測し、実測でも裏付けが取れました。

ただし、2 つの意外な点が有りました。どちらも詳細は後に書きます。

1 つは、MCP でつなぐつもりが動かなかったことです。そのため egress を全開放し、サンドボックスの gcloud に資格情報を渡す形になりました。安全な口を使えないので、広い口を開けています。

もう 1 つは、対話時に environment を指定するとネットワークが黙って無効になることです。最初はこれに気づかず、エージェントが原因を探して 1 ターンで 70 万トークンを使いました。


3. Google 提供のスキルを入れる

Google は Cloud 向けのスキルを github.com/google/skills で公開しています。これの中には Google Cloud の Well-Architected Framework の SKILL が入っています。中身は SKILL.md(YAML フロントマターに name と description)と参照ドキュメントで、Skill Registry に登録すればサンドボックスへマウントできます。

cloud-run-basics と Monitoring 関連の 2 本を登録し、運用エージェントにマウントして比べました。

エージェントとスキルはロケーションが揃わない

Managed Agents は global にしか作れません。 一方 Skill Registry の対応リージョンは 3 つで、global は含まれません。us-central1 / europe-west4 / us-east5 です。どちらもドキュメントに書かれています。

参照: Create and manage skills

問題は、global を指定したときの落ち方です。リクエストは 200 で受理され、スキルのリソースも作られます。そのうえで非同期の取り込みが失敗し、state: FAILED になります。操作の結果は INTERNAL としか返らず、リージョンが対象外であることは読み取れません。Google が管理するビルトインの gcp-skill-registry まで global では FAILED のままでした。

global に登録したときの結果
cloud-monitoring-list-time-series-request  state=FAILED
cloud-monitoring-metric-selection          state=FAILED
cloud-run-basics                           state=FAILED
gcp-skill-registry                         state=FAILED   ← Google 管理のビルトイン

us-central1 に入れ直すと、同じ payload が ACTIVE になります。

us-central1 に登録した結果
cloud-monitoring-list-time-series-request    state=ACTIVE source=USER
cloud-monitoring-metric-selection            state=ACTIVE source=USER
ops-cloud-run-basics                         state=ACTIVE source=USER
gcp-skill-registry                           state=ACTIVE source=SYSTEM

プロジェクトで最初の登録は失敗する

us-central1 でも、最初の 1 本は INTERNAL で失敗しました。このとき、ビルトインの gcp-skill-registry も FAILED でした。しばらくして同じ内容を削除・再登録すると ACTIVE になり、以降の登録も通ります。

マウント先は target のとおりにならない

global のエージェントから us-central1 のスキルを指定できました。ロケーションが違っても参照できます。

エージェント定義のマウント指定
"base_environment": {
  "type": "remote",
  "sources": [
    { "type": "skill_registry",
      "source": "projects/<プロジェクト番号>/locations/us-central1/skills",
      "target": "/.agent/skills" }
  ],
  "network": { "allowlist": [{ "domain": "*" }] }
}

ただし実際の配置は指定と違います。サンドボックスの中を見ると、絶対パスではなくワークスペース相対に置かれていました。

サンドボックス内での確認
$ ls -la /.agent/skills
ls: cannot access '/.agent/skills': No such file or directory

$ find / -maxdepth 6 -name SKILL.md
/workspace/.agent/skills/cloud-monitoring-metric-selection/SKILL.md
/workspace/.agent/skills/gcp-skill-registry/SKILL.md
/workspace/.agent/skills/ops-cloud-run-basics/SKILL.md
/workspace/.agent/skills/cloud-monitoring-list-time-series-request/SKILL.md

マウントしただけでは使われない

同じ指示を 3 通りの条件で投げました。手順は書かず、「直近 30 分のレイテンシと稼働状況を調べてください。使うコマンドや API は自分で決めてください」とだけ伝えています。

条件を変えて 2 回まわしました。1 回目は直近 30 分にリクエストが無い時間帯(最後のアクセスは 17 時間前)、2 回目は 600 リクエストの負荷をかけた直後です。

条件 1 回目のトークン 2 回目のトークン スキルを読んだか
スキル無し 268,839 357,172 読まない
スキル有り・場所を伝えない 291,932 207,593 読まない
スキル有り・場所を伝える 200,690 390,258 読む(3 本)

一貫していたのは 1 点だけです。場所を伝えない限り、スキルは読まれません。 マウントしてあっても、2 回とも一度も参照していません。
もしかすると、現状 agy cli のような skill を自動で読み取るかたちになっていない可能性があります。

場所を伝えたときの最初の 7 ステップ
1. provision_sandbox
2. list_dir
3. view_file /workspace/.agent/skills/ops-cloud-run-basics/SKILL.md
4. list_dir
5. view_file /workspace/.agent/skills/cloud-monitoring-metric-selection/SKILL.md
6. list_dir
7. view_file /workspace/.agent/skills/cloud-monitoring-list-time-series-request/SKILL.md

トークンの増減は、この回数では判断できない

同じ条件でも 1 回目と 2 回目で 1.5 倍以上ぶれています。スキルを読ませると速くなるとも、遅くなるとも言えません。1 回ずつの比較で語れる差ではない、というのが正直なところです。

答えの中身は次のとおりでした。負荷をかけた 2 回目は、実測と突き合わせられます。

条件 2 回目の結論
スキル無し 613 件・エラー 0%・平均 11ms・p99 304ms(正しい)
スキル有り・場所を伝えない 615 件・成功率 100%・平均 11ms・p99 304ms(正しい)
スキル有り・場所を伝える 結論に到達せず。describe の生 JSON を貼っている途中で出力が切れた

手元の負荷生成側の記録は 600 リクエストで、ヘルスチェックを含めて 613〜615 件です。数字は合っています。

3 本目が失敗した形は、コストの節で触れる話と同じです。生の JSON を貼らせると出力が膨らみ、途中で切れます。

スキルを読んだ直後に打って失敗したコマンド
ERROR: (gcloud.monitoring) Invalid choice: 'time-series'.
Maybe you meant: gcloud monitoring dashboards list / gcloud monitoring policies list

入れるなら CLI 前提のスキルを選ぶ

リポジトリの skills/cloud/ 119 本を調べると、MCP に言及しないものが 72 本あります。言及する 47 本のうち 29 本は、MCP ツールの呼び出しを前提に書かれています。

Managed Agents では MCP が動かないため、選ぶ基準は gcloud や REST だけで完結するか になります。今回のシナリオなら次が候補です。

スキル MCP 必須の記述 gcloud への言及
gcloud 0 56
cloud-logging-configuration-basics 0 26
cloud-run-basics 0 19
cloud-run-alert-configuration 0 13
cloud-logging-query-generation 0 0(クエリ言語の知識のみ)
cloud-monitoring-metric-selection 3 0
cloud-monitoring-list-time-series-request 4 1

上 5 本はサンドボックスの gcloud だけで完結します。下 2 本が、今回そのまま入れてしまったものです。

入れる前のふるい分け
grep -L 'MCP tool' skills/cloud/*/SKILL.md   # MCP ツール前提でないものを列挙

4. 詰まった点

MCP は Preview では使えない

mcp_server を宣言したエージェントは、対話そのものが失敗します。 サンドボックスの provisioning 直後に内部エラーで落ちます。

GET interaction の保存レコード
{
  "status": "failed",
  "steps": [ { "type": "function_call", "name": "provision_sandbox", "arguments": { ... } } ],
  "errors": [ { "message": "Internal error encountered.", "code": "api_error" } ]
}

条件を変えて切り分けました。

条件 結果
mcp_server 無し(code_execution のみ) 成功
エージェント設定に直書き / 実行時に tools で注入 どちらも失敗
network 無効 / allowlist: * どちらも失敗
Cloud Run MCP / BigQuery MCP(ドキュメントの例)/ 外部の公開 MCP すべて失敗
認証ヘッダーあり / なし どちらも失敗
ストリーミング / 非ストリーミング どちらも失敗
MCP サーバーを直接 initialize と tools/call で叩く 成功

最後の行が効いています。https://run.googleapis.com/mcp は Streamable HTTP で正しく応答し、同じトークンで list_services も通ります。落ちているのは Managed Agents 側です。

Cloud Run MCP で何ができるはずだったか

認証なしの tools/list で、公開されているツールを確認できます。

エンドポイント ツール
logging.googleapis.com/mcp list_log_entries ほか 6 件(すべて読み取り)
monitoring.googleapis.com/mcp list_timeseries / query_range(PromQL)ほか 9 件(すべて読み取り)
run.googleapis.com/mcp get_service / list_services と、deploy_service_from_image などの書き込み 3 件

ただし deploy_service_from_image が受け取る Service は image / env / args / command / ports しか持ちません。CPU・メモリ・並行数を指定する場所が無いため、MCP が動いたとしても今回のチューニングは environment 変数の変更までしかできませんでした。

対話時の environment がネットワークを黙って消す

同じエージェント(allowlist: *)に、ほぼ同じ指示を出した結果です。

対話リクエスト 結果 消費トークン
"environment": {"type":"remote"} を指定 DNS 解決に失敗。gcloud がクラッシュ 698,991
environment を省略 名前解決も API 呼び出しも成功 29,092
environment を指定したときにサンドボックスで起きたこと
ERROR: gcloud crashed (ConnectionError): HTTPSConnectionPool(
  host='asia-northeast1-run.googleapis.com', port=443): Max retries exceeded
  ... Failed to resolve 'asia-northeast1-run.googleapis.com'
  ([Errno -3] Temporary failure in name resolution)

ドキュメントは「作成時に環境を定義していない場合は対話側で定義する」と書いています。定義してある場合に指定すると base_environment が置き換わり、network が失われます。エラーは出ず、外向き通信だけが止まります。

これのヤバいところが、エージェントが原因を探しに行ったことです。それ自体はまだいいのですが。/etc/passwd の確認、su appuser、setuid バイナリの列挙、sudoers の探索まで進み、1 ターンで 698,991 トークンを使っています。

暴走した対話を止める API が無い

上の約 70 万トークンのターンは、途中で止められませんでした。

キャンセルを試したときの応答
POST /v1beta1/.../interactions/{id}:cancel  → 404
DELETE /v1beta1/.../interactions/{id}       → 400
  "Interaction `...` is not finished yet. Please wait until it is completed or cancelled."

background: true は必須です。false にすると Agent interactions must set background to true. で弾かれます。いったん走り出した対話は、終わるまで待つしかありません。

サンドボックスにはコマンドの検閲がある

権限昇格を試みた過程で、拒否の挙動が観測できました。

サンドボックスが拒否したもの
Rejected: Invalid or unapproved sudo/apt pattern.
  Only 'sudo apt update' or 'sudo apt install <pkg>' without flags are permitted.
Rejected: Metacharacters are not allowed in privileged commands (sudo/apt).

sudo は存在しますが、パターンから外れる使い方は弾かれます。ドキュメントには見当たらない挙動です。


5. コスト

課金はモデルのトークン従量のみで、サンドボックスの計算に対する別課金は観測されませんでした。今回の運用デモ 6 ターンの実測がこちらです。

ターン 内容 トークン うちキャッシュ
Turn 1 観測 95,105 57,154
Turn 2 判断 28,821 0
Turn 3 適用(権限不足で失敗) 248,416 153,913
Turn 4 比較(生 JSON をそのまま扱わせた) 607,391 389,850
再適用 権限を足して適用 210,496 127,667
再比較 集計クエリに変更 149,638 71,860
合計 1,339,867 800,444

Turn 4 と再比較は同じ作業です。Monitoring の応答をそのまま読ませると 607,391 トークン、ALIGN_PERCENTILE_95 で集計させ値だけを出させると 149,638 トークンでした。出力の絞り方がそのまま課金に効きます。


6. 運用で気を付けること

運用させると、資格情報がどこに残り、実行結果がどこから取れるかが効いてきます。実測した観測と、そこから引く対策を並べます。

観測

# 観測
1 egress 許可は * のみ受理。ドメイン単位の最小化はできない
2 宣言ツールを絞っても bash 実行は残る
3 設定に書いた MCP の資格情報は GET agent でも一覧 API でも平文で返る
4 同じ env_id を知る別エージェントが同一サンドボックスに到達する(仕様)
5 プロンプトで渡した資格情報が保存レコードに平文で残る
6 実行結果は保存レコードに残るが、SSE ストリームには流れない

#1 はエラーメッセージまで確認しています。

ドメイン単位の allowlist を指定したときの応答
{
  "error": {
    "code": 400,
    "message": "Only domain: '*' is supported now. Found: `monitoring.googleapis.com`.",
    "status": "INVALID_ARGUMENT"
  }
}

#3 は、エージェント ID を知らなくても回収できます。GET /agents の一覧応答に、登録済みエージェントの headers がそのまま載ります。検証では実トークンではなく sentinel 文字列を入れて確認しました。

一覧 API の応答
"headers": {
  "Authorization": "Bearer SENTINEL-TOKEN-VALUE",
  "X-Goog-User-Project": "<プロジェクト ID>"
}

#6 は監査の材料がどこにあるかの話です。SSE ストリームには、ツール呼び出しの引数しか流れません。一方 GET interaction の保存レコードには、function_result として stdout・stderr・終了コードが残ります。実行結果を追うなら保存レコードを取ります。 裏返しとして、#5 のとおり渡した資格情報もそこに残ります。

ここまで踏まえて気を付けること

外部通信と資格情報

  • 外部通信は本当に必要なときだけ有効にする。現状有効化は全開放を意味する
  • egress を絞れないため、ちゃんとやるなら VPC Service Controls・出口プロキシ・専用プロジェクトで隔離する
  • 渡す資格情報は専用・最小権限・短命にする。保存レコードに平文で残ることを前提に選ぶ
  • 設定に MCP の資格情報を直書きしない。一覧 API で誰にでも読まれる

権限境界とデータ

  • 「read-only エージェント」を宣言ツールだけで作ったつもりにならない
  • 付ける権限は用途ぴったりに切る。Cloud Run の更新なら run.admin と artifactregistry.reader
  • env_id を信頼境界の越しに共有しない。使い捨てにする
  • マウントするデータとスキルは出所を限定したうえで内容を検証する

監査と事故

  • 監査は GET interaction の function_result を取る。SSE ストリームには結果が流れない
  • 予算上限とアラートを先に設定する。暴走した対話を止める API は無い
  • Preview 規約を守る。本番データ・専有データ・機微データを載せない

おわりに

環境を Google Cloud に統一しつつ、Skill など管理ができれば有用に使えそうだと思いました。とはいえまだ Preview で使えない微妙な機能が多い印象です。今回書いてないですが、たとえば scm などのコード管理をどうするか、Secret Managerに置いて取得するか?

  • Mamaged Agent API運用させる能力は実用段階にある。観測から原因推定、変更、検証までを自然言語の指示だけで回せた。失敗したときに成功を装わない点も含めて、任せられる水準。
    • cloud assist もある。Gemini Enterprise から Agent Runtime を通して起動できると( https://adk.dev/agents/managed-agents/ )、できることの幅はさらに広がる可能性がある。こちらちょっと次のネタにしておきます。
  • ただし今は、安全に渡す口が無い。MCP が動かないため、egress 全開放と資格情報の持ち込みが前提になる。
  • 事故はセキュリティよりコストの形で出る。設定ミス 1 つで 1 ターン 70 万トークンが飛び、止める手段が無い。

Discussion