跳转到: 导航, 搜索

Heat/Blueprints/InstanceUsers

实例用户蓝图

https://blueprints.launchpad.net/heat/+spec/instance-users

问题陈述

我们需要启用从 Heat 堆栈启动的实例内的 API 身份验证。一旦启动,实例不再由 Heat 直接控制,因此我们需要将它们视为隐式不受信任的——我们需要限制部署在实例内的任何凭证的权限,以尽可能减少允许使用我们的 API 进行身份验证的权限,理想情况下也通过策略 RBAC 来强化,以最大限度地减少这些凭证可以访问的 API 表面。

关键要求是我们应该能够验证连接到 API 的代理的身份,并将该身份映射到特定的 Heat 资源

  • 凭证的生命周期应该能够基于每个资源进行管理
  • 某些用例可能需要模拟堆栈所有者用户(例如,将指标发布到 Ceilometer?)
  • 许多其他用例不需要模拟(例如,用于等待条件通知的信号,我们可以将 Heat 内的身份映射起来)

我们目前的做法

目前,如果我们创建以下任何资源,我们都会在与创建堆栈的用户相同的租户中创建一个新的 Keystone 用户,并将该用户分配给“heat_stack_user”角色,该角色通过 policy.json 限制为特定的 API 操作。

  • AWS::AutoScaling::ScalingPolicy
  • AWS::CloudFormation::WaitConditionHandle
  • OS::Heat::HARestarter
  • AWS::IAM::User

这个问题是,创建包含以下任何资源的 Heat 堆栈的每个用户都需要成为 Keystone 管理员,否则他们无法创建用户。这对于 Heat 的“真实世界”部署来说是一个大问题,大多数用户预计不会拥有 Keystone 管理员权限。

此外,对 ec2tokens Keystone 功能的依赖性对于某些用户来说也是一个问题,因为他们的环境没有启用此 Keystone 扩展。

建议的解决方案

1. 使用与信任关联的凭证

  • 在专用的项目中创建一个专用的“heat_proxy_user”,该用户在任何项目中都没有分配任何角色
  • 当创建 Heat 堆栈时,我们在创建堆栈的用户和 heat_proxy_user 之间创建一个信任关系,启用模拟并仅委派“heat_stack_user”角色,该角色可用于通过 policy.json 限制访问。堆栈所有者用户不受限制,因为我们可以使用类似于“如果 heat_stack_user 且非 Member”的规则
  • 每个需要凭证的资源都会使用信任范围内的令牌创建一个 ec2 密钥对,这意味着生成的凭证与 trust_id 关联,因此它们可用于模拟堆栈所有者用户,并具有角色限制


优点:解决了管理员要求,可能适用于 v2 Keystone API(因此可以回溯移植到 Havana)

缺点:没有解决对 ec2tokens 的依赖性,可能比较复杂,共享代理用户存在安全隐患(尽管有模拟,因为……bug 总是会发生)

2. 使用域隔离和用户名/密码

此建议由 ayoung 提出(最初是在使用信任的上下文中,但我不太确定我们是否在所有情况下都需要进行模拟)

  • 创建一个专用于 Heat 的 Keystone 域
  • 对于每个 Heat 堆栈,我们在 Heat 域中创建一个新的项目
  • 对于每个需要凭证的资源,我们在 Heat 域的堆栈项目中创建一个 Keystone 用户
  • 用户拥有一个随机创建的密码,我们可以将其部署在实例中
  • 可以向用户分配 heat_stack_user 角色以限制可访问的 API 表面
  • 可选地,我们可以创建堆栈所有者用户和 Heat“资源用户”之间的信任关系,在需要模拟的情况下(仍然不确定我们是否真的需要它)


优点:解决了管理员要求(Keystone 用户创建由 Heat 服务管理员用户执行),相对简单,密码身份验证解决了对 ec2tokens 身份验证的依赖性。

缺点:需要 v3 Keystone API(可能无法回溯移植到 Heat stable/havana)

其他信息/想法

  • 可以向 OS::Nova::Server 添加一个“deploy_credentials”属性,以便通过 nova 元数据键/值对将用户名/密码提供给实例
  • 我们可以使用 python-heaclient 作为与 Heat 通信的代理,例如 heat stack-signal mystack --data "complete!"
  • 仍然可以从 heat-domain-resource-user 派生 ec2 密钥对,以支持与当前 heat-cfntools/boto 的兼容性
  • heat-cfntools 可能会被移植到使用 ReST API 和 python-heaclient 的 python 绑定而不是 boto

3. 使用 OAuth 访问/密钥和签名请求

OAuth 已被提及作为解决此问题的一种可能方案,但目前看来 Keystone 实现中缺少太多内容,无法将其视为可行的方案,特别是客户端支持、请求签名/验证和身份验证中间件尚未存在。

4. x509 证书

TODO:ayoung 提到这是一种可能的解决方案,需要更多信息

5. 资源范围内的虚拟密钥对

  • 在资源数据中创建并存储随机字符串,用作虚拟密钥对。(keystone 使用 uuid.uuid4().hex 创建这些)
  • 像我们现在对真实的 ec2 密钥对一样,将此虚拟密钥对用于任何 URL 或请求签名
  • 创建一个 Heat 引擎服务 RPC 调用,该调用使用 keystoneclient Ec2Signer 使用虚拟密钥对检查请求签名,并使用配置的堆栈凭证(信任或存储的凭证)返回一个令牌
  • 编写新的中间件或修改 EC2Token 以尝试通过 Heat RPC 调用获取令牌,并回退到 ec2token API


优点

  • 无需创建 Keystone 用户,因此 Heat 用户无需成为管理员
  • 不需要任何最新的 Keystone 功能(信任、域等),因此 Icehouse Heat 应该可以在许多 OpenStack 云上工作
  • 无需更改任何现有的模板或代理配置
  • Openstack-infra 可能会开始在 HPCloud 和 Rackspace 上使用 Heat 进行基础设施工作负载(这对于他们来说一直是一个巨大的障碍)
  • 这种方法可以实现(或至少尝试)代码更改相对较少


缺点

  • 潜在的风险是,密钥对被破坏后可能会执行经过身份验证的操作(可能风险与当前解决方案相同,只是这需要新的代码路径在 Keystone 之外。也可能通过 policy.json 缓解)


(shardy):问题 - *谁*的令牌在验证签名后由引擎返回?由于虚拟密钥对不与任何 Keystone 用户关联,因此我不清楚令牌将绑定到哪个用户。此外,由于密钥对与具有 Keystone 角色分配的真实用户不关联,因此我目前不了解如何通过 policy.json 控制访问?

其他信息/想法

  • ec2token 中间件可以始终调用 Heat 引擎 RPC 以获取令牌,并且 RPC 方法的第一个实现可以只是委托给 ec2token API
  • 可以编写一些策略来限制操作到密钥对所属的资源
  • 这可以与上述其他选项(例如 2.)一起开发