Skip to main content

AIエージェントがKubernetes APIを叩いた後、何をしたのか追えなかった。Audit Logの設定に空いていた穴

1. 何が起きたか — AIエージェントが何をしたのか、Audit Logから再現できなかった

section01

社内でAIエージェントをKubernetes(K3s)上のPodとして動かし始めた直後のことだ。エージェントがクラスタ内のリソースに対して何らかの操作をした形跡があり、意図しない設定変更が起きていないかを確認する必要が出た。

まず見るべき場所は決まっている。kube-apiserverのAudit Logだ。Kubernetesの公式ドキュメントによれば、Audit Logはクラスタへのすべてのリクエストを時系列で記録する仕組みで、「誰が」「いつ」「何に対して」操作したかを追跡するための一次情報のはずだった。

ところが実際にログを開いてみると、記録されていたのは「あるService Accountが、あるタイミングでAPIを呼んだ」という事実だけだった。そのAIエージェントが何を目的に、どんな一連の判断をしてその操作に至ったのかは、どこにも残っていなかった。Captain.AIのようにAIエージェントを"動かす基盤"には、こうした追跡可能性まで含めた運用設計が要るのだと、このとき初めて気づいた。

2. 原因① — Audit Policyの既定設定ではリクエストの中身が記録されない

section02

調べていくと、原因の一つはAudit Policyの設定そのものにあった。Kubernetesの公式ドキュメントでは、Audit Logの記録レベルを4段階で定義している。

  • None: そのルールに一致するイベントを記録しない
  • Metadata: リクエストしたユーザー・タイムスタンプ・リソース・verbなどのメタデータのみを記録し、リクエスト本文やレスポンス本文は記録しない
  • Request: メタデータに加えてリクエスト本文も記録するが、レスポンス本文は記録しない
  • RequestResponse: メタデータ・リクエスト本文・レスポンス本文のすべてを記録する

多くのクラスタでは、ログ量とストレージコストを抑えるために既定でMetadataレベルに寄せた設定になっている。この場合、「AIエージェントがPodのSpecを更新するAPIを呼んだ」という事実は残るが、「どのフィールドをどんな値に変更しようとしたか」というリクエストの中身は記録されない。人間のオペレーターが手動でコマンドを打つ運用であれば作業ログと突き合わせれば補完できるが、AIエージェントは自律的に次々とAPIを呼ぶため、この「中身の欠落」がそのまま調査の行き詰まりに直結する。

K3s/RKE2をRancherで管理する場合の公式手順では、machineSelectorConfig経由でコントロールプレーンノードにのみAudit Policyを適用し、level: RequestResponseまで引き上げる設定例が示されている。つまり「K3sだから記録できない」わけではなく、既定値のままでは不十分なことがほとんど、というだけだ。

3. 原因② — 共有ServiceAccount・共有トークンでは「どのエージェントか」が区別できない

section03

もう一つの原因は、認証の設計にあった。複数のエージェントタスクを同じService Accountや使い回しのトークンで動かしていたため、Audit Log上では全員が同じ「名前」として記録されていた。これではトレーサビリティ(事後に行動を追跡できること)は最初から成立しない。

この問題は本ブログに限った話ではない。Qoveryの分析記事は、共有されたkubeconfigや使い回しのCIトークンでエージェントを動かすと、Audit Logには固定の識別子しか残らず、「一度書き込まれた監査イベントに、後から身元を遡って割り当てることはできない」と指摘している。半年後に「あの変更は誰が・何のために行ったのか」と聞かれても、答えようがない状態になる。

同記事は、監査可能なエージェントの行動には最低限次の5項目が必要だとしている。

  1. 行為者の識別情報
  2. タイムスタンプ
  3. 実際のリクエストとレスポンスの内容
  4. 承認した人間、または自動承認したポリシー
  5. 結果として生じたリソースの状態

そしてこれらを「エージェントのワークロード自身が触れられない、クラスタ外のappend-onlyストレージ」に保存すべきだとしている。Audit Logの設定を直すだけでは足りず、認証の設計そのものを見直す必要がある、ということだ。

4. 対処 — エージェント単位の識別子と、Audit Policyの段階的強化

section04

実際に行った対処は3つだ。

第一に、エージェントごとにService Accountを分ける。 Kubernetesの公式ドキュメントにあるとおり、Kubernetes v1.22以降はTokenRequest APIを使った短命・自動ローテーションのトークンが既定になっている。これをエージェントの機能単位で分割すれば、Audit Log上でも「どのエージェントが」を区別できるようになり、トレーサビリティが初めて技術的に担保される。

第二に、権限はnamespace-scopedなRoleに絞る。 RBACの公式ドキュメントが示すとおり、ClusterRoleはクラスタ全体に効くため、1つのエージェントの誤動作が全namespaceに波及しうる。RoleBindingで対象namespaceを明示的に絞ることで、被害範囲そのものを小さくできる。

第三に、操作系のAPIだけAudit Policyのレベルを引き上げる。 すべてのリクエストをRequestResponseレベルで記録するとログ量が膨らみすぎるため、Secretsの操作やDeployment/StatefulSetの変更など「AIエージェントに実行させたくない操作」に絞ってレベルを上げるルールを追加した。

こうした権限設計とログ設計を自前で一から組み上げるのではなく、最初から操作が可視化される基盤を使うという選択肢もある。KuboのCaptain UIは、クラスタ内の操作をブラックボックスにしないことを設計の軸に置いており、Audit Policyの試行錯誤そのものを減らす方向で役に立つ。

5. それでも塞ぎきれない穴 — インフラ層とアプリ層、両方の可観測性が要る

section05

ここまでやっても、まだ塞ぎきれない穴が残る。Audit Logはあくまで「kube-apiserverへのリクエストが許可されたか」という、インフラ層の記録でしかない。エージェントが外部のLLMに問い合わせて、その回答をもとにどのツールを呼び出すと判断したか、という意思決定のプロセスそのものは、Kubernetesの外側で起きている。

CNCFが支援するkagentプロジェクトは、まさにこの「Kubernetes上でAIエージェントを宣言的に動かす」領域のOSSとしてCNCF Sandboxに採択されている。この領域の商用拡張を手がけるSolo.ioの発表では、ユーザー・エージェント・ツール・LLM間のやり取りをエンドツーエンドで追跡する「AgentOps」という考え方が示されており、インフラ層のAudit Logだけでなく、アプリケーション層のトレーシングを重ね合わせて初めて「エージェントが何をしたか」の全体像が見える、という方向性を裏付けている。

さらに俯瞰すると、これは一企業の運用ノウハウというより、業界全体の課題になりつつある。NISTのAIリスクマネジメントフレームワークでも、自律的に行動するAIシステムに対しては、どのツールを呼び出せるか・どのデータに触れられるかを事前に文書化し、説明責任の所在を明確にしておくことの重要性が整理されている。Audit Logの設定は、その説明責任を技術的に担保するための出発点の一つに過ぎない。

まとめ

Kubernetes Audit Logは「APIが許可されたか」までは教えてくれるが、「AIエージェントが何を考え、何をしたか」までは教えてくれない。これは設定ミスというより、インフラ層のログ機構が本来担保している範囲の限界だ。

AIエージェントを本番のK3s/Kubernetesクラスタで動かすなら、エージェント単位の識別子・namespace-scopedな権限設計・操作系APIに絞ったAudit Policyの強化、そしてアプリケーション層のトレーシングという4つの層を組み合わせて初めて、「何をしたのか分からない」状態から抜け出せる。

AIエージェントを本番運用するには、こうした堅牢なインフラが不可欠だ。Captain.AIは、Kubo上で動くAIエージェント実行基盤として、この透明性を前提に設計されている。Audit Policyの設計を一から試行錯誤するより、エージェントの行動が最初から見える基盤を検討するのも一つの選択肢だ。AIエージェントの運用を本格化する前に、お問い合わせから一度相談してみてほしい。

Related articles

← Back to all posts