そのほかの運用上の制御
ほかのページに入らない、配備を守るための制御をまとめます。どれも、設定を誤ると気づかないうちに守りが弱くなるものです。
| 制御 | あなたがやること |
|---|---|
| プレビュー用ドメイン | 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 でサインインする)
監査ログを読む
Section titled “監査ログを読む”audit_logに残るのは、変更と破壊的な操作だけです。読み取りは残しません(例外は、メンバーのエージェントメモリの書き出し)- ターミナルの生のストリームは、秘密が混じるおそれがあるので保存しません
- 配備管理者とテナント管理者が 管理 > 監査 で読みます(監査ログを見る)
ベンダーの同じ機能をわざと止めている
Section titled “ベンダーの同じ機能をわざと止めている”Claude Code 自身のセッション間のメッセージ(/list-agents・SendMessage)は、有効にすると Claude 側への利用統計(telemetry)の送信も戻る作りです。そのため、セルフホストの既定では無効のままにしています。
- 同じ用途は Agent Fleet の セッション間メッセージ(設定 > エージェント、既定はオフ)が担います。届け先と帰属はこちらで制御し、届くのは同じワークスペースの中だけで、受け取った側には「利用者の指示ではない」と示します
- メンバーから「
/list-agentsが使えない」と言われたら、故障ではなくこの判断です
秘密をログに出さない
Section titled “秘密をログに出さない”- 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 の再起動では変わりません。
- Control Plane とワークスペースのイメージを更新します(
AF_WS_WORKLOAD_AWSを変えたときも同じです) - すべてのワークスペースを Console で停止してから起動します。コンテナが作り直されます
- 上の表のホストの設定を適用します
- セッションのシェルから、環境を表示せずに確かめます(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 を読んで