ai-agent / sre / observability / security / mcp
生产排障 Agent 的安全边界:为什么只读 SSH 不是默认方案
生产排障 Agent 的安全边界:为什么只读 SSH 不是默认方案
Codex、Claude Code、Gemini CLI 这类 agent 已经能在代码库里读上下文、跑命令、整理证据、提出假设。把它们带进生产排障,不是很远的事。
容易走偏的做法,是给 agent 建一个只读 Linux 账号,让它 SSH 到生产机器上查问题。
这个方案启动很快,也显得克制。没有 sudo,不改文件,不重启服务。可生产环境里的“读”从来不是简单权限。日志、环境变量、配置、core dump、备份、/proc、Kubernetes 对象,很多东西只要能读,就能带出凭证、客户数据或内部拓扑。
日常入口不该是普通 SSH shell,而应放在观测系统、生产日志查询能力和 incident 上下文上。agent 先读 SLO、告警、metrics、logs、traces、发布记录、runbook 和服务拓扑,再通过受限 MCP 调用一组语义化诊断工具。SSH 可以保留,但要当 break-glass,用 forced command、allowlist、短期凭证和审计系统包住。
这里的“观测系统”不能只理解成 SLO 和告警。很多疑难 bug 不会立刻打爆 SLO,甚至不会触发 paging。它们只在某个租户、某类订单、某个浏览器版本、某种数据形态或某条异步链路里出现。定位这类问题,生产日志、trace、业务事件和请求时间线都可能是必要证据。问题不是能不能查日志,而是谁可以查、按什么范围查、能看到哪些字段、输出到哪里、事后如何审计。
模型能力只是前提。生产系统要先回答几个更无聊也更要命的问题:权限在哪里收口,数据在哪里脱敏,动作在哪里审批,事后能不能复盘。
借用 Google SRE 的自动化框架
Google SRE 的 The Evolution of Automation at Google 很适合拿来校准这个问题。那篇文章没有把自动化当成信仰,而是当成工程工具看待:自动化能带来一致性、平台化、更快的修复和更少的重复劳动,也会引入抽象泄漏、系统性误操作,以及人对系统理解的退化。
生产排障 agent 也要放在这个框架里看。它不是 SRE 的替代品,也不是“让模型登录机器”的理由。它更像一个取证和压缩上下文的自动化层:把 incident 或疑难 bug 期间分散在十几个系统里的证据收拢,按服务、时间线和假设组织起来,让人少花时间翻系统,多花时间判断。
Google SRE 的 Monitoring Distributed Systems 还给了一个约束:监控要围绕症状和用户体验,不要堆满底层原因猜测。对用户可见服务,延迟、流量、错误和饱和度是经典的 four golden signals。Service Level Objectives 则把可靠性管理放在 SLI、SLO 和目标失守后的反应机制上。
这并不等于所有问题都从 SLO 开始。更好的边界是:agent 不从机器细节开始。第一层事实要么是服务级证据,要么是请求级证据。前者包括哪个 SLO 受损、哪条用户路径受影响、错误预算消耗到什么程度、告警对应什么症状;后者包括 correlation id、trace id、时间窗口、业务对象、错误日志模式、最近发布和相关配置变化。
生产排障不是一个动作
“排障”这个词太粗。拆开以后,agent 该插在哪里会清楚很多。
| 阶段 | 目标 | Agent 的合适位置 | 主要风险 |
|---|---|---|---|
| 检测 | 发现 SLO 或症状异常 | 读取告警和上下文 | 不应替代监控链路 |
| 取证 | 收集 metrics、logs、traces、发布记录 | 适合 | 可能读到敏感数据 |
| 假设 | 排列可能的故障路径 | 适合 | 幻觉和过早收敛 |
| 决策 | 判断是否回滚、扩容、切流量 | 只能辅助 | 责任边界必须清楚 |
| 执行 | 改变生产状态 | 默认不适合 | 误操作影响最大 |
| 复盘 | 生成 timeline、证据和 action item | 适合 | 不能把猜测写成事实 |
第一版生产排障 agent 先集中在取证、假设和复盘。检测仍由 Prometheus、Cloud Monitoring、Datadog、Sentry、ARMS/SLS、Alertmanager 这类系统负责。执行仍由人或已有自动化系统负责。
这个边界并不保守。它只是把 agent 放在当前最有价值、也最容易控制风险的位置。
还要把 incident 和疑难 bug 分开。incident 通常从告警、SLO 或用户影响开始,目标是快速止血。疑难 bug 可能从客服工单、用户反馈、灰度验证、数据异常或某个业务对象开始,目标是还原路径、缩小触发条件、找到代码或数据假设里的错位。后一类问题更依赖生产日志查询,但也不需要普通 shell。
公开实践在避开什么
Google Cloud 的 Gemini Cloud Assist 把 AI 辅助运维放在 logs、metrics、traces、配置、代码和告警上下文里,并强调用户授权。Google 的 SAIF agent 安全框架 说得更直接:agent 会处理不可信上下文,推理循环可能被间接 prompt injection 影响,工具权限要最小化,输出渲染本身也是安全边界。它列出的控制点包括 agent permissions、user control、agent observability、output validation 和 sanitization。
阿里的公开资料也不是“让模型登录机器”。开源的 SREWorks 是云原生 DataOps & AIOps 平台。论文 MicroHECL 用服务调用图、RT/EC/QPS 异常、传播链和相关性排序做微服务根因定位。CloudRCA 把 KPI、日志和拓扑放进知识增强的 Bayesian Network,用来做云产品故障诊断。
读这些公开材料,能看到一个朴素结论:先把证据结构化。指标、日志、链路、拓扑、变更、服务关系、SLO 和可控的日志查询接口是推理基础。通用生产 shell 不是。
蚂蚁/支付宝的具体 LLM agent 生产排障方案,目前没有足够强的一手公开资料。不能把猜测写成案例。能稳妥借鉴的是金融级系统的安全标准:最小权限、数据隔离、审计、审批和敏感信息控制必须前置。这个标准本身就排斥普通只读 shell 作为默认入口。
能力层级要显式
Google SRE 讨论自动化演进时,把手工命令、脚本、系统外自动化和系统内部自治机制分开看。生产排障 agent 也要这样分层。否则团队很容易从“看一下日志”滑到“修一下生产”。
| 层级 | 能力 | 典型接口 | 第一版是否适合 |
|---|---|---|---|
| L0 | 只读文档和 runbook | 文档库、postmortem、告警说明 | 适合 |
| L1 | 读取 incident 上下文 | 工单、告警、dashboard 链接、发布记录 | 适合 |
| L2 | 读取观测和日志数据 | Prometheus、Sentry、日志平台、trace 平台 MCP | 适合 |
| L3 | 受限主机诊断 | host diagnostic MCP | 可以试点 |
| L4 | break-glass SSH | forced command wrapper | 只适合应急 |
| L5 | 审批式修复 | 回滚、扩容、切流量的固定 workflow | 需要演练后引入 |
| L6 | 自主修复 | agent 自己判断并执行生产动作 | 不适合第一版 |
每升一级,都要回答三个问题:
- agent 会多看到什么数据?
- agent 会多触发什么动作?
- 如果它错了,影响范围有多大?
答不清楚,就不要升级权限。
“只读”不是安全边界
“只读账号”听起来安全,因为它没有写权限。但生产系统里,读权限本身就很敏感。
Kubernetes RBAC 是一个好例子。Kubernetes 内置的 view role 能读大部分 namespace 对象,但默认不允许读取 Secrets,因为读取 Secrets 可能拿到 ServiceAccount 凭证并造成权限提升。成熟系统不会把 read-only 等同于 safe-to-read。
Linux 主机上也一样。一个只读账号可能读到:
- 原始日志里的 token、session、手机号、邮箱、用户输入。
- 服务配置里的数据库地址、内部域名、feature flag。
/proc/<pid>/environ里的环境变量。- core dump、heap dump、备份文件。
- shell history 和临时文件。
- Nginx、systemd、应用日志里的请求路径、header 或内部错误。
这些都不需要写权限。只要能读,就可能出事。
所以权限设计不能只问“这个账号能不能写”。还要问:这个工具会不会读到不该离开当前安全边界的数据?
SSH 的问题是接口太宽
SSH 本身没有问题。普通 shell 才是问题。它不是一个窄接口。
如果给 agent 一个普通 Linux shell,即使账号不能 sudo,也很难回答这些问题:
- 哪些命令被允许?
- 哪些目录永远不能读?
- 输出是否经过脱敏?
- 一次命令最多能跑多久?
- 一次最多输出多少内容?
- 是否允许端口转发?
- 是否允许 agent forwarding?
- 是否允许 TTY?
- 是否记录了原始命令、参数、输出摘要和 incident ID?
- 是否能把一次排障会话完整复盘?
OpenSSH 的 sshd 手册 支持在 authorized_keys 上配置 command=、restrict、no-pty、no-agent-forwarding、no-port-forwarding、no-user-rc、no-X11-forwarding。forced command 可以通过 SSH_ORIGINAL_COMMAND 拿到原始请求命令,然后由 wrapper 决定是否允许。
这可以把 SSH 包成受控入口。安全边界在 wrapper:
ssh key
-> forced command wrapper
-> parse SSH_ORIGINAL_COMMAND
-> command allowlist
-> argument validation
-> path denylist
-> timeout and output cap
-> redaction
-> audit
-> return bounded result
这个模式适合 break-glass,不适合日常入口。原因很简单:wrapper 最后会长成一个临时 MCP,只是协议更粗,输出更难结构化,策略更难复用。
MCP 的价值在工具边界
MCP 也不是安全魔法。暴露 run_shell(command) 的 MCP,和给 shell 没有本质区别。
MCP 的优势在于可以把能力设计成语义化工具:
get_service_slo(service, window)
get_alert_context(alert_id)
get_recent_deploys(service, window)
query_service_metrics(service, metric, window)
search_sanitized_logs(service, query, window, limit)
get_log_schema(service)
get_request_timeline(correlation_id, window)
get_error_examples(service, signature, window, limit)
compare_log_patterns(service, baseline_window, incident_window)
get_trace_error_summary(service, window)
get_runbook(service)
get_host_health(host)
危险接口通常是这些:
run_shell(command)
read_file(path)
kubectl(args)
sql(query)
curl(url)
前一组工具表达排障意图。后一组工具表达任意能力。差别不在命名风格,而在权限模型。
MCP 官方的 security best practices 已经列出 confused deputy、token passthrough、SSRF、session hijacking、本地 MCP server compromise、scope 过宽等风险。OpenAI Codex 的 MCP 文档 支持配置 enabled/disabled tools、默认审批模式和单工具审批策略。OpenAI Codex 的 permissions 文档 也把 read-only profile、deny 规则、network allowlist 作为权限控制手段。
这些机制指向同一个做法:把策略放在工具边界,而不是寄希望于模型自觉。
一个可落地的架构
生产排障 agent 不要直接挂在生产机器上。更合适的位置,是 incident investigation control plane。
Incident / Alert
-> context assembler
-> policy engine
-> observability MCP
-> diagnostic MCP
-> evidence store
-> human review
-> approved workflow or break-glass SSH
-> postmortem artifact
这套架构需要六个平面。
| 平面 | 职责 | 关键约束 |
|---|---|---|
| Identity plane | agent 用什么身份访问系统 | 独立身份、短期凭证、禁止共享个人 key |
| Policy plane | 决定哪些工具和数据可用 | 按服务、环境、incident scope 授权 |
| Data plane | metrics、logs、traces、配置、拓扑 | 字段级脱敏、限量、默认不读客户 payload |
| Tool plane | MCP 工具和 SSH wrapper | 语义化工具、禁止任意 shell |
| Audit plane | 记录 prompt、工具、参数、输出 | 能复盘每次读取和每次建议 |
| Evaluation plane | 验证 agent 是否可靠 | 历史 incident replay、红队 prompt、演练 |
最容易缺的是 evaluation plane。生产排障 agent 不是上线一个聊天框就结束。它需要像其他生产自动化一样被测试:
- 用历史 incident replay,看它能不能收集到关键证据。
- 用已知 root cause 的案例,看它是否过早下结论。
- 在日志、工单、网页片段里注入恶意指令,验证它是否把数据当成指令。
- 检查输出是否泄露 token、PII、内部拓扑。
- 评估它的建议是否符合 runbook 和变更流程。
- 记录它在 incident 中节省的时间,也记录它制造的误导。
没有 evaluation,agent 只是一个能访问生产上下文的文本生成器。
第一版做标准化取证和日志定位
第一版目标不要叫“自动排障”。先做“标准化取证和日志定位”。它要覆盖两种入口:告警或 incident 驱动的问题,以及生产日志驱动的疑难 bug。
一个可交付的 MVP 可以这样定义:
输入:alert_id、incident_id、bug_id、correlation_id、trace_id 或受控时间窗口
输出:
1. 受影响服务、相关 SLO 或业务路径
2. 如果没有 SLO 受损,给出请求级或业务对象级时间线
3. 最近 30 到 60 分钟的关键指标变化
4. 错误日志摘要,不含原始敏感字段
5. 相似错误样本和出现频率
6. 最近发布、配置、依赖和基础设施事件
7. 相关 runbook
8. 候选假设,按证据强弱排序
9. 下一步人工检查建议
10. 审计记录
对应的工具集合要小:
get_alert(alert_id)
get_bug_context(bug_id)
get_service_slo(service, window)
get_metric_snapshot(service, window)
get_log_schema(service)
search_sanitized_logs(service, query, window, limit)
get_request_timeline(correlation_id, window)
get_error_examples(service, signature, window, limit)
compare_log_patterns(service, baseline_window, incident_window)
get_trace_summary(service, window)
get_recent_changes(service, window)
get_runbook(service)
write_investigation_note(case_id, note)
这里允许查生产日志,但不允许随便查。查询必须绑定服务、环境、时间窗口、字段 allowlist、输出上限和 case id。优先使用 correlation id、trace id、request id、订单 id 的脱敏形式或内部业务对象 id。需要按手机号、邮箱、身份证、真实姓名这类 PII 检索时,应走更高审批等级,最好先由系统把明文字段转换成受控 token 或 hash。
第一版不应该包含:
run_shell
restart_service
rollback
kubectl
sql_query
read_file
curl
export_raw_logs
如果这一版没有价值,问题多半不在 agent。更可能是观测数据、runbook、服务拓扑和发布记录本身还没整理好。
安全红线
生产排障 agent 要有这些红线。
| 红线 | 原因 |
|---|---|
| 正常模式不给任意生产 shell | shell 是过宽接口 |
| 不给 sudo | sudo 直接跨过最小权限边界 |
不提供通用 read_file | 文件系统里有大量非预期敏感数据 |
不提供通用 kubectl(args) | Kubernetes API 太大,读写边界复杂 |
不提供通用 sql(query) | 数据库查询很容易触碰客户数据 |
| 不允许无限制导出原始日志 | 原始日志经常混有 token、PII 和业务敏感字段 |
| 不允许随意按 PII 明文检索 | 用户标识检索要有 case 绑定、审批和脱敏 |
| 不把 MCP 裸放公网 | 远程工具接口必须有强鉴权和网络边界 |
| 不传递用户 token 给下游工具 | token passthrough 会制造 confused deputy 风险 |
| 不让日志和工单成为指令 | 它们是 untrusted input |
| 不允许自主重启、回滚、扩容、切流量 | 生产动作需要明确责任人 |
| 不隐藏工具调用 | 没有审计就无法复盘 |
最后两条经常被低估。agent 可以给建议,但生产动作需要明确审批。agent 可以读日志,但日志里的文本不能改变工具调用策略。
分阶段落地
推荐的 rollout 路线如下。
| 阶段 | 能力 | 上线条件 |
|---|---|---|
| Phase 0 | 只读 runbook、postmortem、告警说明 | 不接生产数据 |
| Phase 1 | 只读 incident context 和 dashboard 链接 | 记录所有回答来源 |
| Phase 2 | observability 和 log-query MCP | 日志脱敏、工具 allowlist、审计 |
| Phase 3 | diagnostic MCP | 只暴露主机健康摘要,不暴露 shell |
| Phase 4 | break-glass SSH wrapper | 人工审批、短期凭证、输出限制 |
| Phase 5 | 审批式 remediation workflow | 演练、回滚路径、单动作审批 |
每个阶段都要有退出条件。Phase 2 之前,日志脱敏、字段 allowlist、查询窗口限制和输出上限必须通过测试。Phase 3 之前,诊断工具要覆盖常见 incident 和疑难 bug 的取证需求。Phase 4 之前,SSH wrapper 必须能拒绝未知命令、限制输出、记录 incident ID。Phase 5 之前,历史 incident replay 和演练要证明 workflow 不会扩大故障。
生产可靠性系统不该靠一次上线赌正确。
结论
生产排障 agent 的价值,不在于它能不能 SSH。价值在于它能否把证据收集、上下文压缩、假设生成和复盘产物做得更一致。
只读 SSH 可以作为实验入口,但不是好的默认架构。它的接口太宽,数据边界太模糊,审计语义太弱。MCP 也不是天然安全,不过它更适合承载语义化工具、审批、脱敏、限流和审计。
默认设计可以很朴素:
SLO、生产日志、trace 和观测系统作为事实入口。
MCP 作为日常诊断边界。
SSH 只做 break-glass。
生产动作必须审批。
所有工具调用必须可审计。
这不激进,但更像能在生产系统里长期运行的方案。
参考资料
- Google SRE, The Evolution of Automation at Google
- Google SRE, Monitoring Distributed Systems
- Google SRE, Service Level Objectives
- Google Cloud, Gemini Cloud Assist
- Google SAIF, Focus on agents
- OpenAI Codex, Permissions
- OpenAI Codex, MCP
- MCP, Security best practices
- Kubernetes, RBAC authorization
- OpenSSH, sshd manual
- Alibaba, SREWorks
- MicroHECL, High Efficient Root Cause Localization in Large-scale Microservice Systems
- CloudRCA, A Root Cause Analysis Framework for Cloud Computing Platforms