コンテンツにスキップ

そのほかの運用上の制御

ほかのページに入らない、配備を守るための制御をまとめます。どれも、設定を誤ると気づかないうちに守りが弱くなるものです。

制御 あなたがやること
プレビュー用ドメイン Console とは別の登録可能ドメインに置く
サインインの許可リスト 外す人はリストから消す。空のままだと誰も入れない
IdP ごとの信頼の宣言 AF_OIDC_<ID>_TRUST を必ず書き、Entra ID は自社のテナントに固定する
ホストのクラウドの身元 ワークスペースからメタデータのエンドポイントに届かないようにする
監査ログ 管理 > 監査 で、変更と破壊的な操作を追う

プレビュー用ドメインを別のドメインに置く

Section titled “プレビュー用ドメインを別のドメインに置く”

サインインの cookie は SameSite=Lax で、兄弟のサブドメインは同じサイトと扱われます。Console と同じドメインの下のプレビューから配ったページも、メンバーの cookie を付けて Console にリクエストできます。

Control Plane は次の安全網を持っています。

  • cookie で認証した書き込みのうち、Sec-Fetch-Site が same-origin でないもの、Origin が Console 自身のホストでないものを 403 で拒みます
  • /api/ の本文に application/json(アップロードは multipart/form-data)を求めます
  • X-Frame-Options: DENY と frame-ancestors 'self' を返し、Console のシェルには script-src 'self'(同じオリジンのスクリプトだけ、インラインなし)を付けます

より強いのは、AF_PREVIEW_DOMAIN を別の登録可能ドメインに置くことです(Console が af.example.com、プレビューが *.af-preview.example.net)。cookie がそもそも送られなくなります。

  • cookie の名前は af_session で、__Host- の接頭辞はまだ付きません。__Host- の名前は今は選べません
  • AUTH=proxy の背後では、ゲートウェイが Host をそのまま渡すか、PUBLIC_BASE_URL に公開のホストを設定します。Origin を照らし合わせる相手がそれだからで、WebSocket の接続と同じ条件です

サインインの許可リストを保つ

Section titled “サインインの許可リストを保つ”
決まり 中身
空なら誰も入れない AF_OAUTH_ALLOWED_* の 3 種類がすべて空で、メンバーシップを持つ人も自動参加のドメインもないと、すべてのサインインを拒みます
再起動なしで効く _EMAILS_FILE はサインインのたびに読み直すので、足すのも消すのも Control Plane の再起動なしに効きます
毎リクエストで確かめる サインインのときだけでなく、リクエストのたびに確かめます。リストから外した人は、AF_SESSION_TTL を待たずに次のリクエストで締め出されます
招待もサインインの資格になる 管理画面でテナントに追加された人は、AF_OAUTH_ALLOWED_* になくてもサインインできます。招待で運用する配備では、名簿がメンバーシップの 1 か所に寄ります

入り口を通っても、どこかのテナントに入れるとは限りません。メンバーシップのない人は「管理者に依頼してください」の画面で止まります。 設定は インストールする、外し方は アクセスを取り消す にあります。

IdP ごとに、メールアドレスを信じる理由を宣言する

Section titled “IdP ごとに、メールアドレスを信じる理由を宣言する”

許可リストはメールアドレスで書くので、IdP が返すアドレスをなぜ信じてよいかが、認可の強さそのものになります。

  • AF_OIDC_<ID>_TRUST(email_verified か issuer)は必須です。宣言のない IdP は、起動時に無効になります
  • Entra ID の issuer は、自社のテナントの GUID に固定してください。/common/ や /organizations/ では、Microsoft のアカウントを持つ誰もがサインインの画面まで進め、個人のアカウントは自分のメールアドレスを付け替えられます
  • そのため、/common/ などの issuer では、AF_OIDC_<ID>_ALLOWED_TIDS がない限り Control Plane は起動しません(Microsoft Entra ID でサインインする)
  • audit_log に残るのは、変更と破壊的な操作だけです。読み取りは残しません(例外は、メンバーのエージェントメモリの書き出し)
  • ターミナルの生のストリームは、秘密が混じるおそれがあるので保存しません
  • 配備管理者とテナント管理者が 管理 > 監査 で読みます(監査ログを見る)

ベンダーの同じ機能をわざと止めている

Section titled “ベンダーの同じ機能をわざと止めている”

Claude Code 自身のセッション間のメッセージ(/list-agents・SendMessage)は、有効にすると Claude 側への利用統計(telemetry)の送信も戻る作りです。そのため、セルフホストの既定では無効のままにしています。

  • 同じ用途は Agent Fleet の セッション間メッセージ(設定 > エージェント、既定はオフ)が担います。届け先と帰属はこちらで制御し、届くのは同じワークスペースの中だけで、受け取った側には「利用者の指示ではない」と示します
  • メンバーから「/list-agents が使えない」と言われたら、故障ではなくこの判断です
  • Control Plane は認証情報の平文を持たず、解釈もせず、ログにも出しません
  • 共通の credential helper がそのつど復号して渡すので、git とプロバイダの認証情報は平文のファイルになりません
  • 例外は MCP サーバーの秘密です。エージェントの CLI の設定ファイルに、home の中で平文(0600)で書かれます(MCP と外部接続のサインインを運用する)

ワークスペース内のブラウザを引き渡す

Section titled “ワークスペース内のブラウザを引き渡す”

エージェントは、ワークスペースの中で自分が起動した Chromium のページを、Console のペインとしてメンバーに引き渡せます。ログインの操作などを人にしてもらうためです。

  • remote debugging はループバックにだけ開きます
  • 引き渡した直後は「閲覧のみ」で、メンバーの入力を一切通しません。操作させるには、明示的に「ユーザー操作」へ移します
  • CDP のエンドポイントや cookie を、回答・ログ・コミットに出さないことは、エージェントへの指示にも書いてあります

ワークスペースにホストのクラウドの身元を渡さない

Section titled “ワークスペースにホストのクラウドの身元を渡さない”

ワークスペースのコンテナは、それが動くマシンのメタデータのエンドポイント(169.254.169.254)に届くことがあります。 メンバーの認証情報を持たない AWS SDK は、そこで見つけたロールに気づかないうちに切り替わります。インスタンスプロファイルを持つ EC2 のホストなら、すべてのセッションが、エラーも出さずにそのロールになります。

Control Plane は、SDK がメタデータを問い合わせないようにします。

  • docker と Kubernetes: ワークスペースを AWS_EC2_METADATA_DISABLED=true 付きで起動します
  • ECS: タスクロールを外したうえで、同じ変数を立てます

ネットワークで遮るのはホストの役目です。

ホスト やること
compose 用の EC2 ホスト(deploy/aws/ec2-single) IMDSv2 とホップ数 1(HttpTokens: required・HttpPutResponseHopLimit: 1)。ホストのネットワークの Control Plane は 1 ホップなのでインスタンスプロファイルを使え、docker のブリッジ上のワークスペースは 2 ホップなのでトークンを得られません。既存のインスタンスには、スタックの更新ではなく、動いているインスタンスに直接適用します(コマンドは ec2-single の手順書)。Ubuntu の AMI のパラメータが進んでいると、スタックの更新でインスタンスが作り直されることがあります
クラウドの上のそれ以外の docker ホスト 同じメタデータの設定か、Docker の DOCKER-USER チェーンでワークスペースのブリッジからの 169.254.169.254 を拒むファイアウォールの規則。ホストの root が要ります(compose 自体に新しい権限は要りません)
Kubernetes この変数は、クラスタのメタデータサーバー(ノードのサービスアカウント、GKE では Workload Identity)を塞ぎません。NetworkPolicy の egress の規則か GKE のメタデータの隠蔽で、クラスタの側で塞ぎます。Control Plane はこれをしません
ecs-ec2 スロットのユーザーデータが ECS_AWSVPC_BLOCK_IMDS=true を設定します。古いスロットは、管理 > スロット で入れ替えを予約します(スロットを入れ替える・止める)
native ワークスペースはメンバーのマシンで直接動くので、そのままにします。そこのインスタンスロールは、そのマシン自身のものです

ワークスペースにタスクロールを渡すとき

Section titled “ワークスペースにタスクロールを渡すとき”

Control Plane に AF_WS_WORKLOAD_AWS=1 を設定すると、ECS のタスクロールをワークスペースに戻し、SDK のメタデータの問い合わせを止めるのをやめます。

  • 上のネットワークの防護はどれも外れません。docker のワークスペースがホストのインスタンスプロファイルに届くことはありません
  • それを渡すには、別に許した認証情報の経路が要ります。既定では、ネットワークの防護を保ってください

動いている docker のワークスペースは、作られたときの環境を保ちます。docker compose up -d や Docker の再起動では変わりません。

  1. Control Plane とワークスペースのイメージを更新します(AF_WS_WORKLOAD_AWS を変えたときも同じです)
  2. すべてのワークスペースを Console で停止してから起動します。コンテナが作り直されます
  3. 上の表のホストの設定を適用します
  4. セッションのシェルから、環境を表示せずに確かめます(3 つの確認は ec2-single の手順書)
確認 AF_WS_WORKLOAD_AWS がオフ(既定) AF_WS_WORKLOAD_AWS=1
変数 true を示す docker では変数がない
プロファイルなしの AWS の呼び出し 「Unable to locate credentials」で失敗する ECS ではタスクロールが解決される
IMDSv2 のトークンの要求 成功しない ホストがメタデータを遮っている所では、やはり失敗しなければならない

メンバーは af-aws-exec で、自分として AWS のコマンドを動かします(af-aws-exec)。

エージェント向け

この指示をエージェントに送ると、このページを読ませられます。

https://agent-fleet.org/docs/ja/operate/secure/controls/index.md を読んで