预签名 URL¶
https://blueprints.launchpad.net/zaqar/+spec/pre-signed-url
存在一种需求,即拥有预签名 URL - 类似于 Swift 的 tempURL - 授予非认证用户对特定队列的临时访问权限。
问题描述¶
在需要允许系统“外部人员” - 例如 guest-agents - 与 Zaqar 交互的情况下,提供一种授予他们访问权限的方式很有用,这样他们就可以在无需提供这些“外部人员”用户名和密码或任何其他系统权限的情况下完成所需的操作。
然而,这种访问需要是临时的、可撤销的且粒度细。外部人员不应一次访问超过一个资源,并且授予的权限应明确他们可以执行的操作类型。
提议的变更¶
针对上述问题的提议解决方案是使用预签名 URL。像 Swift 这样的服务使用类似的方法 - 在那里称为 temp URL - 来提供对内部资源的访问。预签名 URL 包含一个 URL,其中包含一个带有编码权限的 哈希 值。
为了使阅读/编写此规范更容易,让我们将其分为几个部分。第一部分将描述构成 URL 的部分。第二部分将描述 URL 的生成方式,第三部分将描述 URL 的使用方式。
预签名 URL¶
预签名 URL 应该包含足够的信息,以便对其共享的资源提供足够的控制,而不会损害安全性。授权是必须具备的,也是此 URL 的重要组成部分。因此,此 URL 中包含的信息在这一方面必须详尽。
如前文所述,URL 包含一个哈希化的信息片段,该片段序列化了所需的字段。这些字段是
项目:生成 URL 的实体 keystone 租户
TTL:URL 的过期时间(以秒为单位)
队列:此 URL 授予访问权限的 Zaqar 队列名称
HTTP 方法:创建此 URL 的 HTTP 方法。通过选择 HTTP 方法,可以授予对特定资源的读取或读/写访问权限。
上述字段将是生成的哈希的一部分,但它们也将作为 URL 中的公共信息提供。编码它们的原因是在向 Zaqar 发出请求时,有一种方法可以验证 URL 是否未被用户更改。
生成的哈希将是 HMAC-SHA1。要生成这样的签名,需要一个密钥。在 Swift 中,可以为每个帐户设置一个密钥。不幸的是,在 Zaqar + Keystone 中这是不可能的,因此此规范建议添加一个新的配置选项,其中包含要使用的密钥。
[signed_url]
secret_key = some-very-strong-key
URL 生成¶
此规范建议在队列命名空间中添加一个新的端点,该端点返回生成的签名和过期时间,这将授予对该资源的访问权限。此操作的请求和响应
请求:
POST /v2/queues/shared_queue/share HTTP/1.1
...
{
'methods': ['GET', 'POST']
}
响应:
HTTP/1.0 201 OK
...
{
'signature': '518b51ea133c4facadae42c328d6b77b',
'expires': 2015-05-31T19:00:17Z,
'project': '7d2f63fd4dcc47528e9b1d08f989cc00',
'url': '/v2/queues/shared_queue/messages',
'methods': ['GET', 'POST']
}
此请求设置 URL 的不同过期日期。请注意,默认方法是 GET。
请求:
POST /v2/queues/shared_queue/share HTTP/1.1
...
{
'expires': 2015-06-19T19:00:00Z
}
响应:
HTTP/1.0 201 OK
...
{
'signature': '518b51ea133c4facadae42c328d6b77b',
'expires': 2015-06-19T19:00:00Z,
'project': '7d2f63fd4dcc47528e9b1d08f989cc00',
'url': '/v2/queues/shared_queue/messages'
'methods': ['GET']
}
此请求同时结合了这两个参数(方法和 expires)
请求:
POST /v2/queues/shared_queue/share HTTP/1.1
...
{
'methods': ['GET', 'POST'],
'expires': 2015-06-19T19:00:00Z
}
响应:
HTTP/1.0 201 OK
...
{
'signature': '518b51ea133c4facadae42c328d6b77b',
'expires': 2015-06-19T19:00:00Z,
'project': '7d2f63fd4dcc47528e9b1d08f989cc00',
'url': '/v2/queues/shared_queue/messages'
'methods': ['GET', 'POST']
}
使用 URL¶
首先,重要的是要提到 任何 URL 头部都不能/不应该被修改和/或省略。一旦其中一个被修改,签名验证将失败,因此请求将响应 404。
预签名 URL 的请求将由一个中间件处理,该中间件应放置在 keystone 的中间件 之前。这将允许我们提前验证请求并跳过 keystone 的身份验证。使用先前部分中生成的签名的请求如下所示
请求:
GET /v2/queues/shared_queue/messages HTTP/1.1
Host: zaqar.example.com
User-Agent: python/2.7 killer-rabbit/1.2
Date: Wed, 28 Nov 2012 21:14:19 GMT
Accept: application/json
Accept-Encoding: gzip
URL-Signature: 518b51ea133c4facadae42c328d6b77b
URL-Expires: 2015-05-31T19:00:17Z
X-Project-Id: 7d2f63fd4dcc47528e9b1d08f989cc00
Client-ID: 30387f00-39a0-11e2-be4d-a8d15f34bae2
请注意,在上面的示例中,选择了头部而不是查询参数。做出此选择的两个主要原因是
1. 与其他安全相关参数(例如 X-Project-Id)保持一致,这些参数通过 HTTP 头部发送。
2. 这些新参数不属于 消息 请求,也不会影响 消息 导航。
类似地,可以执行如下请求。
请求:
GET /v2/queues/shared_queue/messages?marker=1355-237242-783&limit=10 HTTP/1.1
Host: zaqar.example.com
User-Agent: python/2.7 killer-rabbit/1.2
Date: Wed, 28 Nov 2012 21:14:19 GMT
Accept: application/json
Accept-Encoding: gzip
URL-Signature: 518b51ea133c4facadae42c328d6b77b
URL-Expires: 2015-05-31T19:00:17Z
X-Project-Id: 7d2f63fd4dcc47528e9b1d08f989cc00
Client-ID: 30387f00-39a0-11e2-be4d-a8d15f34bae2
过滤和分页不包含在签名中,而是属于授予的 读取 权限。
发布消息将以相同的方式进行
请求:
POST /v2/queues/shared_queue/messages HTTP/1.1
Host: zaqar.example.com
User-Agent: python/2.7 killer-rabbit/1.2
Date: Wed, 28 Nov 2012 21:14:19 GMT
Accept: application/json
Accept-Encoding: gzip
URL-Signature: 518b51ea133c4facadae42c328d6b77b
URL-Expires: 2015-05-31T19:00:17Z
X-Project-Id: 7d2f63fd4dcc47528e9b1d08f989cc00
Client-ID: 30387f00-39a0-11e2-be4d-a8d15f34bae2
...
其他说明¶
对于预签名 URL,队列不能被延迟创建。这是为了防止队列被删除而用户仍然拥有有效的 URL。在只有一个池的情况下,这并不是一个大问题。但是,如果部署使用多种类型的池,延迟创建的队列可能会最终进入一个不受欢迎的池,并且攻击者可能会尝试对该池进行 DoS 攻击。因此,每当创建预签名 URL 时,如果池不存在,将创建一个池。
我不喜欢在各个地方传递 project-id,但我无法想到另一种方法来做到这一点,同时仍然能够保留多租户能力,而无需传递项目。
我不喜欢将密钥设置在配置文件中。在未来的版本中,我们可以考虑将此信息作为队列本身的一部分。我们现在无法这样做,因为我们在元数据中没有私有字段。对该功能进行增强应该很容易做到。
作为未来的增强,我们还可以使用 Barbican 进行密钥管理。
缺点¶
这项工作可能会增加安全问题。我们应该在审查时格外小心,并创建一个漏洞团队,随时准备解决可能出现的问题。
备选方案¶
无
实现¶
负责人¶
- 主要负责人
flaper87
工作项¶
编写生成具有适当测试的签名的实用程序
添加生成预签名 URL 的端点
创建一个能够处理这些 URL 的中间件
依赖项¶
无
注意
本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode