在可能被入侵的 DMZ 环境中采用“不信任 Agent”前提的设计
1. 引言——DMZ 存在安全监控的“盲点” #
对于云服务商和主机托管商而言,位于 DMZ(非军事区)中的公共 Web 服务器和反向代理是最常成为攻击目标的位置。
即便是这样的位置,通过 syslog 转发汇总日志的配置也并不少见。然而这里存在一个重要前提:
BASTION 的 DMZ Agent 在设计上前提是“Agent 本身也可能已被入侵”。本文将说明支撑这一前提的“Agent 不信任模型”及验证引擎的设计。
2. 为何现有的 EDR 和 SIEM Agent 并不足够 #
EDR(端点检测与响应)和 SIEM 产品的 Agent 功能可以检测端点异常。但这类产品大多基于以下前提:
- Agent 是可信的(= 由服务器端签发的已签名二进制文件)
- Agent 发送的事件是正确的(= Agent 内部已预先完成验证)
- Agent 保持静默即代表服务器安全(= 异常时 Agent 应主动通知)
这些前提在平时是成立的,但在DMZ 服务器被入侵的情况下会彻底失效:
- 即便是已签名的二进制文件,只要获取了 root 权限,Agent 进程本身也可能被篡改
- 如果攻击者理解了 Agent 内部的事件验证逻辑,就能够生成能够通过验证的“伪造事件”
- 通过终止 Agent 并启动伪造的 Agent,可以伪装出“正常的静默”
BASTION 的设计目标就是堵住所有这些漏洞。
3. Agent 不信任模型——三项职责分离 #
BASTION 的 Agent 与中央服务器(AI-SLOG)之间的关系被明确划分为三项职责。
| 职责 | 负责方 | 理由 |
|---|---|---|
| 日志采集与初次事件生成 | Agent(DMZ 侧) | 低延迟和实时响应能力很重要 |
| 事件验证与判定 | AI-SLOG(内部侧) | 必须在无法被入侵的位置执行 |
| 防御动作(阻断) | Agent(DMZ 侧) | 只能在相应服务器上执行阻断 |
关键点在于“检测”与“验证”在物理层面上是分离的。”即便 Agent 通知“检测到攻击”,AI-SLOG 也不会照单全收。它始终会通过从同一服务器经由另一条通路直接拉取的原始日志进行独立验证。
DMZ Server AI-SLOG (Internal)
┌──────────────┐ ┌──────────────┐
│ Agent │── WebSocket ──→│ Receive │
│ ・Log Monitor│ (Events) │ │
│ ・Primary │ │ ↓ │
│ Detection │ │ Validation │←─ Raw logs
│ │ │ Engine │ (via rsyslog)
│ ・Block │←── WebSocket ──│ ↓ │
│ Execution │ (block cmd) │ Send Command │
│ Only │ │ │
└──────────────┘ └──────────────┘
↑ ↑
Agent cannot do more Cross-reference with
than blocking even if lying raw logs; discard event
if mismatch4. 验证引擎——将 Agent 事件与原始日志进行交叉核对 #
验证引擎是一种独立验证从 Agent 送达的事件是否为“事实”的机制。
来自 Agent 的事件示例(攻击检测通知):
{
"agent_id": "dmz-web-01",
"event_type": "vuln_scan_detected",
"src_ip": "203.0.113.42",
"target": "/.env",
"timestamp": "2026-05-13T10:23:45+09:00",
"evidence_lines": [
"203.0.113.42 GET /.env HTTP/1.1 404",
"203.0.113.42 GET /.git/config HTTP/1.1 404",
"203.0.113.42 GET /wp-admin HTTP/1.1 404"
]
}收到该事件后,AI-SLOG 会通过以下步骤进行验证:
- 获取原始日志:相应 DMZ 服务器的 Apache/Nginx 日志已通过 rsyslog 另行单独获取
- 在相应时间戳前后搜索:在事件时间戳的前后 ±30 秒范围内搜索来自同一 IP 的请求
- 与 evidence_lines 交叉核对:验证 Agent 所声称的三行内容是否确实存在于真实日志中
- 不匹配即丢弃:只要有一行不匹配,该事件就会被判定为“可能是伪造的”并被丢弃,同时发出警告
如果 Agent 诚实运作,evidence_lines 就会与实际日志一致,顺利通过验证。即使 Agent 被攻击者入侵并发送伪造事件,通过与原始日志的交叉核对也能轻松将其过滤掉。
重要的一点在于,原始日志的获取通路与 Agent 事件通路是完全分离的。通过 rsyslog 进行的日志转发运行在与 Agent 进程不同的独立通路上,即便攻击者控制了 Agent,也无法篡改内部侧的 rsyslog 接收。
5. Agent 权限设计——将能力最小化 #
授予 Agent 本身的权限也被压缩到了绝对最小限度。
| 操作 | 权限 | 备注 |
|---|---|---|
| IP 阻断(ufw deny 等) | 允许 | 服务器防御所必需 |
| 解除 IP 阻断(ufw delete 等) | 禁止 | 防止攻击者自行解除阻断 |
| 编辑配置文件 | 禁止 | 防止 config.yaml 被篡改攻击 |
| 执行外部 shell 命令 | 禁止 | 基于 config.yaml 中 allowed_commands 白名单 |
| 访问其他服务器 | 禁止 | 防止横向移动 |
尤其重要的是“Agent 无法自行解除阻断”这一设计。即便攻击者控制了 Agent,也无法解除对自身 IP 的阻断以再次进入。
那么对于被误判而遭阻断的正常用户,又该如何解除阻断呢?这通过两条途径来解决:“24 小时后自动过期”(后文详述)以及 AI-SLOG 侧的手动解除阻断指令。
6. 心跳冻结——不活动时的安全装置 #
前文提到过,不能信任“Agent 保持静默就代表安全”这一前提。那么 BASTION 实际上是如何处理 Agent 停止运行这一情形的呢?
每个 Agent 会定期向 AI-SLOG 发送心跳。当心跳中断达到一定时间后,BASTION 会执行以下操作:
- 对来自该 Agent 的所有新事件进行冻结(不做处理直接丢弃)
- 通过 Slack 通知运维人员
- 在 Agent 重启并恢复心跳之前,停止接受该 Agent 的事件
这是针对“Agent 在保持静默的同时暗中发送虚假信息”这类场景的对策。攻击者或许会设想只持续发送心跳、同时停止实际日志转发,但在这种情况下,独立的 rsyslog 通路可以检测到“日志突然中断”这一异常。
换言之,我们有意设置了多条通路来判断 Agent 的状态。
7. 24 小时自动过期——防止阻断永久化 #
由 Agent 执行的阻断(ufw deny 等)被设计为在 24 小时后自动过期。
# Agent-side cron.hourly
/opt/bastion-agent/bastion-ufw-prune.sh
# → Judge elapsed time from timestamp embedded in ufw comments
# → Delete entries exceeding 24 hours with ufw delete
# → Do not wait for unblock instruction from AI-SLOG (autonomous local operation)这一设计包含三个意图:
- 防止误判持续存在:即使因误判而被临时阻断,也会在 24 小时后自动恢复
- Agent 无需解除阻断的权限:由于会自动过期,因此没有必要向 Agent 授予解除阻断的权限
- 降低对 AI-SLOG 的依赖:过期处理在 Agent 本地即可完成,即便 AI-SLOG 宕机也不会有问题
如果同一攻击者在 24 小时后再次出现,也会自然而然地再次被检测并阻断。只要攻击者持续活动,阻断就会持续生效。
8. 实现决策——为何选择 WebSocket #
Agent 与 AI-SLOG 之间的通信采用 WebSocket 实现。以下分享一下具体的理由。
| 选项 | BASTION 的决策 |
|---|---|
| HTTP POST(Agent → AI-SLOG) | 未采用。需要另一条通路来回传指令 |
| MQTT | 未采用。增加 broker 会加大运维负担,在封闭网络中显得过度 |
| gRPC | 未采用。协议定义的运维负担较大,调试也较困难 |
| WebSocket(双向) | 采用。可在单一连接中实现双向通信,兼容 TLS 与 HTTP |
尤其重要的是,“Agent → AI-SLOG 的事件发送”和“AI-SLOG → Agent 的阻断指令”可以在单一连接中处理。这简化了跨防火墙的通信,也大幅减轻了运维负担。
此外,它还可以通过 HAProxy 等标准反向代理进行终结(与 HTTP 语义相同),因此 TLS 终结和身份验证的整合都能沿用现有资产。
9. 设计上的权衡与限制 #
坦白说,这一机制也存在限制。
1. 验证引擎的计算成本:由于每个 Agent 事件都要与原始日志进行交叉核对,处理时间会随事件量增加而上升。BASTION 通过将 evidence_lines 限制在 3~5 行、并按时间窗口缩小搜索范围来控制成本。
2. 原始日志获取通路的冗余性:验证引擎使用经由 rsyslog 的日志,但如果 rsyslog 本身停止,验证就无法进行。为此,我们另行实现了 rsyslog 的健康监控,一旦停止即立刻发出告警。
3. 验证逻辑的透明度:公开详细的验证逻辑会让攻击者能够设计出绕过验证的伪造事件。因此,具体的验证算法细节不予公开(本文仅说明其概念)。
4. 解除阻断的运维负担:由于 Agent 不具备解除阻断的权限,若要立即解除误判导致的阻断,就需要从 AI-SLOG 侧进行操作。这就变成了“忍耐 24 小时,或由运维人员手动介入”。
这些都是由“不信任已被入侵的 Agent”这一根本前提所衍生出的不可避免的权衡。该设计有意将天平向安全性一侧倾斜,而非便利性。
10. 实际运维中的效果——在我们自身环境中的验证 #
BASTION 的 DMZ Agent 目前正在三台公共 Web 服务器上投入生产运行。截至本文撰写时:
- Agent 事件被拒绝次数:0(因验证而被丢弃的事件 = 全部为合法事件)
- Agent 心跳异常次数:0(心跳中断次数为零)
- 误阻断事故:0(公司 IP/合作伙伴 IP 被阻断次数为零)
- 因 24 小时过期而导致的非预期解除:0(一切均按预期运作)
这是一种“Agent 诚实运作,因而验证顺利通过”的状态,而不信任模型只有在真正发生入侵时才会显现其真正价值。它在平时安静运行,在出事时保护运维人员。
11. 未来发展 #
Agent 与验证引擎目前已投入实际使用,但仍有改进空间。
- 迁移至 Go 语言:将目前的 Python Agent 实现迁移至 Go,实现单一二进制文件分发(更便于向客户环境部署)
- 签名验证:为 Agent 二进制文件增加签名验证,并在启动时增加自校验逻辑
- 审计日志区块链化:为验证引擎的判定历史实现防篡改记录(用于客户审计)
- 多重验证通路:不仅使用 rsyslog,还结合 SNMP 与网络流量信息进行多层验证
这些将会依次逐步实现。
12. 相关文章 #
- 多层关联攻击活动检测机制 —— 由 Agent 检测到的初次事件是如何被判定为整体攻击活动的
- 让 BASTION 从“安全产品”蜕变为“AI 运维平台” —— BASTION 整体的演进历程
- 敬请期待 利用本地 LLM 实现基础设施日志自动分析
- 敬请期待 LLM 幻觉审计的实现
13. 联系我们 #
对于正在考虑引入 BASTION 或有意参与联合验证项目的企业,欢迎通过联系表单与我们联系。
对于拥有 DMZ 或隔离环境的客户而言,本文所介绍的 Agent 不信任模型将成为重要的差异化竞争优势。我们将根据您的具体范围提供个别报价方案。