跳转到: 导航, 搜索

Swift/ideas/keymaster v2

< Swift‎ | ideas

Keymaster v2

原始 keymaster 使用存储在代理服务器配置文件中的单个根加密密钥,基于帐户/容器/对象的路径生成帐户、容器和对象的密钥。

将添加到 keymaster 的功能摘要

此设计旨在向 keymaster 添加以下功能

支持多个根加密密钥

支持多个根加密密钥包括

  • 能够切换到新的根加密密钥以加密新对象
  • 不实现现有数据的重新加密/重新包装,但是
  • 以允许以后重新加密的方式设计和实现更改


支持存储在外部密钥管理服务器中的根加密密钥

更新:这已在 https://review.openstack.org/#/c/364878 中实现。测试所需的步骤位于 https://etherpad.openstack.org/p/swift-kms-keymaster-setup

  • 实际上,使用 Castellan 库访问的 Barbican 服务器
  • 实现和测试结构化,以便不想使用 Barbican 的人无需安装依赖项(例如 oslo)


支持多个密钥服务器实例

  • 本地存储根密钥的多个位置
  • 多个外部 Barbican 服务器


系统模型

System model

对 swift 存储系统的假设如下

  • 当前 Swift 管理员受信任
  • 加密密钥存储受信任且可安全擦除,例如由 HSM 支持的密钥管理服务器,或插入代理服务器的可移动存储
  • 服务器(代理、帐户、容器、对象)受信任,包括服务器中的进程、内存
  • 所有存储都不受信任


攻击场景

考虑并保护了以下攻击场景

获取来自代理、帐户、容器、对象服务器的退役磁盘的访问权限

  • 加密密钥存储在元数据中,数据不可访问
  • 暴力破解加密密钥需要很长时间
  • 密钥轮换可以减少密钥被暴力破解时的暴露


攻击者是具有密钥服务器凭据的前 Swift 管理员,试图通过连接到密钥管理服务器来访问密钥

  • 人员变动时轮换凭据可以限制对密钥的访问


以下威胁不受保护

  • 恶意 Swift 管理员
  • 攻击者获得对 Swift 服务器的管理员访问权限,以及对存储的访问权限

动机

当前无法轮换密钥是一个限制

  • PCI DSS 要求规定,每次了解密钥的人员离职或职位变动时,都应轮换密钥
  • NIST SP 800-57 规定,对称密钥加密密钥的加密周期最长可达两年,或根据加密密钥的数量,短至一天或一周
  • 还要轮换访问密钥的凭据


为了安全、密码删除,应轮换存储在可安全擦除介质上的密钥

  • 可移动本地介质
  • 外部密钥管理服务器 (Barbican)


可以推迟旧密钥的重新包装,因为重新包装在技术上具有挑战性

  • 只要我们只使用密钥来加密/包装有限的时间,我们仍然可以在密钥需要重新包装之前解密一段时间


将根密钥存储在代理服务器上的本地存储中不是一个好主意

  • 指向与 proxy-server.conf 不同的配置文件允许将根密钥存储在外部介质上
  • 将密钥材料与其余配置信息分离可能是有意义的,但这会导致另一个间接


客户端管理的 / 自带密钥

  • 不同本地介质上的密钥,不同的外部密钥管理服务器
  • 普通用户使用本地介质,高级用户使用 HSM 支持的 Barbican
  • 每个帐户的客户端管理的 Barbican 服务器

新功能详情

支持多个根加密密钥

为了支持多个根加密密钥,需要以下内容

  • 多个根加密密钥,例如,在外部密钥管理服务器中;在本地配置文件中,或者;两者的组合
  • 指向当前根加密密钥的指针,用于加密新数据
  • 指向默认根加密密钥的指针,用于解密不指示应使用哪个密钥的数据;这对于与当前实现的兼容性是必需的


keymaster.conf 中 keymaster 的配置方式将进行以下更改

[keymaster]
current_root_secret=key3
default_root_secret=key1

root_secrets=key1,key2,key3

[key1]
key_material=d2qkoer+g4S+s2tbt1ZKJl9EfMUyMfT9BNdIXU2HI2s=

[key2]
key_material=3uVi489y9sL2GHHzqNgzJk2f0BnIFIC0SQFuvkdElBY=

[key3]
key_material=IIQf3dasef1tiqqXUIOYBP/1HKqPiP6V67JKyr8JYqo=

元数据将如下所示

X-Object-Sysmeta-Crypto-Body-Meta:
    {"iv": body_iv,
     "cipher": "AES_CTR_256",
     "body_key": {"key": wrapped_body_key,
                  "iv": body_key_iv},
     "root_secret_id": root_secret_id"}


Where

  • root_secret_id 是 keymaster.conf 中配置的密钥的 ID,例如“key3”

支持存储在外部密钥管理系统上的根加密密钥

外部密钥管理系统的配置需要以下参数

  • 用户名、密码、其他凭据
  • Barbican 服务器主机、端口
  • Keystone 服务器主机、端口
  • 等等

上述内容可以在 keymaster.conf 中如下配置

[keymaster]
external_key_server=barbicanserver1
current_root_secret=barbican_key3
default_root_secret=barbican_key1

root_secrets=barbican_key1,barbican_key2,barbican_key3

[barbicanserver1]
server_type = barbican
barbican_username = swift
barbican_password = swift
barbican_project_name = service
barbican_auth_url = http://192.168.50.11:5000/v3

元数据中的引用如下所示

X-Object-Sysmeta-Crypto-Body-Meta:
    {"iv": body_iv,
     "cipher": "AES_CTR_256",
     "body_key": {"key": wrapped_body_key,
                  "iv": body_key_iv},
     "root_secret_id": root_secret_id}


Where

  • root_secret_id 是 keymaster.conf 中配置的密钥的 ID,例如“key3”

元数据更改与之前相同,但 keymaster 需要知道 root_secret_id 在 Barbican 中,而不是在本地存储中

支持多个密钥服务器实例

需要

  • 服务器和密钥配置的分离
  • 配置和元数据需要指向 <server,key> 元组


keymaster.conf 中密钥引用的更改

[keymaster]
key_servers=barbicanserver1,localfile1
current_root_secret=barbicanserver1:key3
default_root_secret=localfile1:key1

[localfile1]
server_type = localfile
key_file = /mnt/usb1/swift_keys1.conf

[barbicanserver1]
server_type = barbican
barbican_username = swift
barbican_password = swift
barbican_project_name = service
barbican_auth_url = http://192.168.50.11:5000/v3

本地密钥将如下所示在例如 /mnt/usb1/swift_keys.conf 中指定

[key1]
key_material=d2qkoer+g4S+s2tbt1ZKJl9EfMUyMfT9BNdIXU2HI2s=

[key2]
key_material=3uVi489y9sL2GHHzqNgzJk2f0BnIFIC0SQFuvkdElBY=

元数据更改如下所示

X-Object-Sysmeta-Crypto-Body-Meta:
    {"iv": body_iv,
     "cipher": "AES_CTR_256",
     "body_key": {"key": wrapped_body_key,
                  "iv": body_key_iv},
     "root_secret_id": server_id:root_secret_id}


Where

  • root_secret_id 是 keymaster.conf 中配置的密钥的 ID,例如“key3”
  • server_id 是 keymaster.conf 中定义的服务器之一,例如“barbicanserver1”

未来工作

轮换现有密钥

X-Object-Sysmeta-Crypto-Body-Meta:
    {"iv": body_iv,
     "cipher": "AES_CTR_256",
     "body_key": {"key": wrapped_body_key,
                  "iv": body_key_iv},
     "root_secret_id": server_id:root_secret_id}
  • 指向新的 server_id:root_secret_id
  • 使用新的根密钥替换 wrapped_body_key 与现有的 body_key


挑战包括最终一致性,当旧密钥可以删除时

巴塞罗那峰会反馈

  • 将根加密密钥存储在可移动介质上(并在代理服务器启动后将其移除)不建议这样做,因为代理服务器可能随时重新启动/被重新启动。
  • 研究使用 Hashicorp Vault 来与外部密钥管理系统(例如 AWS)通信以及审计密钥访问
  • 对将其他信息(例如密钥唯一标识符和服务器标识符)存储在对象元数据中表示担忧。另一种方法是按周期存储密钥,并在 keymaster 中维护周期到密钥的映射,以便可以执行查找以根据对象的创建时间找到要使用的密钥。
  • 通过在容器中存储包装的随机、不可变密钥,并使用该密钥来派生对象密钥,可以避免在对象元数据中存储密钥 ID。或者,不可变密钥可以是帐户级别,容器和对象密钥从该密钥派生,类似于 a/c/o 密钥现在从根密钥派生。使用这些方法,密钥轮换的好处将大于仅轮换根密钥,但仅在帐户或帐户和容器级别轮换密钥将比重新包装对象密钥(仅对象密钥加密密钥,绝不加密实际对象数据使用的 body 密钥)更易于管理。
  • 对在现有 keymaster 中的函数中有条件地导入 castellan/barbican 模块表示担忧;另一种方法是拥有一个单独的、新的 keymaster。
  • 如果采用类似于 Amazon 使用的自带密钥 (BYOK) 方法,如果客户端未提供密钥,但 Swift 代理服务器已启用加密,会发生什么?在这种情况下,我们应该使用集群密钥进行加密,或者我们应该始终使用集群密钥进行加密,如果提供了 BYOK,则将有两层加密。
  • 如果不存在帐户或容器密钥,并且两个客户端同时在不同的代理服务器上创建帐户/容器密钥,我们需要能够存储这两个密钥,因为我们最终可能会用一个密钥(或从一个密钥派生的密钥)加密一个对象,并用另一个密钥加密另一个对象。
  • 不要添加仅添加新的、轮换的密钥的支持,同时不添加支持清理和删除不再使用的密钥的支持。


联系方式:mathiasb 在 IRC 上。