多进程 Agent 通信安全:从 Socket 权限到 TLS 双向认证
Agent 进程间通信安全的核心问题不是“要不要加密”,而是通信双方是否可信、消息是否完整、权限是否最小。
如果 Agent 的调度进程、工具执行进程和状态存储进程之间走的是明文 TCP 或权限过宽的 Unix Socket,那么本机上的其他进程或同网段机器就可能冒充合法 Agent 发送伪造任务或窃取中间结果。
本文按“先识别风险、再收紧通道、最后验证”的顺序展开,适用于 Linux 环境下使用 Unix Socket 或本地 TCP 进行进程间通信的多进程 Agent 架构。
先分清通信通道和信任边界
Agent 进程间通信通常落在两类通道上:
- Unix Domain Socket:同一台机器上的进程通信,路径如
/run/agent/control.sock。默认权限由文件系统控制,如果 socket 文件权限是777,任何本地用户都能连接。 - 本地或内网 TCP:监听
127.0.0.1:9000或内网地址。如果没有认证,同主机其他进程或内网其他机器可以直接调用。
判断是否需要加固,先看三个条件:
- 通信通道是否允许非 Agent 进程连接;
- 消息是否携带可验证的发送方身份;
- 接收方是否校验消息完整性和来源权限。
只要有一条不满足,就属于需要处理的暴露面。
收紧 Unix Socket 的文件权限和目录权限
Unix Socket 的安全基础是文件系统权限。
假设 Agent 控制通道 socket 路径为 /run/agent/control.sock,运行用户为 agent,同组为 agent,只允许该用户和组访问:
sudo mkdir -p /run/agent
sudo chown agent:agent /run/agent
sudo chmod 750 /run/agent
sudo chmod 660 /run/agent/control.sock
关键点:
- 目录权限
750阻止其他用户进入目录,即使知道 socket 路径也无法连接; - socket 文件权限
660只允许属主和属组读写; - 不要把 socket 放在
/tmp下并给777权限,这是最常见的错误配置。
如果 Agent 进程以 systemd 管理,可以在 unit 文件中固定运行用户和组:
[Service]
User=agent
Group=agent
RuntimeDirectory=agent
RuntimeDirectoryMode=0750
RuntimeDirectory 会在服务启动时自动创建 /run/agent 并设置权限,避免手动创建目录后权限被重置。
TCP 通道启用 TLS 双向认证
当 Agent 进程间必须走 TCP(例如跨容器或跨主机),仅监听 127.0.0.1 不够,应启用 TLS 并校验客户端证书。
以下以 OpenSSL 生成自签名证书为例,仅用于内网测试环境;
生产环境应使用内部 CA 签发。
生成 CA 和双方证书:
openssl req -x509 -newkey rsa:4096 -days 365 -nodes \
-keyout ca.key -out ca.crt -subj "/CN=Agent-Internal-CA"
openssl req -newkey rsa:4096 -nodes \
-keyout server.key -out server.csr -subj "/CN=agent-server"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 365
openssl req -newkey rsa:4096 -nodes \
-keyout client.key -out client.csr -subj "/CN=agent-client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt -days 365
服务端配置示例(Python ssl 模块):
import ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile="server.crt", keyfile="server.key")
context.load_verify_locations(cafile="ca.crt")
context.verify_mode = ssl.CERT_REQUIRED
客户端连接时同样加载自己的证书和 CA:
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_cert_chain(certfile="client.crt", keyfile="client.key")
context.load_verify_locations(cafile="ca.crt")
context.check_hostname = False
context.verify_mode = ssl.CERT_REQUIRED
注意:自签名证书的 CN 必须与连接地址匹配,否则校验失败。
如果使用 IP 连接,应在证书中写入 SAN 扩展,而不是只写 CN。
消息层增加签名和重放保护
TLS 解决传输加密和通道认证,但不解决“消息被重放”或“应用层伪造”。
建议在消息体中增加两个字段:
timestamp:发送时间戳,接收方拒绝超过 60 秒的消息;signature:对payload + timestamp + nonce用 HMAC-SHA256 签名,密钥双方预共享。
接收方校验顺序:
- 检查时间戳偏差是否在允许窗口内;
- 用共享密钥重新计算 HMAC 并比对;
- 维护短期 nonce 缓存,拒绝重复 nonce。
这一步不需要引入复杂框架,几十行代码即可完成。
关键是签名密钥不能放在代码仓库里,应通过环境变量或密钥管理服务注入。
验证配置是否真正生效
改完权限和认证后,至少做三项检查:
- 用非授权用户尝试连接 Unix Socket,预期返回
Permission denied:
sudo -u nobody socat - UNIX-CONNECT:/run/agent/control.sock
- 用不带客户端证书的
openssl s_client连接 TLS 端口,预期握手失败:
openssl s_client -connect 127.0.0.1:9000 -CAfile ca.crt
- 发送一条时间戳过期的签名消息,确认接收方拒绝并记录日志。
如果三项都符合预期,说明通道层和应用层防护已生效。
常见误区
- 只监听 127.0.0.1 就认为安全:同主机上任何本地用户仍可连接,必须配合文件权限或 TLS 客户端认证。
- 把 socket 权限设为 777 图省事:等于把 Agent 控制通道开放给所有本地进程。
- TLS 只配服务端证书不校验客户端:只能防窃听,不能防冒充。
- 消息签名密钥硬编码在配置文件中:拿到配置文件即可伪造消息,密钥应独立管理。
Agent 进程间通信安全不需要一次性上齐所有措施,但至少要保证通道权限最小、发送方可验证、消息可校验。
按本文顺序先收紧 Socket 权限,再补 TLS 双向认证,最后加消息签名,每一步都可以独立验证,出问题时也容易回退。