generate-sandbox-policy について
自然言語の要件や API ドキュメントから、サンドボックスのネットワークポリシー YAML を生成するエージェントスキルです。アプリケーションの通信範囲を定める用途向けで、ホスト単位からエンドポイント単位の L7 ルールまで扱い、ミドルウェア設定も出力できます。
主な機能
- 01要件に応じた粒度でポリシーを生成
- 02L4 と L7 のルールに対応
- 03API ドキュメントからエンドポイントルールを作成
- 04ネットワークミドルウェア設定を出力
- 05範囲の確認とポリシー検証をガイド
活用シーン
- 01バイナリに読み取り専用 API アクセスを設定
- 02既知のパスで HTTP メソッドを制限
- 03OpenAPI ドキュメントからエンドポイントルールを生成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nvidia/ openshell --skill generate-sandbox-policyインストール後、Claude Code で/generate-sandbox-policyを入力して読み込まれたか確認します。
同梱ファイルexamples.md
詳細
サンドボックスポリシーの生成
API ドキュメントと自然言語によるユーザー要件から、YAML 形式のサンドボックスネットワークポリシーとネットワークミドルウェア設定を生成します。
概要
このスキルは、ユーザーが自然言語で記述したポリシーの意図を、有効なサンドボックスポリシーに変換します。ユーザーが提供する詳細度によって、生成されるポリシーの粒度が決まります。ホストとポートだけの広範な L4 ポリシーまたはプリセットベースのポリシーから、API ドキュメントをすべて使用したエンドポイント単位の細かな L7 ルールまで対応します。
出力は、network_policies YAML ブロック、任意の network_middlewares ブロック、そしてサンドボックスポリシースキーマに準拠したポリシーファイル一式(任意)です。
ステップ 1:入力の収集
詳細度の判定
ユーザーの入力は、次の 3 つの段階に分かれます。ユーザーが提供した情報を使って作業し、必要以上に高い段階の情報を求めないでください。
| 段階 | ユーザーが提供する情報 | 生成できるもの |
|---|---|---|
| 最小限 | ホストと自然言語による意図 | L4 のみのポリシー、またはアクセスプリセット(read-only、read-write、full)を使用した L7 ポリシー |
| 中程度 | ホストと既知の URL パスまたはリソース | 既知のパスを対象とする L7 の glob ルールと、その他のパスに対するプリセット |
| 完全 | API ドキュメント一式(OpenAPI、Swagger、Markdown、URL) | メソッドとパスの具体的な組み合わせを指定する、エンドポイント単位の細かな L7 ルール |
最小限の段階(ホストと意図のみ)
ユーザーが API エンドポイントと大まかな意図を提供します。API ドキュメントは不要です。
例:
- 「curl から api.github.com へのアクセスを読み取り専用で許可」
- 「claude に api.anthropic.com へのフルアクセスを許可」
- 「/usr/bin/myapp から internal-svc:8080 への通信を許可。ただし読み取りのみ」
この情報で、次のポリシーを生成できます。
- L4 のみのポリシー(ホストとポート、およびバイナリのチェック。メソッドやパスのルールなし)
- プリセットベースの L7 ポリシー(すべてのパスに対する
read-only、read-write、full)
この段階では、次のように設定します。
- ユーザーが「read」、「browse」、「view」、「query」、「fetch」と言った場合は、デフォルトで
access: read-onlyにします。 - ユーザーが「read-write」、「create」、「update」と言った場合(「delete」は含みません)は、デフォルトで
access: read-writeにします。 - ユーザーが「full access」、「everything」、「unrestricted」と言った場合は、デフォルトで
access: fullにします。 - ユーザーが「そのまま許可」、「通過させる」、「検査しない」と言った場合は、L4 のみのポリシーにします。明示的プロキシを使用するクライアントでは
protocolを省略します。ワークロードがネイティブ DNS と直接のソケット呼び出しを使用する必要があり、エンドポイントに有効な DNS ホスト名があり、選択したランタイムが対応している場合(現在は Docker と Podman)のみ、protocol: tcpを指定します。
中程度の段階(ホストと部分的なパス情報)
ユーザーは API パスを一部把握していますが、ドキュメント一式は持っていません。
例:
- 「integrate.api.nvidia.com で /api/v1/models への GET と /api/v1/completions への POST を許可」
- 「api.github.com の /repos/** は読み取り専用にする。ただし /repos///issues への POST も許可」
判明しているパスには明示的な rules を生成します。特定のパス以外にも広い範囲でアクセスを許可する場合は、キャッチオールルールと組み合わせるか、代わりにプリセットを提案します。
完全な段階(API ドキュメント一式)
ユーザーが API ドキュメント一式を提供します。対応する形式は次のとおりです。
| 形式 | 取り込み方法 |
|---|---|
| URL | エージェントのウェブアクセスを使って取得し、エンドポイント一覧を解析します。 |
| ファイルパス | ファイル(OpenAPI JSON/YAML、Markdown など)を読み込みます。 |
| 貼り付けられたテキスト | 会話内のテキストをそのまま解析します。 |
| OpenAPI/Swagger 仕様 | すべてのメソッドとパスの組み合わせについて、paths オブジェクトを抽出します。 |
API ドキュメントから、(method, path, description) タプルの一覧であるエンドポイントインベントリを作成します。リソースやタグなどに基づいて論理的に分類します。その後、ユーザーの意図に必要なものだけを許可する、正確なルールを生成します。
ポリシーの目的
ティアにかかわらず、ユーザーの説明から以下を抽出(または推測)します。
| 項目 | 特定する内容 | 必須? |
|---|---|---|
| スコープ | API のホストとポート | はい — 常に必要です |
| アクセスレベル | 大まかな意図:読み取り専用、読み書き、フル、またはカスタム | はい — 不明な場合は確認します |
| メソッド | 許可する具体的な HTTP メソッド | カスタム/きめ細かな設定の場合のみ |
| パス | 具体的な URL パスまたはパターン | カスタム/きめ細かな設定の場合のみ |
| 適用モード | enforce または audit? デフォルトは enforce です。 | いいえ — デフォルトがあります |
| バイナリ | アクセスを許可するバイナリ/プロセス | はい — 記載がなければ確認します |
| ミドルウェア | 許可された HTTP リクエスト、最終的な HTTP レスポンス、またはクライアントの WebSocket テキストメッセージに、組み込みまたはオペレーター実行の処理段階が順番に必要かどうか | いいえ |
ホストとアクセスレベルは明確でも、バイナリが指定されていない場合は、リクエストを行うバイナリまたはプロセスをユーザーに尋ねます。/usr/bin/curl、/usr/local/bin/claude など、一般的なデフォルトを提案します。
ステップ 2:スコープを絞り込む(確認ループ)
ポリシーを生成する前に、ポリシーのスコープをできるだけ狭められるよう、積極的に確認の質問をします。目的は、ユーザーのニーズを満たしつつ、最も制限的なポリシーにすることです。
必須の確認事項
ユーザーがすでに指定していない場合は、以下について必ず質問します。
| 不足している情報 | 質問する内容 |
|---|---|
| バイナリが未指定 | 「これらのリクエストを行うバイナリまたはプロセスはどれですか?(例:/usr/bin/curl、/usr/local/bin/claude)」 |
| ポートが未指定 | 「この API が使用するポートは何ですか?(HTTPS では通常 443 です)」 |
| 適用モードが未指定 | 「ポリシー違反をブロック(enforce)しますか、それとも確認用にログへ記録(audit)するだけにしますか?判断がつかない場合は、デフォルトで enforce にします。」 |
スコープを絞り込むための質問
ユーザーの意図が広範で、さらに具体化できる場合は、以下を質問します。
| ユーザーの発言 | 絞り込むための質問 |
|---|---|
| 「フルアクセス」/「すべてを許可」 | 「DELETE アクセスも本当に必要ですか? それとも DELETE 以外のすべてを許可する読み書きで十分ですか?」 |
| 「api.example.com へのアクセスを許可」(メソッド/パスの詳細なし) | 「必要な具体的な API パスや操作は分かりますか? 分かれば、ポリシーをそれらだけに制限できます。分からない場合は、広範なプリセットを使用します。」 |
| L4 のみ/「そのまま通すだけ」 | 「L4 のみの場合、プロキシはメソッドやパスのルールを適用しないため、任意のメソッドとパスが許可されます。少なくとも読み取り専用または読み書きの制限を設けなくてもよいですか?」 |
ワイルドカードのバイナリ(/usr/bin/*) | 「ワイルドカードのバイナリパターンを指定すると、そのディレクトリ内の任意のバイナリがこのポリシーを使用できます。特定のバイナリに絞り込めますか?」 |
| 1 つのポリシーに複数のホストを指定 | 「これらのホストすべてに同じアクセスレベルが必要ですか? より厳しい制限が必要なホストがあれば、別々のポリシーに分けられます。」 |
enforcement: audit で access: full | 「監査モードでのフルアクセスでは、実際には何も制限されず、すべてのトラフィックが通過し、違反がログに記録されるだけです。この設定で意図どおりですか? それとも制限を適用しますか?」 |
すべてのルールのパスに ** を使用 | 「すべてのパスに ** を使用すると、任意の URL パスが許可されます。必要な具体的な API パスのプレフィックス(例:/api/v1/)は分かりますか?」 |
| 宛先がプライベート/内部 IP | 「このサービスはプライベート IP(10.x、172.16.x、192.168.x)に名前解決されますか? 正確なホスト名であれば allowed_ips がなくてもプライベートアドレスに接続できますが、ワイルドカードまたはホスト名のないエンドポイントでは必要です。エンドポイントを特定の CIDR 範囲に固定しますか?」 |
よく知られたサービスの API ドキュメントを自動検出する
ユーザーが認知度の高い API ホストについて言及しているものの、ドキュメントを提供しておらず、現在のティアが Minimal の場合は、API ドキュメントをオンラインで検索して Full へのアップグレードを試みます。
実行する条件:
- ホストがよく知られた公開 API である(例:
api.github.com、api.anthropic.com、api.openai.com、integrate.api.nvidia.com、api.stripe.com、api.slack.com、api.gitlab.com) - ユーザーが API ドキュメントをまだ提供していない
- ユーザーが広範なプリセットを明示的に求めていない(「読み取り専用で、特別なことは何もしない」など)
実行方法:
- ユーザーに次のように伝えます:「より正確なポリシーを生成できるよう、[サービス] の REST API ドキュメントを調べてもよろしいですか?」
- ユーザーが同意した場合(または断っていない場合)、ドキュメントを検索します。
"[サービス名] REST API documentation endpoints"や"[サービス名] OpenAPI spec"のようなクエリでウェブを検索します- 検索結果から公式ドキュメントの URL を探します
- ドキュメントのページを取得し、エンドポイントの一覧(メソッドとパスの組み合わせ)を抽出します
- 検出したエンドポイントを使って、より細かい範囲に絞る提案をします:「[サービス] の API で [N] 個のエンドポイントが見つかりました。ご希望に基づいて、ポリシーを [サブセット] のみに絞れます。そうしますか、それとも広範なプリセットのままにしますか?」
スキップする条件:
- ユーザーが広範なプリセットを明示的に求めた場合、または「ドキュメントは調べなくていい」と述べた場合
- API が内部用、非公開、または公開ドキュメントがない場合
- ホストがよく知られたサービスのものだと判断できない場合
- このホストについて以前に検索した際、有用な結果が得られなかった場合
検索に失敗した場合の対応: 検索しても利用可能な API ドキュメントが見つからない場合(検索結果が無関係、ドキュメントの閲覧に認証が必要、ページの解析には大きすぎるなど)は、処理を止めず、現在のティアにフォールバックします。次のように伝えます:「[ホスト] の利用可能な API ドキュメントが見つからなかったため、[プリセット/L4] のアプローチでポリシーを生成します。後からドキュメントを提供して、範囲を絞ることもできます。」
ユーザーがこれ以上範囲を絞れない場合
ポリシーを広範なままにする必要があるとユーザーが確認した場合(パスがわからない、本当に広範なアクセスが必要など)は、受け入れたうえで、範囲の広さを指摘します。ポリシーの生成を妨げず、警告が出力に表示されるようにしてください(ステップ 6 を参照)。
反復
何度かやり取りが必要になる場合があります。やり取りは簡潔に保ちます。
- 明確化の質問をまとめて一度に尋ねます(関連する質問はまとめます)
- 回答に基づいて理解を更新します
- 回答によってさらに範囲を絞れることがわかった場合は、追加で質問します
- ユーザーが範囲を確認するか、続行するよう指示した時点で終了します
質問を重ねすぎないでください。 ユーザーの依頼が明確かつ具体的な場合は、確認を省略してそのまま生成に進みます。本当に曖昧な点がある場合や、攻撃対象領域を意味のある形で縮小できる場合にのみ質問します。
ステップ 3:ポリシースキーマを確認する
ポリシーを生成または変更する前に、公開されているポリシースキーマのリファレンスを確認してください。現在のスキーマの正式な情報源は公開ドキュメントです。このスキルの例からフィールドを推測しないでください。
参照する主なセクション:
- ポリシースキーマのリファレンス — トップレベルの構造
network_policies— ルールの構造NetworkEndpointフィールド — host、port、protocol、tls、enforcement、access、rules、allowed_ipsL7Rule/L7Allow— メソッドとパスのマッチング- アクセスプリセット —
read-only、read-write、full allowed_ipsによるプライベート IP アクセス — プライベート IP 空間の CIDR 許可リスト- ネットワークミドルウェア — トップレベルのミドルウェア設定、実行順序、ホストの選択、障害発生時の動作
- 検証ルール — 有効または無効となる組み合わせ
ミドルウェアが必要な場合は、公開されているスーパーバイザーミドルウェアガイドも確認してください。
適用の仕組みと標準設定を確認するには、サンドボックスポリシーとデフォルトポリシーのリファレンスを参照してください。デフォルトポリシーは OpenShell ランタイムに組み込まれており、明示的なポリシーが指定されていない場合に適用されます。
作成したポリシーだけでなく、意図したプロバイダーの組み合わせも検証してください。
プロバイダーを合成した結果、イメージのエンドポイントに認証情報が設定され、
起動が ConfigurationInvalid で失敗する場合があります。公開されている
ポリシーのワークフローに従って、ポリシー全体またはプロバイダーの選択を修正してください。
起動エラーを回避するためだけに
allow_uninspected_credentials を追加しないでください。
ステップ 4:ポリシーの形式を選ぶ
詳細レベルとユーザーの意図に基づいて、次の判断ツリーに従ってください。
Is L7 inspection needed?
├─ No (user wants pass-through / "just allow it")
│ ├─ Explicit-proxy client → omit protocol
│ └─ Native DNS/socket client with a DNS hostname on a supported runtime → protocol: tcp
│
└─ Yes (user wants method/path control)
│
├─ Does a preset match the intent exactly?
│ ├─ Read-only (GET, HEAD, OPTIONS) → access: read-only
│ ├─ Read-write (no DELETE) → access: read-write
│ └─ Everything → access: full
│
└─ No preset fits (specific paths, mixed broad+narrow, exclude certain paths)
└─ Build explicit rules list
└─ Requires either known paths from the user or full API docs
原則:意図を満たす最もシンプルな形式を常に選んでください。ユースケースに対応できる場合は、明示的なルールよりプリセットを優先してください。
TLS の判断
ポートにかかわらず、すべてのエンドポイントで tls を省略してください。プロキシが TLS を自動検出し、検査のために終端します。空でない値として受け付けられるのは skip のみで、クライアント証明書による mTLS または非 HTTP プロトコルを必要とするアップストリーム向けに予約されています。
拒否された値(削除された terminate と passthrough も含みます)を skip に変更して「修正」しないでください。代わりにフィールドを削除してください。skip を指定すると、そのエンドポイントでの検査、認証情報の注入、L7 ルールの適用が停止されるため、エンドポイントが許可する範囲が気付かないうちに広がります。
ミドルウェアの判断
ユーザーが、許可された HTTP リクエスト、最終 HTTP レスポンス、またはクライアントの WebSocket テキストメッセージの検査、変換、編集、もしくは個別の認可を求めた場合にのみ、network_middlewares を追加します。リクエストミドルウェアは、ネットワークポリシーと L7 ポリシーによる許可後、プロバイダーの認証情報が挿入される前に実行されます。レスポンスミドルウェアは、対応する最終レスポンスがサンドボックスに返される前に実行されます。
- HTTP リクエスト本文またはクライアントからアップストリームへの完全な WebSocket テキストメッセージを、固定パターンで編集する場合は、ゲートウェイへの登録なしで
openshell/regexを使用します。 - 運用者が所有するミドルウェア名を使用するのは、すでに
[[openshell.supervisor.middleware]]の下に登録され、ゲートウェイとサンドボックスの両方のスーパーバイザーから到達可能な場合に限ります。 - サービスが
Describeで必要なバインディングを提示していること、また運用者のbinding_policyがその使用を許可していることを確認します。たとえば、サービスが両方の HTTP フックを提示していても、登録でhttp_response_pre_returnしか許可されていない場合、on_error: fail_closedであっても、該当するリクエストではこのミドルウェアがスキップされます。 - リクエスト検査を必須にするには、運用者に
bindingsへhttp_request_pre_credentialsを含め、binding_policy = "allowlist"または"exact"を設定するよう依頼します。デフォルトのdynamicポリシーでは、サービスが提示する内容に従います。サンドボックスポリシーだけでは、存在しないバインディングを必須にできません。これらに依存する前に、ゲートウェイとすべてのスーパーバイザーがバインディングポリシーに対応していることを確認します。 - WebSocket ミドルウェアが検査するのは、
ws://とwss://の両方におけるクライアントのテキストメッセージのみです。バイナリメッセージとアップストリームからクライアントへのメッセージは、fail_closedであっても検査されずに通過します。 on_errorは、選択されたステージでの失敗を制御します。明示的な拒否は常にトラフィックをブロックします。WebSocket ステージがfail_openで失敗した場合、接続の残りの期間もそのステージがバイパスされることがあります。on_errorのデフォルトにはfail_closedを設定します。ステージをバイパスしてもユーザーが示したセキュリティ要件が保たれる場合に限り、fail_openを使用します。- ポリシー全体で一意の
order値を割り当てます。値が小さいものから実行され、選択できる設定は最大 10 個です。 endpoints.includeでは、可能な限り絞り込んだ宛先ホストを指定します。広範なセレクターに信頼できる例外がある場合は、excludeを使用します。tls: skipのエンドポイントには、フェイルクローズのミドルウェアを選択しないでください。スーパーバイザーはそのトラフィックを検査できません。
パスを glob パターンにマッピングする(明示的なルールを作成する場合)
Moderate および Full ティアでのみ必要です。API パスのパラメーターを glob パターンに変換します。
| API パス | Glob パターン |
|---|---|
/repos/{owner}/{repo} | /repos/*/* |
/repos/{owner}/{repo}/issues | /repos/*/*/issues |
/repos/{owner}/{repo}/issues/{id} | /repos/*/*/issues/* |
/api/v1/models/{model_id}/versions/{version} | /api/v1/models/*/versions/* |
/api/v1/ 以下のすべてのサブパス | /api/v1/** |
REST ルールのパスでは、* は / で停止しますが、セグメント全体を表す ** は / をまたぎます。
たとえば、/api/v1/** は子孫のパスには一致しますが、/api/v1 自体には一致しません。このパスが必要な場合は、明示的なルールを追加します。? は / 以外の 1 文字に一致し、[0-9] のような角括弧クラスも使用できます。
エンドポイントの path セレクターは別のセマンティクスを持ちます。/api/v1/** は
/api/v1 自体を含み、その他のパターンにおける * は / をまたぐことがあります。これらのセマンティクスは、エンドポイントの設定の選択と、どのエンドポイントの許可・拒否ルールを適用するかの判断の両方に適用されます。公開されているポリシースキーマの
マッチャーのセマンティクスを参照してください。
明示的なルールリストの作成
許可する操作ごとに、allow エントリーを作成します。
rules:
- allow:
method: GET
path: "/api/v1/models/*"
- allow:
method: POST
path: "/api/v1/completions"
意図する範囲をカバーする、最も具体的なパターンを使用します。API の構造が分かっている場合は、** よりも限定的な glob を優先します。
ステップ 5:ポリシーを生成する
出力形式
完全な network_policies エントリを生成します。次のテンプレートを使用してください。
network_policies:
<policy_key>:
name: <policy_key>
endpoints:
- host: <api_host>
port: <port>
protocol: rest # Required for L7 inspection
enforcement: enforce # or audit
# Use ONE of: access OR rules (never both)
access: <preset> # read-only | read-write | full
# OR
rules:
- allow:
method: <METHOD>
path: "<glob_pattern>"
# Optional: restrict resolved addresses (CIDR or exact IP). Required
# for private IPs on wildcard or hostless endpoints.
# allowed_ips:
# - "10.0.5.0/24"
binaries:
- { path: <binary_path> }
ミドルウェアが要求された場合は、ネットワークポリシーの下にネストせず、独立したトップレベルのマップとして追加します。
network_middlewares:
<config_key>:
name: <human_readable_name>
middleware: <built_in_or_registered_name>
order: 10
config: {}
on_error: fail_closed
endpoints:
include: ["<api_host>"]
# exclude: ["<trusted_host>"]
マップキーは、ポリシー内で安定した識別子です。ミドルウェアの選択は、リクエストを許可したネットワークポリシーのエントリとは独立しています。
拒否ルール
deny_rules を使用すると、広範なアクセスを許可しながら、特定の危険な操作をブロックできます。拒否ルールは許可ルールの後に評価され、優先されます。これは rules の方法とは逆です。許可する操作をすべて列挙する代わりに、広範なアクセスを許可し、少数の危険な操作をブロックします。
# Example: Allow full access to GitHub but block admin operations
github_api:
name: github_api
endpoints:
- host: api.github.com
port: 443
protocol: rest
enforcement: enforce
access: read-write
deny_rules:
- method: POST
path: "/repos/*/pulls/*/reviews"
- method: PUT
path: "/repos/*/branches/*/protection"
- method: "*"
path: "/repos/*/rulesets"
binaries:
- { path: /usr/bin/curl }
拒否ルールは、許可ルールと同じマッチング機能(method、path、query パラメーターのマッチャー)をサポートします。ポリシーを生成する際は、ユーザーが広範なアクセスと少数のブロック対象操作を求めている場合、拒否ルールを優先してください。60 件を超える許可ルールを列挙するよりも、短く保守しやすいポリシーになります。
プライベート IP 宛先
プロキシの SSRF 保護では、エンドポイントがホストをどのように指定しているかに応じて、プライベート(RFC 1918)宛先の扱いが異なります。
- 完全一致のホスト名(
host: api.internal.corp)—allowed_ipsがなくても、接続先がホスト名の名前解決で得られるプライベートアドレスに到達する場合があります。 - ワイルドカードホスト、ホスト指定のないエンドポイント、またはポリシーアドバイザーによる提案 —
allowed_ipsで許可されていない限り、名前解決で得られるプライベートアドレスはブロックされます。
allowed_ips を使用して、エンドポイントが到達できるアドレスを固定します。設定すると、パブリックアドレスも含め、名前解決で得られるすべてのアドレスがリストの範囲内にある必要があります。
- ホスト + 許可リスト:
host+allowed_ips— ドメインが許可リスト内の IP に名前解決される必要があります - ホスト指定なしの許可リスト:
allowed_ipsのみ(hostなし)— 指定ポート上の任意のドメインが、許可リスト内の IP に名前解決される場合に許可されます
ホスト名のみの認可では、スーパーバイザーのリゾルバーが正となります。Linux の明示的プロキシ構成で、ワークロードのプロセス名前空間がスーパーバイザーに公開されている場合、Kubernetes の hostAliases マッピングなどのサンドボックス内の /etc/hosts エントリは、allowed_ips に正確な IP または狭い CIDR を設定した場合に限り、通常のエンドポイントで有効になります。OpenShell のドライバー管理のホストゲートウェイエイリアスでは、別の信頼済み IP 固定方式が使用されます。
ループバック(127.0.0.0/8)、リンクローカル(169.254.0.0/16)、未指定アドレス、およびクラウドメタデータアドレスは、allowed_ips の設定にかかわらず、上流の宛先として常にブロックされます。
Google Cloud メタデータエミュレーターは、Linux サンドボックスで 127.0.0.1:8174 を予約します。OpenShell はスーパーバイザーを介して SDK の検出をローカルで処理します。allowed_ips の例外を追加したり、ホストのクラウドメタデータサービスへのアクセスを許可したりしないでください。詳しくは、Google プロバイダーのドキュメントを参照してください。
# Example: Pin an internal service to a known private IP range
internal_api:
name: internal_api
endpoints:
- host: api.internal.corp
port: 8080
allowed_ips:
- "10.0.5.0/24"
binaries:
- { path: /usr/bin/curl }
ポリシーキーの命名
説明的な snake_case キーを使用します。例:github_api、nvidia_inference、internal_service_readonly。
複数のエンドポイント
ユーザーが複数のホスト、または異なるルールで同じホストへのアクセスを必要とする場合は、次のいずれかを選択します。
- 同じポリシー — バイナリーのセットが同じ場合は、
endpointsに複数のエントリを設定します - 個別のポリシー — バイナリーのセットが異なる場合は、異なるポリシーキーを使用します
ステップ 6:検証と警告
ポリシーをユーザーに提示する前に、正しさを確認し、さらにアクセス範囲の懸念点を指摘します。
ハードエラー(サンドボックスの起動を妨げます)
- 同じエンドポイントに
rulesとaccessが両方存在していない - L7 の
protocolが設定されている場合、rulesまたはaccessのいずれかも存在している。protocol: tcpは L4 専用であり、どちらのフィールドも含めてはならない - すべての
protocol: tcpエンドポイントに有効な DNS ホスト名がある。ホスト名がない、IP リテラルである、末尾にドットが付いている、または不正な DNS セレクターである状態ではない -
tlsは省略するか、skipに設定する。それ以外の値は受け付けない -
rulesリストが存在する場合、空ではない - すべてのミドルウェア設定に、空でない
middleware名と空でないendpoints.includeがある - ミドルウェアの
order値が重複しておらず、選択されるどのチェーンも 10 ステージを超えない - フェイルクローズのミドルウェアセレクターが
tls: skipエンドポイントを対象にできない - オペレーターが実行するサービスによる検査が必須の場合、登録にバインディング(
http_request_pre_credentials、http_response_pre_return、またはwebsocket_message_pre_credentials)が必要で、そのサービスがバインディングをアドバタイズし、アタッチメントでon_error: fail_closedを使用している - ユーザーが、V1 WebSocket ミドルウェアではクライアントのテキストメッセージのみを検査することを理解している
- 認証情報付きプロバイダーが提供するエンドポイントは、L4 専用でも
tls: skipでもない。ただし、例外を明示的に記録するallow_uninspected_credentials: trueが設定されている場合を除く
スキーマ警告(ログにのみ記録されますが、修正する必要があります)
-
tls: skipをポート 443 の L7 ルールと組み合わせていない。暗号化されたトラフィックは検査できない - HTTP メソッドが標準のもの(GET、HEAD、POST、PUT、DELETE、PATCH、OPTIONS、または
*)である - 認証情報付きの宛先が、アタッチされたプロバイダープロファイルのエンドポイントにも含まれている。ポリシーによる許可だけでは、認証情報の解決は許可されない
構造チェック
- すべてのポリシーに
name、endpoints、binariesがある - すべてのエンドポイントに
hostとportがある - すべてのバイナリに
pathがある - ポリシーキーが
nameフィールドと一致している - すべてのミドルウェアセレクターで、
includeとexcludeのパターンの合計が 32 以下である
広範なアクセスに関する警告
生成されたポリシーを評価し、アクセス範囲が広すぎる場合は警告をユーザーへの出力に含めてください。警告は生成を妨げるものではありませんが、ユーザーに必ず表示する必要があります。
| 条件 | 表示する警告 |
|---|---|
L4 のみ(protocol がない、または protocol: tcp) | "このポリシーでは、すべてのアプリケーションのメソッドとパスが許可されます。protocol を省略すると明示的プロキシ動作が使用され、メソッドやパスのルールは適用されません。デフォルトの TLS 処理では、プロキシは検出した TLS を終端し、解析した HTTP リクエストのオーソリティを確認しますが、HTTP/2 の事前知識や HTTP 以外のプロトコルなど、その他の CONNECT ペイロードは未加工のリレーを通過する場合があります。また、tls: skip では終端と解析もバイパスされます。protocol: tcp は、完全な基盤機能を備えているとランタイムが示す場合(現在は Docker と Podman のみ)に限り、ポリシー DNS と透過的な TCP を有効にします。ホスト名は接続のルーティングを制約しますが、アプリケーションのオーソリティは制約しないため、互換性のある共有インフラストラクチャでは、他のテナントやサービスが公開される可能性があります。HTTP メソッド単位またはオーソリティの制御が必要な場合は、プリセットを使った protocol: rest を検討してください。" |
access: full | "このポリシーでは、すべてのパスに対するすべての HTTP メソッド(DELETE を含む)が許可されます。DELETE が不要な場合は、read-write の方が安全です。読み取りのみが必要な場合は、read-only が最も制限の厳しい選択肢です。" |
access: full + enforcement: audit | "監査モードでのフルアクセスには、実際の制限がありません。すべてのトラフィックが通過します。実質的に、これは監視のみのポリシーです。" |
書き込みの必要性をユーザーが確認していない場合の access: read-write | "このポリシーでは、すべてのパスに対する POST、PUT、PATCH が許可されます。データの読み取りのみが必要な場合は、read-only の方が制限的です。" |
ワイルドカードを含むバイナリ(バイナリパスに * または ** がある) | "このポリシーでは、glob パターンに一致するあらゆるバイナリが許可されます。そのディレクトリ内の侵害された、または想定外のバイナリがこのポリシーを使用する可能性があります。バイナリパスを個別に指定することを検討してください。" |
すべての明示的なルールで ** パス glob を使用 | "すべてのルールで、あらゆる URL パスに一致する ** パターンが使用されています。これはプリセットと同等です。明確にするために access: read-only(または同様の設定)を使用するか、API の構造がわかっている場合はパスの範囲を狭めることを検討してください。" |
| 1 つのポリシーに複数の広範なエンドポイントがある | "このポリシーは、N 個の異なるホストに同じ広範なアクセスを許可します。いずれかのホストに後から厳しい制限が必要になった場合は、ポリシーを分割する必要があります。" |
ホストを指定しない allowed_ips(host フィールドがなく、protocol: tcp でもない) | "このエンドポイントには host がありません。ポート上で許可された IP 範囲に解決されるあらゆるドメインが、従来のプロキシを通過できます。許可リストを使用できるドメインを制限するため、host フィールドの追加を検討してください。" |
広範な CIDR(例:10.0.0.0/8) | "この allowed_ips エントリーは非常に広い範囲を対象とします。露出を最小限に抑えるため、特定のサブネット(例:10.0.5.0/24)に範囲を狭めることを検討してください。" |
on_error: fail_open | "このミドルウェアが利用できない場合、設定を拒否した場合、無効な結果を返した場合、または本文の上限を超えた場合、このミドルウェアをバイパスできます。この制御より可用性を優先する場合を除き、fail_closed を使用してください。" |
| 広範なミドルウェアのホストセレクター | "このミドルウェアは、ネットワークルールの許可とは独立して、一致するすべての宛先に関連付けられます。オペレーターが実行するミドルウェアでは、サービスが通知し、登録で許可されたバインディングのみを実行できます。一致するすべてのホストへの関連付けが必要でない場合は、endpoints.include の範囲を狭めるか、除外を追加してください。" |
allow_uninspected_credentials: true | "このエンドポイントでは、OpenShell が検査または書き換えできないトラフィックにプロバイダーの認証情報が含まれる可能性があります。検査可能なプロトコルと認証情報の書き換えを優先してください。未加工のトラフィックが必要な場合に限り、この例外を維持してください。" |
範囲に関する警告は、次のように明確な形式で出力してください。
⚠️ Breadth warning: This policy uses `access: full`, which allows all HTTP
methods (including DELETE) on all paths. If you don't need DELETE, consider
using `read-write` instead.
範囲に関する警告がない場合は、明示的に次のように伝えてください:"範囲に関する懸念はありません。このポリシーの範囲は適切です。"
ステップ 7:出力モードを決定する
ポリシーの保存先を決めます。該当するモードを判断してください。
| シグナル | モード |
|---|---|
| ユーザーが既存のポリシーファイルを指定する(例:「my-sandbox-policy.yaml に追加して」) | 既存ファイルを更新 |
| ユーザーが「ポリシーを更新して」「このポリシーをポリシーファイルに追加して」と言う | 既存ファイルを更新 — 更新するファイルを尋ねる |
| ユーザーが既存のポリシールールを名前で指定して変更するよう求める | 既存ファイルを更新 — 指定されたポリシーをその場で編集する |
| ユーザーが「新しいポリシーファイルを作成して」と言う、または存在しないファイルを指定する | 新しいファイルを作成 |
| ファイルに関する情報がない | 提示のみ — YAML を提示し、ファイルに書き込むかユーザーに尋ねる |
モード A:既存のポリシーファイルを更新する
-
既存のファイルを読み取り、現在の状態を把握します。
network_policiesの下にすでに存在するポリシーfilesystem_policy、landlock、processセクションの内容- ファイルがコンパクトな YAML 形式(
{ host: ..., port: ... })と展開形式のどちらを使用しているか
-
競合を確認します。
- 同じキーのポリシーがすでに存在しますか?存在する場合は、置き換える、新しいエンドポイント/バイナリをマージする、または別のキーを使用するのか、ユーザーに尋ねます。
- 既存のエンドポイントセレクターが新しいセレクターと重複していますか?互換性のある重複は許可されており、許可ルールと拒否ルールを意図的に集約できます。接続またはリクエスト処理のメタデータ(TLS、宛先制約、プロトコル/パーサーの動作、強制適用、認証情報の処理を含む)が異なる、同程度に具体的な重複は拒否するか、修正してください。より具体的なパスセレクターは、より広範なリクエスト処理メタデータを上書きできます。
- サンドボックスでプロバイダーの認証情報が割り当てられている場合は、プロバイダープロファイルにも意図したホスト、ポート、パスが宣言されていることを確認してください。サンドボックスポリシーの許可設定によって、プロファイルの静的な認証情報バインディングを拡張することはできません。
credential_signingの場合、エンドポイントを持つプロファイルが割り当てられているなら、そのプロファイルでAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYが宣言され、署名対象のエンドポイントがカバーされていることを確認してください。エンドポイントを持たない AWS プロファイルの場合は、正確な割り当て先プロバイダー名を指定してcredential_binding.providerを追加してください。
-
変更を適用します。
- 新しいポリシーを追加する場合:ファイル既存のインデントとスタイルを維持しながら、新しいポリシーブロックを
network_policiesの下に挿入します。 - 既存のポリシーを変更する場合:対象のポリシーをその場で編集し、エンドポイントの追加/削除、アクセスプリセットの変更、ルールの更新、バイナリの追加などを行います。ルールは、列挙されているすべてのバイナリに、列挙されているすべてのエンドポイントおよびポートへのアクセスを許可します。そのため、バイナリを 1 つ追加すると、そのルールのすべてのエンドポイントへのアクセスが許可され、エンドポイントを 1 つ追加すると、そのルールのすべてのバイナリにそのエンドポイントへのアクセスが許可されます。書き込む前に、結果として生じる組み合わせをユーザーに伝えてください。バイナリがルールのエンドポイントの一部にのみアクセスするようにしたい場合は、既存のルールを拡張するのではなく、そのバイナリとエンドポイントを別のルールに記述してください。
binariesリストが空の場合は、どのバイナリでも対象になります。そのため、省略するとルールの対象がすべてのプロセスに広がります。 - ポリシーを削除する場合:ユーザーが求めた場合は、ポリシーブロックを削除します。
- 新しいポリシーを追加する場合:ファイル既存のインデントとスタイルを維持しながら、新しいポリシーブロックを
-
それ以外はすべてそのまま保持します。ユーザーから明示的に求められない限り、
filesystem_policy、landlock、process、その他のポリシーを変更しないでください。
モード B:新しいポリシーファイルを作成する
完全なスタンドアロンポリシーファイルを生成します。スキーマの完全なひな形を使用します。
version: 1
filesystem_policy:
include_workdir: true
read_only:
- /usr
- /lib
- /proc
- /dev/urandom
- /app
- /etc
- /var/log
read_write:
- /tmp
- /dev/null
landlock:
compatibility: best_effort
network_policies:
# <generated policies go here>
上記の filesystem_policy セクションと landlock セクションは、妥当なデフォルト設定です。
プロセスの ID は省略されており、選択したコンピュートドライバーが決定できます。Docker と Podman の場合、省略された各 ID フィールドは、イメージの OCI USER にフォールバックします。これらはデフォルト設定であり、環境に応じて調整が必要になる場合があることをユーザーに伝えてください。ゲートウェイの推論設定は、openshell inference set/get で別途構成します。生成される network_policies ブロックが主な出力です。
ユーザーが process.run_as_user または process.run_as_group を明示的に指定した場合は、sandbox または 1 から 4294967294 までの数値 UID/GID を受け付けます。root(0)と無効な ID のセンチネル値(4294967295)は拒否します。数値が小さい ID では、イメージファイル、マウントされたボリューム、またはデバイス上で同じ ID に付与された権限が引き継がれることを警告してください。
MicroVM の場合、数値セレクターは、サンドボックスの書き込み可能なオーバーレイの所有者として解決された ID と一致する必要があります。ユーザーとグループは個別に確認され、どちらかが一致しなければ起動できません。所有者の UID:GID が不明な場合は、セレクターを省略するか、sandbox を指定して、ドライバーがその ID を維持するようにします。別の数値 ID を選択したり、既存のオーバーレイの所有者をポリシーで変更できると示唆したりしないでください。たとえば、所有者が 1000:1000 のときに UID 10000 を求められた場合は、VM を起動できないポリシーを生成するのではなく、理由を説明して拒否し、省略する方法または sandbox を指定する方法を提示してください。
ユーザーがファイルパスを指定した場合は、そのパスに書き込みます。指定がない場合は、保存場所を尋ねてください。一般的な慣例は、プロジェクト内のポリシーファイル(例:sandbox-policy.yaml)を openshell sandbox create --policy <path> に渡すか、OPENSHELL_SANDBOX_POLICY 環境変数で設定する方法です。
モード C:提示のみ(ファイルには書き込まない)
生成したポリシー YAML を、次の内容とともに表示します。
- 概要 — ポリシーが許可する内容と拒否する内容を平易な言葉で説明します
- YAML — そのまま貼り付けて使える、
network_policiesブロック全体 - 統合に関するガイダンス:
- ローカルファイルに保存し、
openshell sandbox create --policy <path>に渡すか、OPENSHELL_SANDBOX_POLICY=<path>を設定します - 本番環境では、ゲートウェイを通じて構成します
- ローカルファイルに保存し、
- 注意事項 — 前提とした内容、およびユーザーが確認すべき事項
ステップ 8:確認して調整する
ポリシーを提示または適用した後、次の調整を希望するかユーザーに尋ねます。
- ルールを厳しくする、または緩める
- エンドポイントやバイナリを追加する
- 強制モードと監査モードを切り替える
- プリセットから明示的なルールに切り替える(またはその逆)
- 提示のみの場合、ポリシーをファイルに適用する
- 他の API 用にポリシーを追加作成する
クイックリファレンス:よくあるパターン
L4 のみ(メソッドやパスのルールなし)
my_api:
name: my_api
endpoints:
- { host: api.example.com, port: 443 }
binaries:
- { path: /usr/bin/curl }
読み取り専用プリセットを使った HTTPS API
my_api_readonly:
name: my_api_readonly
endpoints:
- host: api.example.com
port: 443
protocol: rest
enforcement: enforce
access: read-only
binaries:
- { path: /usr/bin/curl }
明示的なルールを使った HTTPS API
my_api_custom:
name: my_api_custom
endpoints:
- host: api.example.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow:
method: GET
path: "/api/v1/**"
- allow:
method: POST
path: "/api/v1/data"
binaries:
- { path: /usr/bin/curl }
- { path: /usr/local/bin/myapp }
HTTP(非 TLS)内部 API
internal_svc:
name: internal_svc
endpoints:
- host: api.internal.svc
port: 8080
protocol: rest
enforcement: enforce
rules:
- allow:
method: GET
path: "/health"
- allow:
method: POST
path: "/api/v1/jobs"
binaries:
- { path: /usr/bin/curl }
プライベート IP アクセス(ホスト + 許可リスト)
internal_db:
name: internal_db
endpoints:
- host: db.internal.corp
port: 5432
allowed_ips:
- "10.0.5.0/24"
binaries:
- { path: /usr/bin/curl }
プライベート IP アクセス(ホストなし — 範囲内の任意のドメイン)
private_services:
name: private_services
endpoints:
- port: 8080
allowed_ips:
- "10.0.5.0/24"
- "10.0.6.0/24"
binaries:
- { path: /usr/bin/curl }
追加リソース
- ポリシースキーマ
- サンドボックスポリシー
- デフォルトポリシー
- スーパーバイザーミドルウェア
- デフォルトポリシー:OpenShell ランタイムに組み込まれています
- 実際の API ドキュメントの翻訳例については、examples.md を参照してください