コンテンツにスキップ

セキュリティ

kstackの目標の一つは、AIエージェントがKubernetesの監視、トラブルシューティング、監査タスクを通常よりも安全な方法で実行できるようにすることです。kstackは、どの入力を信頼できないデータとして扱うべきか、またどのフォローアップアクションが実行前にパーミッションを必要とするかをエージェントに指示するセキュリティガードレールを設定することでこれを実現します。このページでは、信頼境界、信頼できないデータをエージェントのコンテキストから遠ざけるためにkstackがとる措置、そしてその境界を意図的に越える2つのスキル(/exec/logs)について説明します。


AIエージェントを使用したクラスターとのあらゆるやり取りには、3つの関係者が関与します。

  • あなた — プロンプト、kubeconfig、およびクラスターを操作する権限を提供します。破壊的または危険なアクションを許可できるのはあなただけです。
  • エージェント — プロンプトを解釈し、どのスキルを呼び出すかを決定し、スキルが返す出力を読み取ります。
  • クラスター — Kubernetes APIおよび関連ツールを通じてデータを返します。そのデータは信頼できる入力ではありません。最悪のシナリオでは、Pod名、ログ行、アノテーション、イベントメッセージはすべて攻撃者が制御可能であり、それらを無批判に読み取るエージェントはそれらによって誘導される可能性があります。

kstackの役割は、信頼できないクラスターデータがエージェントの挙動を左右することなく、エージェントを有用な状態に保つことです。


1. 明確に定義されたレスポンスエンベロープ

Section titled “1. 明確に定義されたレスポンスエンベロープ”

kstackスキルが内部的に使用するすべてのスクリプトは、ちょうど1つのJSONオブジェクトをstdout(「レスポンスエンベロープ」)に書き込みます。オブジェクトのスキーマはバージョン管理され、事前定義されたフォーマットに対して検証されます。

{
"kstack": "1",
"status": "ok" | "error",
"render": "verbatim" | "agent", // ok only
"content": string, // ok only; JSON-escaped
"agent_context": string, // ok only; optional side-channel
"kind": "user" | "infra", // error only
"message": string, // error only
"kube_context": string, // optional; pinned cluster
"notice": string // optional; operator banner
}

このコントラクトのセキュリティ関連プロパティは次のとおりです。

render
content の意図されたターゲットをエージェントに伝える列挙型(verbatim または agent)。render: verbatim は、エージェントに content をそのまま出力し、再フォーマットやフォローアップ推論なしにターンを終了するよう指示します。render: agent は、content をエージェントが推論できるツール出力としてマークします。
content
エージェントへのペイロードを含むJSONエスケープ文字列フィールド。
agent_context
エージェントがフォローアップに使用できるコンテキストデータ(キャッシュパス、カウント、解決された識別子など)を提供するためにスクリプトが使用できるJSONエスケープ文字列フィールド。エージェントによって読み取られ、ユーザーには表示されません。これにより render: verbatim に対して content がクリーンな状態に保たれ、メタデータが端末に漏洩するのを防ぎます。
message
スクリプトによって生成された型付きエラーを伝えるJSONエスケープ文字列フィールド。

ゼロ以外の終了コードは予期しないクラッシュのために予約されており、その場合エージェントは意図を推測するのではなくstderrを出力して停止するように指示されます。

2. バルククラスターデータはディスク上に保持され、jq を通じて読み取られます

Section titled “2. バルククラスターデータはディスク上に保持され、jq を通じて読み取られます”

kstackがない場合、AIエージェントはすべてのPod、Node、イベントをコンテキストにストリーミングし、無関係なデータにトークンを消費し、攻撃者によって影響を受けた可能性のあるテキストの塊内でフィールドと指示を区別するためにモデルに依存します。kstackはコンテキストごとの cache_dir にレスポンスを書き込み、エージェントにその場所を渡すことでこれを回避します。これにより、フォローアップの質問はキャッシュされたJSONに対して jq を実行することで答えられます。

このアプローチには2つの利点があります。

  • 散文解釈ではなく構造解析。 jq '.items[].metadata.name' は既知のスキーマを走査し、文字列値を返します。Podアノテーション内のプロンプトインジェクションペイロードは既知のJSONパスの文字列値のままであり、モデルが指示として理解するよう求められるテキストではありません。

  • コンテキスト増大の抑制。 Podごと・Nodeごとの完全なテーブルがモデルのコンテキストウィンドウに入ることはありません。kstackスキルが提供する確定的なサマリーはクラスターサイズに関わらず数百トークンであり、後続ターンでは質問が必要とする特定のフィールドのみが引き出されます。

3. 破壊的またはセンシティブなアクションにはあなたの確認が必要です

Section titled “3. 破壊的またはセンシティブなアクションにはあなたの確認が必要です”

kstackスキルによって実行されるクラスターアクションは読み取り専用であり、設計上安全ですが、クラスターの状態を変更するフォローアップタスクの実行や特権情報の取得をエージェントに依頼することもできます。エージェントがあなたの許可なくこれらのアクションを実行しないよう、各スキルはエージェントとの明確な境界を設定し、クラスターの状態を変更するアクション(リソースの削除、ConfigMaps の変更)やクレデンシャルの公開(Secrets の読み取り)を行う前に確認を要求するよう指示します。

4. クラスターコンテキストはセッションごとに固定されます

Section titled “4. クラスターコンテキストはセッションごとに固定されます”

セッション内の最初のkstackスキルは kube_context を解決して返します。後続のスキルは、別のクラスターを明示的に要求するまで、すべてのkubectl/kubetail呼び出しに --context=<value> を組み込むよう指示されます。これにより、あるクラスターを対象としたアクションを誤って別のクラスターで実行することを防ぎます。

kstackはシェルスクリプトと SKILL.md ファイルとしてホームディレクトリ以下にインストールされます。すべてのKubernetes呼び出しは、各コンテキストに設定された user に対してすでに持っているクレデンシャルとRBACバインディングを使用して、ローカルの kubeconfig 経由で行われます。


ライブクラスターデータをエージェントにストリーミングできるスキル

Section titled “ライブクラスターデータをエージェントにストリーミングできるスキル”

kstackには、/exec/logs という2つのスキルがあり、これらはあなたとエージェントの両方が対話できるtmuxペイン内で実行されます。ペインはクラスターデータがエージェントの推論コンテキストに最も入り込みやすい場所であるため、実行前に考慮すべきスキルです。

ペインベーススキルの信頼モデル

Section titled “ペインベーススキルの信頼モデル”

デフォルトでは、エージェントはtmuxセッション(コマンド入力、スコープクエリ)を操作できますが、指示しない限りペインの内容を読み取りません(例:「ログの最後のセットのエラーを解析して」)。これは、信頼できないデータがエージェントの推論コンテキストに誤って入力されるのを防ぐよう設計されています。この動作は2つのフラグで制御できます。

  • --trust-pane — エージェントは毎ターンペインを読み取り、内容を要約・関連付け・モデルAPIに送信できます。エージェントに何が起きているかを明示的に推論させたい場合に使用します(例:「これを監視してクラッシュループが解消されたら教えて」)。
  • --detach — エージェントはペインにまったくアタッチしません。読むことも入力することもできません。手動で接続することになり、モデルがセッション内容にアクセスする経路はありません。これはデフォルト動作を構造的に補完するものであり、エージェントのコンプライアンスではなくkstackによって強制されます。

ペインの読み取り動作はプロンプトレベルのコントラクトであることに注意してください。

/exec スキルは、Pod、エフェメラルデバッグコンテナ、またはNode上の特権Podへのインタラクティブシェルを開きます。

注意すべき点:

  • NodeモードとデバッグコンテナモードはPrivilegedです。 Nodeモードは hostPIDhostNetwork、および /host にマウントされたホストファイルシステムを持つ短期間のPodを作成します。デバッグコンテナモードはターゲットPodのプロセスNamespaceに参加します。どちらも通常の exec をはるかに超えたアクセスを許可します。エージェントはシェルを開く前に解決されたターゲットとモードを説明するため、続行前に確認できます。
  • セッションは明示的に停止するまで実行し続けます。 エージェントは特権NodeのPodを自分で削除しません。あなたが指示するのを待ちます。

/logs スキルは、クラスターに対してKubetailクエリを実行し、一致するログ行をペインにストリーミングします。

注意すべき点:

  • ログには機密データが含まれることがよくあります。 Authorization ヘッダー内のトークン、PIIを含むリクエストボディ、シークレットを含むスタックトレースはすべて一般的です。--trust-pane が設定されているかどうかにかかわらず、特定のワークロード、短い時間ウィンドウ、ターゲットを絞ったgrepパターンなど、クエリを狭い範囲に絞ってください。
  • Kubetailのノード側grepが役立ちます。 フィルターをクラスター側にプッシュすることで、そもそもワイヤーを通過する行が少なくなります。つまり、ペイン(--trust-pane 指定時はエージェントにも)に到達する行が少なくなります。広範囲に引き出して手動でフィルタリングするのではなく、フィルターを具体的にしてください。

kstackのテスト戦略は、意味のある最低層で上記の各保護を検証します。これにより、リグレッションが本番環境での驚きではなくテストの失敗として表面化します。プロジェクトには4つのテスト層があります — tests/unittests/integrationtests/e2etests/evals — そしてセキュリティカバレッジはこれらに次のように分散されています。

  • ユニット(bats)。 src/lib/response.sh のエスケープルーチンとエンベロープビルダーを直接検証します。クォート、バックスラッシュ、改行、制御文字、バイナリ風の混合ペイロードを response::_escaperesponse::ok_* に通し、各エンベロープを jq でラウンドトリップして整形式JSONであることを証明します。インジェクション形状の文字列("," を含むPod名、\n"render":"agent" を含むアノテーションなど)が content 値として到達し、兄弟キーを導入しないことを確認します。--detach のフラグパースはユニットテスト済みであり、タイポやリファクタリングによって暗黙的に無効化されることはありません。
  • インテグレーション(bats)。 各スキルは PATH 上のフェイク kubectl を使用してエンドツーエンドで呼び出され、発行されたエンベロープが src/schemas/response.schema.json のJSONスキーマに対して検証されます。kube_context の固定は、マルチスキルフローを実行してすべてのダウンストリーム呼び出しが --context=<resolved> を持つことをアサートすることで確認されます。
  • エンドツーエンド(kind使用)。 実際のクラスターを kind で立ち上げ、スキルをそれに対して実行します。これらのテストは、実際のKubernetes APIサーバーでの構造的保護の保持を確認します。RBAC拒否がstderrの漏洩ではなく型付きの error エンベロープを生成すること、および /exec の特権モード(Node、デバッグコンテナ)が確認パスの前に想定されたPodスペックに解決されることを確認します。
  • Evals(Claude使用)。 プロンプトレベルのコントラクトにはエージェントインザループテストが必要なため、ここに存在します。シナリオ:Podアノテーション、ログ行、イベントメッセージに埋め込まれたプロンプトインジェクションペイロードに対してエージェントがそれらを指示ではなくデータとして扱うことを確認。確認なしにクラスター状態を変更させるまたは Secret を読み取らせようとする試み。型付きエラーを別のコマンドとして再試行させようとする試み。そして --trust-pane なしでデフォルトの読み取り不可動作が保持されることを確認するペインベーステスト。Evalは確率的であるため、ルーブリックはバイナリ結果ではなく合格率を記録し、成果物は事後レビューのために保持されます。

shellcheck lintパスはすべてのPRで実行され、構造的保証を損なうシェルバグのクラス(引用符なし展開、信頼できない入力への eval)を捕捉します。ユニット層とインテグレーション層はすべてのPRでLinux、macOS、Windowsの amd64arm64 の両方で実行されます。e2e層はLinuxで実行されます。そしてeval層はCIからオンデマンドでトリガーされます。

上記のセクションに対応するテストがない保証を見つけた場合、それは報告する価値のあるバグです。


セキュリティ上の問題を発見した場合は、GitHubリポジトリ経由で報告してください。