2021年,某高校的物流机器人实验室因未启用任何通信加密,被外部设备嗅探到话题数据,导致错误任务指令被注入——三台机器人原地失控。这类事故在真实项目中并不罕见。ROS2自带的SROS2安全框架就是为了堵住这类漏洞而设计的,但多数团队用ROS2做原型验证时,往往把安全配置这一步跳过了。
| 安全层面 | SROS2组件 | 类比 | 用途 |
|---|---|---|---|
| 身份认证 | 证书 + CA | 员工工牌 + 发证机构 | 确认节点身份是否可信 |
| 访问控制 | 权限文件(permissions.xml) | 门禁系统的楼层权限表 | 规定节点能读写哪些话题/服务 |
| 传输加密 | 治理文件(governance.xml) | 保密会议室的门锁 | 防止通信内容被窃听或篡改 |
SROS2 基于 DDS Security 1.1 标准实现,三层安全机制层层递进:没有证书的节点无法加入系统,即使加入了也找不到无权访问的话题,即使找到了也读不懂加密后的数据。我在部署第一个安全机器人项目时,就因为漏掉了 governance.xml 中的加密规则,导致话题数据以明文传输——系统日志里能看到完整的传感器数值,相当于白配了证书。
SROS2 采用 PKI(公钥基础设施)体系:一台离线机器充当 CA(证书颁发机构),为每个节点签发独立证书。节点启动时,DDS 层会验证对方证书是否由同一 CA 签发——就像机场安检核对护照章是否由海关盖的。
生成证书链时,先创建 CA 根证书,再为每个节点生成证书签名请求(CSR),由 CA 签署后分发。我踩过的一个坑:节点证书的 Common Name(CN) 字段没有按照 节点名@域名 的格式填写,导致权限文件的规则匹配不上,节点一直报 Authentication failed。
权限文件 permissions.xml 的核心是一组 ACE(访问控制条目),每个条目定义了一个节点对某话题或服务的操作权限。格式类似这样:
allow
subject: "节点A"
action: "publish"
topic: "/camera/image"
ACE 的语法来自 DDS Security 规范,支持 allow / deny、publish / subscribe / call / service 等动作类型。一个常见的初学者错误是把话题名写成了 /camera/image/(末尾多了斜杠),导致策略失效——ROS2 的话题名不允许尾部斜杠。
/parameter_events、/rosout 等系统内部话题——节点启动后直接报权限不足。治理文件 governance.xml 定义哪些话题需要加密、哪些节点之间需要身份认证。它是一份"通信安全等级"地图。实际项目中,大部分团队会对所有话题开启加密,但会为诊断日志等低敏数据关闭认证以降低延迟。
ros2 security --enclave 在开发阶段生成一份基线权限文件,然后基于这份文件做裁剪——而不是从空文件开始写ACE规则。基线文件会列出系统已知的所有话题和服务,能有效避免漏配。另外,keystore 目录务必放在版本控制之外,尤其是私钥文件(.key),泄露等于整个安全体系失效。
从节点启动到安全通信建立,内部经历了四个步骤,用流程图可以看得更清楚:
如果认证或权限校验未通过,DDS 底层会直接丢弃报文,节点收不到任何错误提示——只有通过 ros2 security debug 或在 DDS 日志中才能看到具体拒绝原因。这是新手排查时最容易被迷惑的地方:节点看起来正常启动,但就是收不到数据。
针对失败场景2,我提供一个排错线索:在权限文件中加入一条 allow * * *(通配所有话题和动作)来测试——如果节点通信恢复正常,就说明是权限规则写漏了。生产环境不要保留这条通配规则,仅用于调试。
在单机上部署一个带安全管控的 ROS2 系统:
ros2 security create_keystore 创建 keystore 目录/chatter,listener 订阅 /chatter/chatter 话题开启加密ros2 topic echo 验证能否读取数据(此时因权限不足应读取失败)ros2 topic echo 对应的节点名加上订阅权限,再次验证