13. ROS 2安全飞地

本文规定了安全飞地的集成。

作者:鲁芬·怀特(Ruffin White)、米凯尔·阿格达斯(Mikael Arguedas)

撰写日期:2020-05

最后修改:2020-07

本设计文档会对ROS 2与安全飞地的集成进行形式化描述。总之,所有安全进程都必须使用包含独有运行时安全工件的飞地,但每个进程不一定都有一个唯一的飞地。可以将多个飞地封装在单个安全策略中以对信息流控制进行精准建模。用户可以通过部署时控制飞地的应用范围来调整此类模型的保真度。例如,每个OS进程一个唯一的飞地,每个OS用户一个唯一的飞地,每个设备/机器人一个唯一的飞地,或者每个集群一个唯一的飞地,等等。本文档后续部分将详细说明如何按照惯例组织和使用飞地。

13.1 概念

在详细介绍SROS 2的飞地集成之前,先介绍以下几个概念。

13.1.1 参与者(Participant)

参与者是表示网络上单个实体的对象。在DDS环境中,Participant是一个DDS DomainParticipant,它同时具有访问控制权限和安全身份。

13.1.2 命名空间(Namespaces)

在ROS中,命名空间是一种基本的设计模式,被广泛用于组织和区分多种类型的资源以实现其唯一可标识性;即命名空间被用于话题、服务、动作和节点名称。因此,命名空间的概念为当前用户所熟知和理解,并且得到了现有工具的大力支持。命名空间通常可以在运行时通过命令行参数或通过启动文件声明以静态/编程方式进行配置。

以前,节点的全限定名称(FQN,Fully Qualified Name)直接由选定的安全目录查找策略所使用以加载必要的密钥材料。但是,既然现在参与者映射到运行环境(contexts)而不是节点,节点全限定名称FQN 到安全工件的这种直接映射不再合适。

13.1.3 运行环境(Contexts)

随着ROS 2的出现,现在可以将多个节点组合到一个进程中以提高性能。但是在以前,每个节点都会保留其与一个独立中间件Participant(参与者)的一对一映射。鉴于每个进程的多个Participant会产生不可忽略的开销,因此引入了一个变化以将单个Participant映射到运行环境,并允许多个节点共享该运行环境。

基于DDS Security规范v1.1,一个Participant只能使用单个安全身份;其结果就是,可应用于映射到某个给定运行环境的每个节点的访问控制权限必须被综合并组合到一组安全工件或飞地中。因此,每个进程中的所有运行环境及其各自的参与者都会使用该单个飞地。这样,需要额外的工具并对SROS 2进行扩展来支持这种新的范式。

13.2 密钥库(Keystore)

随着运行环境(Contexts)的添加,最好也借此机会重构密钥库布局。我们可以将所有此类安全目录下推到一个指定的enclaves子目录中,而不是带命名空间节点安全目录的一个扁平目录。同样地,也可以将私有和公共密钥库材料下推到根密钥库目录中它们各自的子目录中。这让人想起之前在Keymint[1]中使用的模式。

13.2.1 public目录

目录public中包含任何允许作为公共秘钥的内容,例如身份或权限证书颁发机构的公共证书。因此,可以向所有可执行文件授予对该目录的读取访问权限。请注意,在默认情况下,identity_ca和permissions_ca都指向同一个CA证书。

13.2.2 private目录

目录private中包含允许作为私有秘钥的任何内容,例如上述证书颁发机构的私有密钥材料。在将密钥库部署到目标设备/机器人之前,应该编辑这个private目录。

13.2.3 enclaves目录

目录enclaves中包含与各个飞地关联的安全工件,因此节点目录不再相关。然而,与节点目录类似,enclaves目录仍然可以递归地嵌套子路径以组织单独的飞地。按照惯例,ROS_SECURITY_KEYSTORE环境变量应该指向这个目录。

13.3 集成(Integration)

随着在ROS客户端库rcl中引入运行环境(contexts),不再依赖节点命名空间以从密钥库中查找安全工件,现在飞地路径与节点命名空间完全分离,反而飞地路径现在是用作其自身的唯一资源标识符。虽然不得不同时保留两个标识符空间可能会带来更多的自由度,但仍然应该可以组织密钥库中的飞地以模仿节点命名空间层次结构,以实现分配权限的透明可追溯性。

13.4 未来的工作

未来应该更新内省(introspective)工具和启动文件接口,以帮助降低向运行环境(contexts)和飞地(enclaves)迁移时引入的复杂性。

13.4.1 运行时(Runtime)

考虑到一个策略中的一个飞地可能会特定于单个节点/容器进程的规范示例,节点重映射到的命名空间会不可避免地影响该飞地内所需的安全权限。为了突出这种相互依赖性,并帮助避免飞地路径冲突,借用命名空间的层次结构是合适的。按照惯例,ros2launch可用于向使用作用域内命名空间的单个进程节点或容器添加飞地相对路径的前缀,以启用具有可调整和参数化飞地路径的可组合启动文件的约定。给定用于指定全限定飞地路径的运行时命令参数后,ros2launch会相应地解析由启动属性定义的可执行文件的飞地相对路径。

13.4.2 未限定的(Unqualified)飞地路径

对于具有未限定飞地路径的单个进程节点,会将其飞地目录默认设为根层次的飞地。

<launch>
  <node pkg="demo_nodes_cpp" exec="talker"/>
  <node pkg="demo_nodes_cpp" exec="listener"/>
</launch>

13.4.3 推送的未限定(Pushed unqualified)飞地路径

对于由某个命名空间推送的具有未限定飞地路径的单个进程节点,会将其飞地目录推送到相对子目录。

<launch>
  <node pkg="demo_nodes_cpp" exec="talker"/>
  <group>
    <push_ros_namespace namespace="foo"/>
    <node pkg="demo_nodes_cpp" exec="listener"/>
  </group>
</launch>

为了可读性而受抑制的符号链接

13.4.4推送的相对限定(Relatively pushed qualified)飞地路径

对于具有由某个命名空间推送的限定飞地路径的单个进程节点,其限定的飞地目录会被推送到相对子目录。

<launch>
  <group>
    <push_ros_namespace namespace="foo"/>
    <node pkg="demo_nodes_cpp" exec="listener" enclave="bar"/>
  </group>
</launch>

13.4.5 全限定(Fully qualified)飞地路径

对于具有绝对飞地路径的单个进程节点,命名空间不会推送相对子目录。

<launch>
  <group>
    <push_ros_namespace namespace="foo"/>
    <node pkg="demo_nodes_cpp" exec="listener" enclave="/bar"/>
  </group>
</launch>

13.5替代方案

<push_ros_namespace namespace=".​​.." enclave="foo"/>

一种此类方法可以通过向push_ros_namespace元素添加enclave属性来完成。这还会使飞地的推送与命名空间的推送保持更近/可读。

<push_ros_enclave enclave="foo"/>

另一种替代方法就是添加一个全新的push_ros_enclave元素。这可以确保飞地路径推送独立于/灵活于命名空间。

13.6 主要顾虑

13.6.1 每个运行环境有多个命名空间

对于用户可能会将不同命名空间的多个节点组合到单个运行环境中的情况,用户仍必须为此指定可应用于所有组合节点的公共飞地路径。对于飞地路径与节点命名空间正交的情况,对所有相关飞地路径使用全限定可能是冗长乏味的,但可能仍然可以通过使用<var/>和<arg/>替换和扩展来进行参数化。

13.6.2 对进程中的节点权限建模 v.s.对中间件Participant权限建模

在使用运行环境(contexts)之前,多个节点组合到一个进程中,其中每个节点映射到一个单独的Participant(参与者)。随后每个Participant会加载为其各自节点建立的安全身份和访问控制凭证。但是,该进程中的所有节点都共享同一个内存空间,因此可以访问来自其他节点的数据。这样,加载的中间件凭据/权限与进程中可访问的资源之间并不匹配。

通过使用飞地,某个运行环境中的所有节点会共享同一个安全身份和访问控制凭证。这不可避免地意味着编译到节点foo的代码可以访问仅受节点bar信任的凭据/权限。组合的这种结果可能会无意中颠覆策略设计者构建的或通过ROS 2工具/IDL测量/生成的最小跨度策略。

随着飞地的引入,通过将SROS 2策略配置文件集合定义为某个具体飞地中的元素来描述访问控制权限的并集就成为了可能。这就允许形式分析工具[2]检查在运行时给出节点组合的信息流控制中的潜在违规行为。如果一个进程加载单个飞地,这会对Participant的权限和该进程的权限进行协调。

但是,如果每个进程加载多个飞地,则由于共享同一个内存空间的原因,此类安全保证将再次丢失。因此,应该对甚至是否应该支持每个进程有多个飞地提出疑问。

总之,这里的区别在于,之前多个节点权限的组合无法传递给工具。节点能否获得同一个进程空间中其他节点的权限并不是要注意的关键点;要注意的关键事实是,这种副作用无法由设计师形式建模或解释。现在将可以使用飞地,但是允许每个进程有多个加载各独立飞地的运行环境会重新引入并加剧同样的建模不准确性。

13.6.3 可组合启动文件的包含(includes)功能

使用有安全飞地的启动文件的一个特殊挑战是保持包含层次结构的可组合性。在编写供下游使用的启动文件时,可能会产生在简单性和可配置性之间的继承(inherit)权衡问题。启动文件的作者可以选择性地选择将哪些属性公开为输入参数,而用户则可以隐式覆盖提供的默认值。

在飞地示例中,最佳实践到底应该是由软件包作者还是由用户来保留可组合和直观的启动文件结构,这一点并不清楚。例如:作者是否应该将每个节点的飞地路径参数化为输入参数?用户是否应该将包含的启动文件的命名空间推送到唯一的飞地?

不过可以肯定的是,不应该鼓励在启动文件中设置安全环境变量,因为这会限制使用启动文件的静态分析与Node IDL组合来生成程序性策略。

13.6.4 容器中的可组合节点

鉴于容器可以是动态的,在容器中节点可以在运行时添加或删除,可能存在一些关于容器应如何与安全飞地集成的问题。在ros2launch中,容器实例化作用域内的命名空间可用于解析容器指定的相对飞地路径,从而可用于解析该容器内的所有节点/组件。在最终扩展容器的启动API时,应该进一步考虑这一点。

13.6.5 迁移 RMW实现

由于所有RMW实现在实现运行环境(contexts)这个新系统之前可能需要一些时间,因此仍应指定一个定义好的回退行为。对于此类实现,应按照“ROS 2与DDS-Security的集成ROS 2 DDS-Security integration)”设计文档中的规定为参与者加载由RCL确定的飞地安全目录。这主要是停止使用包含在默认查找路径中的节点名称,从而使用户习惯于为单独的进程创建单独的飞地,或者通过启动文件明确指定唯一的飞地路径。

13.7 参考文献

1. Procedurally Provisioned Access Control for Robotic Systems

@inproceedings{White2018,
	title     = {Procedurally Provisioned Access Control for Robotic Systems},
	author    = {White, Ruffin and Caiazza, Gianluca and Christensen, Henrik and Cortesi, Agostino},
	year      = 2018,
	booktitle = {2018 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
	doi       = {10.1109/IROS.2018.8594462},
	issn      = {2153-0866},
	url       = {https://arxiv.org/pdf/1810.08125.pdf}}

2. Network Reconnaissance and Vulnerability Excavation of Secure DDS Systems

@inproceedings{White2019,
	title     = {Network Reconnaissance and Vulnerability Excavation of Secure DDS Systems},
	author    = {White, Ruffin and Caiazza, Gianluca and Jiang, Chenxu and Ou, Xinyue and Yang, Zhiyue and Cortesi, Agostino and Christensen, Henrik},
	year      = 2019,
	booktitle = {2019 IEEE European Symposium on Security and Privacy Workshops (EuroS PW)},
	doi       = {10.1109/EuroSPW.2019.00013},
	pages     = {57-66},
	url       = {https://arxiv.org/abs/1908.05310.pdf}}

*英语原文网址:design.ros2.org/article