Attestation Interface 和 Keylime 集成

https://storyboard.openstack.org/#!/story/2002713

为了帮助验证裸机节点是否处于可信状态,我们需要一个接口,以便在状态机进行过程中采取某些操作或验证步骤。

这些步骤可能包括调用外部认证服务器,或在清理过程中执行特殊步骤,以确保节点由认证服务器拥有。

从高层来看,我们需要一个钩子接口。而提供一种执行外部工具的机制是最佳途径。

问题描述

术语表

在尝试将两个不相关的服务结合在一起时,不可避免地会产生一些命名空间污染。因此,对于不熟悉 Keylime 术语,并为了避免与 Openstack 词汇混淆,我们将在本规范中定义所有必要的术语。

“可信平台模块 (TPM)” - 机器内部的一个微控制器,可以创建和安全地存储哈希值。所有希望使用 Keylime 进行认证的节点都需要具有 TPM 2.0。

“完整性测量架构 (IMA)” - Linux 中的一个安全子系统,它收集文件、文件元数据和进程元数据的哈希值,作为系统的一个“测量”。将测量结果存储在机器的 TPM 中。在 Ironic 和 Keylime 集成的上下文中,我们需要在我们要进行认证的节点上运行 IMA。

“允许列表 (allowlist)” - 代表节点黄金状态的哈希值。在 Keylime 的上下文中,允许列表与 IMA 测量结果进行比较,以查看节点是否以未经授权的方式被篡改。

“Keylime 验证器 (verifier)” - Keylime 套件的一个组件,负责将允许列表与从我们要进行认证的节点收集到的测量结果进行比较。验证器将在 Ironic 和 Ironic 控制的节点外部的机器上运行,并查找要进行认证的对象。

“Keylime 注册器 (registrar)” - Keylime 套件的一个组件,Ironic 需要与其通信才能启动节点的认证工作流。注册器也运行在 Ironic 和节点外部的机器上。验证器和注册器可以运行在同一台机器上,但这不是必需的,由操作员决定。

“Keylime 代理 (agent)” - Keylime 套件的一个组件,它运行在我们要进行认证的节点上。代理将命令 IMA 收集测量结果,并将测量结果发送到验证器。

“Keylime 租户 (tenant)” - Ironic 控制器需要用来与注册器和验证器通信的 API。不要与 Openstack 租户混淆。

简介

目前,我们依赖于使用裸机资源的用户的某种程度的信任。虽然我们在部署之间执行清理,但恶意攻击者可能会潜在地修改附加设备的固件,这些修改可能不易被检测到。

针对此问题提出的解决方案是使用经过测量的启动环境,并结合可信平台管理 (TPM) 模块,以帮助确保运行的系统配置文件完全如预期或由认证服务批准。

但从安全角度来看,安全性并不总是关于代码。有时安全性是遵守流程。为了利用 TPM 进行认证,我们建议使用 Keylime,一个开源的远程启动认证和运行时完整性测量系统。

第一步是添加一个新的接口类型 ‘attestation_interface’ 作为 ‘BaseDriver’ 的子类。然后,它将带有 ‘attestation_interface’ 实现,该实现将使用 Keylime 了解节点的安全状态并管理配置。所有对认证接口的调用都将发生在现有的清理和部署工作流中,并且如果节点被认为受到损害,则简单地失败转换。

第二步是对 ramdisk 进行一组增强,以支持 TPM 2.0,并安装 Keylime 代理。然后,Keylime 代理将与注册器和验证器通信。管理器将在节点工作流的某些点触发认证,例如在启动过程中。请注意,为了执行认证,验证器必须与节点位于同一网络中。

提议的变更

认证接口

nodes 表中添加一个 attestation_interface 字段,该字段映射到 task.node.driver.attestation 接口,以及驱动程序组合模型中存在的其他标准配置参数和默认行为。

相应地,attestation_interface 将在通过 REST API 检索时返回到节点对象上,并且可以设置为另一个接口。

attestation_interface 将提供一种配置和协调节点与验证器机器连接的手段。

Ironic 控制器将假定用于与认证服务通信的网络是安全的,并且认证实体始终是可信的。试图关注重放攻击或欺骗消息等问题超出了 IMA 认证工作流的范围。

为了适应操作员工作流,其中操作员可能无法访问认证服务,我们不能允许认证服务执行任何编排。这要求所有与认证服务的通信都涉及 Ironic 控制器轮询 API 以获取状态或指示认证服务或节点采取行动,而不是从认证服务或节点本身接收信息。例如,Keylime 提供了在节点受到损害时立即采取行动的撤销框架。但是,从 Ironic 的角度来看,允许另一个服务执行任何编排可能会使 Ironic 处于不知道节点上发生情况的状态。

目前,我们主要关注监控节点的部署和清理。预期的工作流是在这些步骤中使用该接口来确保节点的固件未被修改。

Keylime 接口

Keylime 接口将继承自 AttestationInterface 类。该接口的目的是允许控制器收集有关节点安全状态的相关信息,并根据结果采取行动。这样做需要调用 Keylime 验证器的通过可用的 REST API 的方法,以及调用 IPA 以传递必要的配置参数。预计 Keylime 将支持通用硬件类型。

Keylime 配置

Keylime 验证器和 Keylime 注册器是 Keylime 套件的两个组件,操作员必须启动它们。验证器和注册器需要通过 https 建立 TLS 连接才能进行通信。Keylime tenant CLI 安装在 ironic 控制器上。操作员负责保护注册器和验证器设置的网络。

详细的通信要求如下:

Keylime tenant -> Keylime verifier: 相互 TLS 连接

Keylime verifier/tenant -> node: 未加密连接

Keylime verifier/node/tenant -> registrar: 相互 TLS 连接用于 post/put 请求;未加密连接用于 get/delete 请求

每个 Keylime 代理都必须与其关联一个 uuid,以便将其注册到注册器。它使用 Keylime 配置文件生成其 uuid。uuid 默认设置为随机 ID。

允许列表和排除列表

允许列表和排除列表将预先生成并托管在远程服务器上或在 conductor 的文件系统中。将文件路径指向 conductor 的文件系统或指向远程服务器以找到这些文件的 URL 将在配置之前提供给 Ironic。允许列表也可以使用校验和进行签名,以确保它们未被篡改。这些校验和也将提供给 Ironic,并附带指向文件的路径或 URL。

可以将允许列表、校验和和排除列表的路径保存在 driver_info\keylime_allowlistdriver_info\keylime_allowlist_checksumdriver_info\keylime_excludelist 中。

Linux 的 IMA 子模块收集使用 TPM 引用签名的测量列表。Ironic 控制器将使用 Keylime tenant 将允许列表发送到验证器。Keylime 验证器获取测量列表,并通过将测量列表与允许列表进行比较来执行认证,以确定节点是否被篡改。

备选方案

我们可以将此功能添加到各种接口,但通常认证将是部署或部署一部分的特定模型,因此我们可能有一天需要针对特定的认证解决方案和工作流的“供应商”特定驱动程序。因此,不为此创建一个新接口似乎不太理想。

另一种选择是在状态转换期间执行某些检查。例如,在清理时,我们可以检查固件,并在发生修改时失败。但是,这在我们需要遵守严格的工作流和流程的情况下是不可取的。在所有者将节点借给不可信的承租人时,所有者可能希望确保承租人不会执行任何意外操作。这也不可扩展到其他工作流,例如定期监控。

数据模型影响

attestation_interface 字段添加到节点对象,这将需要数据库迁移来创建该字段。该字段将默认设置为 None,这将映射到无认证接口。

状态机影响

预计对状态机没有影响。对新接口方法的调用都将发生在由状态机驱动的现有工作流中。将在收到结果后立即对结果采取行动。

REST API 影响

将通过 API 微版本保护 attestation_interface 添加到节点对象。

客户端 (CLI) 影响

“ironic” CLI

“openstack baremetal” CLI

相应地更改 OSC 插件,以帮助用户更改新的 attestation_interface 字段。

RPC API 影响

此新的 attestation_interface 字段需要递增 RPC 版本。

驱动程序 API 影响

建议的认证接口方法将由定义在新的基类 AttestationInterface 上的“无认证”接口组成。

这些方法包括:

def validate_security_status(self, task):
    """Grabs the latest information about the node's security state
    from the attestation machine. Returns nothing on success, raises
    an exception if status is not what we expect or unable to reach
    verifier to obtain a status.
    """

def start_attestation(self, task):
    """Grabs the allowist, allowlist checksum, and excludelist from
    ``driver_info`` instructions. Verifies the integrity of the allowlist
    using the checksum. Attempts to send the allowlist and excludelist to
    the attestation service. Sending allowlist and excludelist allows the
    node to begin attesting itself. Returns nothing on success, raises an
    exception if checksum does not pass or is unable to reach the
    verifier to send allowlist/excludelist.
    """

def unregister_node(self, task):
    """Unregisters the node from the verifier machine. Returns
    nothing on success, raises an exception if status is not what
    we expect.
    """

这些方法可以在节点的清理和部署期间使用。对特定安全状态采取的行动将是可配置的。是否在认证失败时引发错误将是可配置的。

需要将一些额外的变量作为 driver_info 的一部分保存,以便管理节点。这些包括:

driver_info\keylime_allowlist 节点的允许列表。

driver_info\keylime_allowlist_checksum 允许列表的校验和,以确保允许列表未被篡改。

driver_info\keylime_excludelist 节点的排除列表。

driver_info\keylime_agent_uuid Keylime 代理的 uuid。需要用于查询验证器以获取安全状态,并将允许列表/排除列表对与节点关联到 Keylime 验证器。

工作流

考虑到所有这些,我们设计了以下使用 Keylime 实现认证接口的部署/清理工作流。

首先,操作员将启动一台具有 Keylime 验证器和注册器的机器。用户将为节点生成自己的允许列表、允许列表校验和和排除列表。管理员可以将这些文件放在与 Ironic 控制器相同的机器上,并将文件路径传递给 driver_info,或者非管理员可以将这些文件放在可以获取的位置,而是传递一个 URL 到 driver_info。必须在配置之前完成此步骤。操作员还将传递如何找到 Keylime 注册器和验证器到 driver_info.

在镜像构建过程中,节点镜像将设置为带有 Keylime 代理的实例,以及 TPM 和 IMA 配置,这些配置将允许 Keylime 代理运行。Keylime 代理将在启动后自动向 Keylime 注册器注册。此时,启动已经开始,节点可以将其第一个心跳发送回 Ironic 控制器。

接下来,将调用 start_attestation() 以将允许列表和排除列表发送到验证器。Conductor 将对代理进行 RPC 调用,以检索 Keylime 代理的 uuid、Keylime 代理的地址和 Keylime 代理正在侦听的端口。Ironic 控制器会将这些变量保存为 driver_info\keylime_agent_uuiddriver_info\keylime_agent_addressdriver_info\keylime_agent_port 以供进一步使用。如果 Conductor 未收到这些凭据,清理将失败。

允许列表和排除列表将通过以编程方式调用 keylime_tenant cli 发送到验证器。一旦验证器收到允许列表和排除列表,认证将开始。验证器将定期轮询 Keylime 代理以获取 IMA 测量结果,并将它们与允许列表和排除列表进行比较,以确定节点是否被篡改。验证器将记录节点的状态,但不对状态采取任何操作。

此时,conductor 可能会执行 validate_security_status() 调用来获取节点的状态。如果状态符合我们的预期,我们可以继续。如果状态与我们不符,或者由于网络问题,controller 无法访问 verifier,我们将使部署失败。

Keylime agent 需要通过调用 unregister_node() 来进行注销,以指示 Keylime verifier 结束其连接并从其数据库中删除该节点。

以下是预期工作流程的图表

diagram { Image; Node; Keylime-tenant; Keylime-verifier; Keylime-registrar; activation = none; span_height = 1; edge_length = 250; default_note_color = white; default_fontsize = 12; Image -> Node [label = “节点使用 diskimage-builder 工具生成的镜像启动。Keylime 和 TPM 环境在镜像中设置”]; Node -> Keylime-registrar [label = “向 Keylime-registrar 发送 POST 请求以注册节点上的 Keylime agent”]; Keylime-registrar -> Node [label = “使用加密的 AIK 响应节点”]; Node -> Keylime-registrar [label = “使用来自 TPM 的临时 registrar 密钥发送激活请求”]; Keylime-registrar -> Node[label = “200 OK”]; Node -> Keylime-tenant [label = “第一次心跳”]; Keylime-tenant -> Keylime-tenant [label = “用户将 allowlist 和 excludelist 提供给 Keylime tenant 命令”]; Keylime-tenant -> Keylime-verifier [label = “发送 allowlist 和 excludelist,并将 Keylime agent uuid 添加到 verifier”]; Keylime-tenant -> Node [label =”从节点获取 TPM quote,以使用 registrar 检查 Keylime agent 的有效性”]; Keylime-verifier -> Node [label =”开始轮询节点进行验证”]; Keylime-tenant -> Keylime-verifier [label = “获取节点当前状态”]; }

在框架内,允许节点租户引入他们自己的 Keylime 实例来证明节点在理论上是可行的。但是,Keylime 目前缺乏在 Ironic 中使其完全自动化的某些功能。

Nova 驱动程序影响

Ramdisk 影响

为了使 Keylime agent 与 TPM 2.0 协同工作,必须提供某些库和配置。这些增强功能将作为 ramdisk 的一部分提供。这包括 tpm2-tss 软件堆栈、tpm2-tools 实用程序,以及,虽然不是必需的,tpm2-abrmd 资源管理器。

Keylime-agent 将在 ramdisk 上设置。将创建一个新的 dib 元素来安装 keylime-agent 并使其作为系统服务运行。

需要一个新的 IPA 扩展来收集并将 keylime_agent_uuid、keylime_agent_address 和 keylime_agent_port 发送回 conductor。

安全影响

它对安全性有积极影响,因为我们可以通过证明服务验证节点是否可信。

其他最终用户影响

可扩展性影响

性能影响

其他部署者影响

默认情况下不会启用 attestation 接口,因为默认值将映射到 no-attestation 接口。

配置选项

关于在证明失败时是否应该使清理和部署失败的配置选项将是新的 [keylime] 部分的一部分

fail_clean_on_attestation_failure

布尔值,用于确定在证明失败时是否使清理失败

fail_deploy_on_attestation_failure

布尔值,用于确定在证明失败时是否使部署失败

开发人员影响

实现

负责人

主要负责人

Leo McGann <ljmcgann> lmcgann@redhat.com Danni Shi <sdanni> sdanni@redhat.com

其他贡献者

工作项

  • 添加 attestation_interface 数据库字段。

  • 实现基本接口添加

  • 实现 no-attestation 接口。

  • 添加节点 RPC 对象字段

  • 添加 API 支持和微版本。

  • 实现 Keylime 证明接口。

依赖项

测试

对该接口和基本功能进行测试,以及使用 ansible-keylime-tpm-emulator 进行 TPM 模拟的集成测试。

升级和向后兼容性

预计不会出现问题。

文档影响

将提供关于如何使用 keylime-verifier 和 keylime-registrar 的文档。

参考资料

https://github.com/keylime