標籤: Kubernetes

  • Google AX 多代理調度與網路隔離實戰

    Google AX 多代理調度與網路隔離實戰

    📌 本文重點

    • 將 Agent 視為 K8s Job 可利用現有雲原生能力
    • 單靠 LLM sandbox 不足,必須做 OS/網路層隔離
    • wire format 會吃掉 port 是「Agent Egress Illusion」關鍵風險
    • eBPF 或 sidecar proxy 可實作可驗證的 egress 控制

    在多代理(multi-agent)系統裡,真正麻煩的不是「叫一個 LLM 幫你想辦法」,而是如何安全地讓一堆有能力執行程式碼的 Agent,在企業網路裡被可靠調度、精準限權、可觀測且可驗證地被關起來。Google AX 給了一個值得抄的架構:把 Agent 當 Kubernetes Job 來排程,所有工具和憑證都以最小權限下放,同時嘗試提供精細網路出口控制——但也踩到一個 wire format 的安全坑。

    這篇文章會聚焦三件事:

    1. 設計層:為何要把 Agent 當 Job 調度、如何在企業環境做最小權限隔離。
    2. 實作層:以 AX 風格實作一個精簡版 Go agent runner,含 agent spec、network policy、執行沙盒 配置樣板。
    3. 資安與踩坑:解析「Agent Egress Illusion」中 port 資訊丟失 bug,示範用 eBPF 或 sidecar proxy 做真正可驗證的 egress 控制,以及應自動化的安全檢查。

    重點說明

    1. 為何把 Agent 當 K8s Job 調度?

    AX 的核心設計是:每個 Agent/任務就是一個可觀測、可重試的 Job,而不是一個長駐服務。這帶來幾個直接好處:

    • 資源隔離自然落在 Pod/Job 邊界:CPU / memory / volume / ServiceAccount 都用現有 K8s 原生能力。
    • 權限最小化更容易實作:不同工具/憑證綁在不同 Job template 上,下發時只給需要的那一份。
    • 重試與狀態同步內建:Job 狀態是可觀測事件流,AX 做的是把這些 event 封裝成 Agent 狀態機(state machine),方便 orchestrator 決策下一步。

    對你的專案來說,這代表:

    • 不用自己重新發明一套 job scheduler,照 K8s Job 範式套一層 Go orchestration 即可。
    • 多 Agent 協作 = 多 Job 工作流,你可以在 Go 裡用 DAG / state transition 描述整個流程。

    💡 關鍵: 把每個 Agent 當一次性 Job,可直接沿用 K8s 的資源隔離與重試機制,避免重造 scheduler 輪子。

    2. AX-style Agent Spec 與精細網路控制

    AX 用一個類似「AgentSpec」的結構描述每個 Agent:

    • 要跑的 tool image / command
    • 限制的 network egress 規則(domain / IP / port)
    • 授權的 secrets / credentials

    它宣稱可以做到「精細網路出口控制」,但在 wire format 的 protobuf/JSON 中,port 資訊沒被帶到真正執行的層級,導致你以為只開 443,實際上所有 port 都能出去,這就是「Agent Egress Illusion」。

    這個教訓是:

    • 不要只相信 API 層的 policy,必須驗證到 socket 層。
    • 對自己寫的 orchestrator,要有「從 UI → spec → wire → kernel」的完整 trace,確認資訊沒有在中途被丟失或過度簡化。

    3. 為何單憑 LLM sandbox 不夠?

    LLM sandbox 做的通常是:

    • 限制 prompt 能呼叫哪些工具
    • 限制工具的參數範圍

    但實務上常見攻擊路徑是:

    • 反向殼層(reverse shell)回到攻擊者機器
    • 內網掃描打開更多攻擊面
    • 泄漏環境中的 API key / DB credentials

    這些都不會被「prompt-sandbox」阻止,只有 OS / network layer 的硬性隔離才有用:namespace、cgroup、iptables、eBPF、sidecar proxy 等。


    實作範例:精簡版 AX-style Agent Runner(Go)

    下面是一個簡化示意,展示如何在自己專案做一個 AX 風格的調度層。重點在 AgentSpec、NetworkPolicy、以及 runner 如何執行與觀測。

    1. 定義 Agent Spec 與 Network Policy

    // AgentSpec 描述一個可被調度的 Agent 任務
    type AgentSpec struct {
        ID      string
        Image   string
        Command []string
        Env     map[string]string
    
        Network NetworkPolicy
        Secrets []string // reference to secret IDs
    }
    
    // NetworkPolicy 為每個 Agent 定義 egress 規則
    type NetworkPolicy struct {
        AllowedDestinations []DestinationRule
    }
    
    type DestinationRule struct {
        Host  string // example.com or 10.0.0.0/24
        Port  int    // 0 表示任何 port(強烈不建議在生產環境使用)
        Proto string // tcp/udp
    }
    

    這個 Spec 可以直接當成你自己的 API 層 contract。關鍵是:

    • 不要在任何一層「自動忽略」Port,即使使用者沒填,也要在 schema 上明確設定預設值與含義。
    • 在轉成 wire format(JSON / protobuf)時,保證欄位不被省略。

    2. Runner:把 Agent Spec 下放到 Worker 節點

    下例示範一個最小可用 runner:從 queue 拿到 AgentSpec,spawn 一個 container(可以是 K8s Job、或本機用 container runtime)並附帶 network policy:

    type Runner struct {
        // 抽象的 container 執行介面,可以是 K8s client,也可以是本機 Docker
        Exec ExecBackend
    }
    
    type ExecBackend interface {
        Run(spec AgentSpec) (RunHandle, error)
    }
    
    // K8sJobBackend 是一個以 K8s Job 為基礎的實作
    type K8sJobBackend struct {
        // kube client, omitted
    }
    
    func (b *K8sJobBackend) Run(spec AgentSpec) (RunHandle, error) {
        job := BuildK8sJobFromAgent(spec)
    
        // 將 NetworkPolicy 轉成 K8s NetworkPolicy 或 CNI 插件規則
        np := BuildNetworkPolicyFromAgent(spec)
    
        // 建議:先創 NetworkPolicy,再創 Job
        if err := b.applyNetworkPolicy(np); err != nil {
            return RunHandle{}, err
        }
        if err := b.createJob(job); err != nil {
            return RunHandle{}, err
        }
    
        return RunHandle{ID: spec.ID}, nil
    }
    

    其中 BuildNetworkPolicyFromAgent 是重點,用來把 AX-style 的 egress 規則真正落到 K8s 或底層 CNI:

    func BuildNetworkPolicyFromAgent(spec AgentSpec) *netv1.NetworkPolicy {
        // 示意:將每個 DestinationRule 轉為 egress rule
        // 注意:K8s NetworkPolicy 的 port 是獨立欄位,不能在轉換時丟掉
    }
    

    如果你不想依賴 K8s NetworkPolicy,也可以直接用 sidecar proxy 控制:

    • 為每個 Agent Pod 加一個 envoy/mitmproxy sidecar。
    • 在 sidecar config 中生成 per-Agent egress ACL。

    3. 觀測與狀態同步

    AX 的設計亮點之一是狀態同步與觀測。你可以在 runner 裡加上一層事件流:

    type AgentStatus string
    
    const (
        StatusPending AgentStatus = "PENDING"
        StatusRunning AgentStatus = "RUNNING"
        StatusSuccess AgentStatus = "SUCCESS"
        StatusFailed  AgentStatus = "FAILED"
    )
    
    type StatusStore interface {
        Update(id string, status AgentStatus, meta map[string]string) error
    }
    
    func (r *Runner) RunAndWatch(spec AgentSpec, store StatusStore) error {
        handle, err := r.Exec.Run(spec)
        if err != nil {
            return err
        }
    
        store.Update(spec.ID, StatusRunning, nil)
    
        go func() {
            result := handle.Wait()
            if result.Err != nil {
                store.Update(spec.ID, StatusFailed, map[string]string{"error": result.Err.Error()})
            } else {
                store.Update(spec.ID, StatusSuccess, nil)
            }
        }()
    
        return nil
    }
    

    這樣你即可在前端或控制平臺上,實時看到每個 Agent 的狀態,並進行工作流編排(例如下一個 Agent 只有在上一個成功時才啟動)。


    資安與踩坑:Agent Egress Illusion 與真正可驗證的控制

    1. Agent Egress Illusion:port 資訊在 wire format 被吃掉

    簡化來說,問題長這樣:

    1. Config / UI 層支援 host+port,例如:example.com:443。
    2. Spec 序列化成 wire format(JSON / protobuf)時,只保留 example.com,port 被 default 掉(例如 0 或空)。
    3. 執行層的 network module 把「空 port」解讀為「any port」。

    結果:你以為自己寫了 allow example.com:443,實際執行的是 allow example.com:*,甚至 allow *:*。

    避免同樣踩坑,最實際的做法是:

    • 在 schema 層面強制 port 必填或有明確預設邊界(例如只允許 80/443)。
    • 在 wire / decode 層加 結構化驗證:任何 Host 沒設定 Port 就拒絕部署。
    • 寫端到端測試,驗證「指定 port 不同時,實際 socket 行為不同」。

    💡 關鍵: 只要 port 在序列化或 decode 過程被默默 default,實際執行的網路權限就會遠超過 UI 上看到的設定。

    2. 用 eBPF 做真正可驗證的 egress 控制

    在 Linux 上,可以用 eBPF 寫一段針對 connect() 的 hook,根據 Agent ID + 目的 host/port 做精細控制。示意邏輯(偽 C):

    int sock_connect(struct bpf_sock_addr *ctx) {
        __u16 dport = bpf_ntohs(ctx->user_port);
        struct agent_policy *policy = lookup_policy_for_current_pid();
    
        if (!policy) return 0; // 無 policy 的情況下可選擇允許或拒絕
    
        if (!policy_allows(policy, ctx->user_ip4, dport)) {
            return -EPERM; // 直接阻擋
        }
        return 0;
    }
    

    然後在 Go runner 裡,為每個 Agent 產生對應的 eBPF policy map:

    func InstallEBPFPolicy(agentID string, net NetworkPolicy) error {
        // 1. 將 AgentID 映射到一個 cgroup 或 pid namespace
        // 2. 將 DestinationRule 寫入 eBPF map
        return nil
    }
    

    這樣你可以做到:

    • policy 與 socket 在同一層被驗證,不再依賴高層配置是否完整。
    • 可以收集 eBPF 事件,作為 shadow env 觀測:任何違反 policy 的連線都會被紀錄,甚至被 fuzz 測試工具捕捉。

    3. Sidecar Proxy 方案(較好上手)

    如果 eBPF 對團隊太重,你可以選擇 sidecar proxy:

    • 每個 Agent Pod 都透過 sidecar 發出所有外部連線。
    • AX-style NetworkPolicy 轉成 proxy 的 ACL:
    # envoy filter pseudo config
    - name: agent-egress-filter
      typed_config:
        allowed_destinations:
          - host: example.com
            port: 443
          - host: api.internal
            port: 8443
    

    對開發者來說,這個方案的優點是:

    • 配置全部在 user space,容易 debug。
    • 可以在 staging 做 policy fuzzing:自動產生隨機目標,確認 proxy 確實阻擋。

    建議與注意事項

    1. 三件必做的自動化安全檢查

    1. 端到端 egress 測試:
    2. 建一個專門的 Agent,用來嘗試從各種 host/port 打出去。
    3. CI 裡檢查:不應該開放的目標全部連線失敗。

    4. policy fuzzing:

    5. 針對你的 NetworkPolicy 模組,用模糊測試工具產生多組 host/port 組合,確認 decode / merge 過程不會產生意外的「any port」。

    6. shadow env 觀測:

    7. 在 staging/灰度環境,把所有 egress 事件打到一個集中 log。
    8. 針對異常 pattern(例如 Agent 對內網 IP 連線)設 alert。

    2. 多代理環境常見安全誤區

    • 只做 prompt 限制不做網路限制:LLM 只要能呼叫 bash 或 python,就能繞過任何 prompt policy。
    • 所有 Agent 共用一組 API key 或 ServiceAccount:一旦有 Agent 被利用,就等於全網被打開。
    • 忽略內網掃描:很多團隊只防外聯,不防 Agent 對內網執行 nmap/port scan,結果是 lateral movement 更容易。

    實務建議:

    • 每個 Agent 類型一個 最小權限 ServiceAccount,不要共用。
    • 有寫檔需求的 Agent,只給 只讀/只寫的特定 volume,避免觸及主機檔案系統。
    • 將所有 egress 限制在白名單 domain,而不是黑名單。

    💡 關鍵: 多代理環境的核心風險在橫向移動與憑證濫用,因此需以最小權限帳號和白名單 egress 為設計預設。

    3. 如何在現有專案落地 AX-style 架構

    • 已有 K8s:
    • 直接定義自己的 Agent CRD + Controller,用上文的 AgentSpec 當 schema,K8s Job 當執行層。
    • 接上 NetworkPolicy 或 sidecar proxy,做 per-Agent egress。

    • 沒有 K8s、純 VM/裸機:

    • 用 Go Runner + container runtime(Docker / containerd),以 namespace + iptables 或 eBPF 做隔離。
    • 同樣透過 AgentSpec 描述任務,確保 spec → runtime 的 mapping 可觀測。

    核心結論:

    • 把 Agent 當 Job 調度,可以用現有雲原生堆疊快速搭起可擴充的多代理平臺。
    • LLM sandbox 絕對不夠,必須有實體網路與系統層的防護,並且用 eBPF 或 sidecar 這類「可驗證」的手段落實。
    • 在設計 Agent 平臺時,wire format 不可忽視,任何欄位(尤其是 port)一旦在序列化過程中被吃掉,就會變成下一個「Agent Egress Illusion」。

    🚀 你現在可以做的事

    • 在現有專案中定義一個 AgentSpec 結構,試著用 K8s Job 或 Docker 實作最小可用 runner
    • 為某個測試 Agent 建立白名單 egress 規則,實驗一版 sidecar proxy 或 NetworkPolicy 的落地做法
    • 寫一個簡單的 egress 測試 Agent,加入 CI 流程,驗證你的網路策略沒有出現「any port」的隱形放寬
  • Kubernetes 安全跑 AI Agent 的四種隔離架構

    Kubernetes 安全跑 AI Agent 的四種隔離架構

    📌 本文重點

    • 不要讓 Agent 直接在應用 Pod 裡執行 shell
    • 把程式碼執行抽象成獨立 Exec API
    • 依需求從 Sidecar 演進到 Dispatcher + microVM

    在 Kubernetes 上跑 AI Agent,最大痛點不是「模型怎麼接」,而是:我要讓 Agent 能執行程式碼,但又不想整個 cluster 變成 root shell 即時互動環境。這一篇用四種實戰隔離模式,從 完全禁止 exec 到 短暫 sandbox,給你一個能落地、能演進、不會把未來自己鎖死的設計路線。

    兩個基本原則先講清楚:
    1. 不要讓 Agent 直接在應用 Pod 裡 exec /bin/sh
    2. 把「執行程式碼」當成一個獨立產品線,至少要有 API、隔離與審計


    重點說明

    1. 四種 Exec 隔離模式與威脅模型

    1. No-Exec 基線
    2. 威脅模型:Agent 只能讀資料、呼叫 API,不允許任意程式碼或 shell。防止「自動化腳本變挖礦機」。
    3. 使用情境:報表、客服、內部 FAQ、只讀資料查詢。
    4. 成本/延遲:最低;只要你有 Agent,就應該先有這個 baseline。

    💡 關鍵: 先建立 No-Exec 基線,把「不執行程式碼也能運作」當成預設安全狀態,之後才有空間加能力而不是拆炸彈。

    1. Sidecar Exec Server
    2. Agent Pod 旁邊掛一個 sidecar 容器,提供 受限的程式碼執行 API(例如只允許 Python,禁網路)。
    3. 威脅模型:Agent 若被 prompt 注入,最多傷到 該 Pod 的 sandbox,不會拿到整個 node。
    4. 使用情境:需要頻繁、小量運算(轉檔、格式化、查詢小 DB)。
    5. 成本/延遲:啟動快、延遲低,但隔離仍與主容器共享同個 Pod 命名空間,需嚴控權限。

    6. 獨立 Exec Pod(長駐)

    7. 用 單獨 Deployment/Pod 提供 Exec API,Agent 透過 Service/HTTP 呼叫。
    8. 威脅模型:即使 Agent 被攻擊,影響範圍收斂在 Exec Pod 的 namespace / RBAC。
    9. 使用情境:多 Agent 共用運算資源、內部「程式碼執行服務」。
    10. 成本/延遲:多一跳網路,但隔離與資源配額更好控制。

    11. 短暫性 Exec Dispatcher(Job / ephemeral Pod)

    12. 每次高風險程式碼執行,Agent 呼叫 Dispatcher API → 建立一次性 Job/Pod → 執行完就刪。
    13. 威脅模型:攻擊者很難長期駐留,每次都是新 sandbox;配合 NetworkPolicy、seccomp,接近 microVM 的防護。
    14. 使用情境:自動修 production bug、CI 內部 code 修補、批次資料轉換。
    15. 成本/延遲:啟動開銷高,但安全性最佳、審計最容易。

    💡 關鍵: 短暫性 Dispatcher 每次執行都重建 sandbox,換取較高延遲,換來接近 microVM 等級的隔離與容易審計。


    2. 把 Exec 抽象成 API:Agent 只看見一個能力

    不論選哪種模式,推薦都做成一個 Exec API 抽象層:

    • Agent 視角:呼叫 /exec,送程式碼和限制(language、timeout、resources),拿回 stdout/stderr。
    • 基礎設施視角:背後可以從 Sidecar → 獨立 Pod → Dispatcher/Job 演進,而介面不變。

    這樣可以避免那種常見悲劇:

    「先在應用容器裡 subprocess.run 上線,等 Agent 用到 everywhere 之後才發現安全有洞,想拆出來卻動不了。」

    💡 關鍵: 先穩定 Exec API 介面,再替換背後實作,可以避免一開始圖方便埋下日後無法重構的安全技術債。


    3. 與 microVM(如 SuperHQ)怎麼搭配?

    像 SuperHQ 這種 microVM 沙盒 的隔離更硬(虛擬化層級),但成本與管理更重。實務上可以:

    • Kubernetes 內部先用 短暫性 Exec Dispatcher 做 cluster 級隔離。
    • 對於「真的可能動 production」的改動,Dispatcher 再往下調用像 SuperHQ 的 microVM sandbox,做二層隔離。

    關鍵是:不要一開始就把 microVM 當銀彈,反而要先把 API、審計、RBAC 的基本盤打好。


    實作範例

    1. 給 Agent 的 Exec API 抽象

    假設你在後端提供一個 POST /exec 給 Agent 使用:

    // TypeScript / pseudo-code
    interface ExecRequest {
      language: 'python' | 'bash';
      code: string;
      timeout_ms?: number;
      memory_mb?: number;
      audit_metadata?: {
        agent_id: string;
        user_id: string;
        task_id: string;
      };
    }
    
    interface ExecResponse {
      stdout: string;
      stderr: string;
      exit_code: number;
      sandbox_id: string;
      started_at: string;
      finished_at: string;
    }
    
    // Agent 只呼叫這個
    async function agentExec(req: ExecRequest): Promise<ExecResponse> {
      const resp = await fetch("https://exec-gateway.internal/exec", {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(req),
      });
      return resp.json();
    }
    

    背後可以是 Sidecar、獨立 Pod 或 Dispatcher,Agent 完全不需要知道。


    2. Sidecar Exec Server:最小可行安全版

    Pod 範例(主容器 + Sidecar):

    apiVersion: v1
    kind: Pod
    metadata:
      name: agent-with-sidecar
    spec:
      containers:
        - name: agent
          image: myorg/agent:latest
          env:
            - name: EXEC_SERVER_URL
              value: "http://127.0.0.1:8080"  # 只在 Pod 內可達
    
        - name: exec-sidecar
          image: myorg/exec-sandbox:py3
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            seccompProfile:
              type: RuntimeDefault
            capabilities:
              drop: ["ALL"]
          volumeMounts:
            - name: tmp
              mountPath: /tmp
      volumes:
        - name: tmp
          emptyDir: {}
    

    注意幾點:

    • Sidecar 用 readOnlyRootFilesystem: true,只給一個 emptyDir 當 scratch space。
    • 用 seccompProfile: RuntimeDefault + capabilities: drop: ["ALL"] 擋掉大多數系統呼叫。
    • exec server 只在 localhost 對 agent 開放。

    Sidecar 容器內部可用像這樣的 server:

    # exec-sidecar main.py (簡化示意)
    from fastapi import FastAPI
    import subprocess, tempfile, textwrap
    
    app = FastAPI()
    
    @app.post("/exec")
    async def exec_code(req: dict):
        code = req["code"]
        timeout = min(req.get("timeout_ms", 5000) / 1000, 10)
        with tempfile.NamedTemporaryFile(suffix=".py", dir="/tmp", delete=False) as f:
            f.write(code.encode("utf-8"))
            path = f.name
        p = subprocess.run(
            ["python", path],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=timeout,
            check=False,
            text=True,
        )
        return {
            "stdout": p.stdout,
            "stderr": p.stderr,
            "exit_code": p.returncode,
        }
    

    3. 獨立 Exec Pod + NetworkPolicy 限制網路

    Exec Service Deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: exec-service
      namespace: agent-exec
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: exec-service
      template:
        metadata:
          labels:
            app: exec-service
        spec:
          securityContext:
            runAsNonRoot: true
          containers:
            - name: exec
              image: myorg/exec-sandbox:py3
              securityContext:
                allowPrivilegeEscalation: false
                readOnlyRootFilesystem: true
                seccompProfile:
                  type: RuntimeDefault
              resources:
                limits:
                  cpu: "1"
                  memory: "1Gi"
    

    NetworkPolicy:只允許 Agent Namespace 打進來,不允許對外上網:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: exec-deny-egress
      namespace: agent-exec
    spec:
      podSelector: { matchLabels: { app: exec-service } }
      policyTypes: ["Ingress", "Egress"]
      ingress:
        - from:
            - namespaceSelector:
                matchLabels:
                  name: agent
      egress: []  # 不允許任何外連
    

    搭配 RBAC:只給 Agent ServiceAccount 能呼叫 Exec Service,不給其他 Pod 用。


    4. 短暫性 Exec Dispatcher:一次一個 Job

    Dispatcher 可以是一個常駐服務,收到 Agent 的 Exec Request 後,動態建一個 Job:

    apiVersion: batch/v1
    kind: Job
    metadata:
      generateName: exec-task-
      namespace: agent-exec
    spec:
      ttlSecondsAfterFinished: 60
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: runner
              image: myorg/exec-runner:py3
              command: ["python", "/runner/run.py"]
              env:
                - name: CODE_B64  # 程式碼以 base64 傳入
                  value: "{{ .code_b64 }}"
              securityContext:
                runAsNonRoot: true
                allowPrivilegeEscalation: false
                readOnlyRootFilesystem: true
                seccompProfile:
                  type: RuntimeDefault
    

    Dispatcher 伺服器(簡化 pseudo-code):

    // create Job + watch logs/exit code
    async function handleExec(req: ExecRequest): Promise<ExecResponse> {
      const jobName = await k8sCreateJobFromTemplate(req.code);
      const { logs, exitCode } = await waitForJobAndCollectLogs(jobName);
      await writeAuditLog({
        sandbox_id: jobName,
        ...req.audit_metadata,
        code_hash: hash(req.code),
        exit_code: exitCode,
      });
      return {
        stdout: logs.stdout,
        stderr: logs.stderr,
        exit_code: exitCode,
        sandbox_id: jobName,
        started_at: new Date().toISOString(), // 真實實作請用 Job status
        finished_at: new Date().toISOString(),
      };
    }
    

    好處:

    • 多租戶隔離:可依 tenant 建不同 namespace,Dispatcher 根據 audit_metadata.tenant_id 選 namespace。
    • 審計完整:所有指令、結果都在 Job + audit log 裡,符合合規需求。

    建議與注意事項

    1. 多租戶 / 多 Agent:Namespace + RBAC 要先設計好

    • 每個 tenant / 敏感業務線,用不同 namespace + ServiceAccount。
    • 用 RBAC 控制:
    • 哪些 Agent 可以呼叫哪些 Exec Service / Dispatcher API。
    • 哪些 ServiceAccount 可以在哪些 namespace 建 Job。
    • 禁用 kubectl exec 這類廣泛權限,改成只允許建立特定 label 的 Job。

    2. 記錄與審計:把 Agent 當「能下命令的人」對待

    最少要記:

    • 誰發的指令:agent_id, user_id, tenant_id。
    • 執行了什麼:程式碼 hash / snippet、image name、namespace。
    • 結果:exit code、stdout/stderr 片段、耗時、資源消耗。

    實務建議:

    • 把審計資料寫到 集中 log(如 Loki / Elasticsearch),設 index pattern 方便 incident 回溯。
    • 敏感環境可以啟用 只讀審計存儲(append-only S3、WORM 存儲)。

    3. 選型決策表:怎麼組合四種模式?

    公司安全等級 / 場景 建議模式組合
    內網 demo、無敏感資料 No-Exec 基線;需要運算再加 Sidecar Exec。
    一般內部工具,允許 Agent 自動改測試 / 小腳本 獨立 Exec Pod + NetworkPolicy + RBAC;高風險任務用 Dispatcher。
    有合規需求(金融、醫療)、多租戶 SaaS 短暫性 Exec Dispatcher + 多 namespace + 強 RBAC + 完整改審計。
    能直接動 production(自動修 bug、自動部署) Dispatcher + microVM(如 SuperHQ)疊加;需要人類 review gate + 強審計。

    實務路線建議:

    1. 先上 No-Exec baseline:把所有「執行程式碼」需求集中到一個 Exec API 服務。
    2. 需求變多 → 用 獨立 Exec Pod + NetworkPolicy 接手 Sidecar。
    3. 需要自動動 production → 引入 短暫性 Exec Dispatcher +(選配)microVM。

    最後再提醒一次:最危險的不是沒用 sandbox,而是先圖方便在應用容器裡直接 exec shell,等 Agent 真的有價值時,整個 cluster 已經跟它綁死,誰都不敢動。現在就把 Exec 抽出來,之後演進才有空間。


    🚀 你現在可以做的事

    • 檢查現有 Agent 是否在應用 Pod 內直接 exec 或 subprocess.run,列出需遷移的路徑
    • 在開發環境先實作一個簡單的 POST /exec 抽象層,後端先接到一個獨立 Exec Pod
    • 為高風險任務 PoC 一個「短暫性 Exec Dispatcher + Job」流程,並加上最基本的審計欄位