MFA Auth Receipt

mfa-auth-receipt

为了在 OpenStack 中提供适当的可用的多因素身份验证 (MFA) 支持,我们需要向用户返回一个身份验证收据,代表部分身份验证,该收据可以作为挑战响应过程的一部分返回给 Keystone。

问题描述

截至 Ocata,Keystone 支持在给定用户上设置身份验证规则,并可能要求他们使用多种方法进行身份验证。这是 MFA 的良好实现,但问题在于用户或服务事先知道他们需要如何进行身份验证。大多数标准的 MFA 系统都是基于挑战响应的。您使用您的一个因素进行身份验证,然后获得该部分身份验证的收据,您可以将其连同缺失的部分一起返回。

Keystone 需要这种机制,因为如果没有它,我们无法在 OpenStack 中的任何地方以对用户有意义的方式实际使用 MFA。

最初在 Keystone 中提出的 MFA 实际上包含了这个概念,但从未实现:multi-factor-authn

讨论过半令牌的概念,但它从未真正以我们可以用于 MFA 的方式实现。

提议的变更

该提议是添加一种新机制,在部分成功的身份验证尝试时向用户返回收据。本质上,这将非常类似于一个令牌,并且理想情况下,将使用类似的系统进行存储(fernet、jwt),以保持内部逻辑的一致性和可重用性。

当用户使用他们的众多身份验证规则之一成功进行身份验证时,我们可以推断他们就是他们所说的那个人,然后向他们返回一个收据,其中包含有关缺失身份验证规则的信息。

如果用户尝试使用多种方法进行身份验证,并且大多数方法失败但至少有一种成功,我们不会返回收据,但我们会包含 json 错误数据,说明哪些方法失败了,哪些方法成功了。

理想情况下,应该能够使用收据获取带有额外身份验证方法的新的收据。如果您需要三种身份验证方法才能获得令牌,您应该能够添加您的收据,直到它可以成为令牌为止。

此收据将不允许任何 API 交互,但它将证明某些身份验证方法已经完成。收据的有效期默认为相当短的时间范围(5 分钟)。

收据响应

此响应的返回代码将是 401,因为用户仍然未授权,响应头包含收据 ID,主体包含有关收据的信息,用户需要这些信息才能继续身份验证过程。

此外,此响应将明确设置为仅在具有身份验证规则的用户使用其任何规则中的一种方法成功进行身份验证时发生。

收据 ID(加密的有效负载)将包含在 401 响应的标头中,就像令牌一样,但位于 OPENSTACK-AUTH-RECEIPT 标头下。

一个示例响应

{
    "receipt": {
        "methods": [
            "password"
        ],
        "user_id": "423f19a4ac1e4f48bbb4180756e6eb6c",
        "expires_at": "2015-11-06T15:32:17.893769Z"
    },
    "required_auth_methods": [
        ['password', 'totp'],
        ['password', 'option2'],
        ['password', 'option3', 'option4']
    ]
}

required_auth_methods 将是包含已成功身份验证方法的规则列表,而不是用户所有身份验证规则的列表。收据中的方法不必完全来自相同的身份验证规则,收据包含有效的方法以及它们可以应用的规则,因此这是一个交集测试。

另一个示例响应

{
    "receipt": {
        "methods": [
            "password", "option3"
        ],
        "user_id": "423f19a4ac1e4f48bbb4180756e6eb6c",
        "expires_at": "2015-11-06T15:32:17.893769Z"
    },
    "required_auth_methods": [
        ['password', 'option2'],
        ['option3', 'option4']
    ]
}

在上面的例子中,尽管两个身份验证规则之间没有重叠,但用户现在可以使用相同的收据获得两个可选的 MFA 路径。

收据有效负载

收据将不包含范围数据,因为它与收据无关。用户将在使用收据并尝试获取令牌时提供范围,Keystone 不会查看收据以获取范围。潜在地将范围引入收据的唯一原因是在我们引入基于范围的身份验证规则时。

与令牌一样,收据的实际提供程序应该是可配置的,并且类似类型(fernet、jwt)。在 fernet 的情况下,密钥存储库理想情况下应该能够与令牌提供程序共享,但应该能够配置以拆分存储库。这最大限度地减少了对部署者的潜在痛苦,并为他们提供了在需要添加第二个密钥存储库之前的时间。

理想情况下,我们可以与令牌提供程序共享的任何代码都应该共享,并将尽可能多的代码移动到公共工具中。就像令牌一样,我们甚至以相同的方式处理密钥轮换。接受用当前和上一个密钥加密的收据,但使用当前密钥颁发新的收据。

收据数据本身(在加密之前)可能是

{
    "methods": [
        "password"
    ],
    "user_id": "423f19a4ac1e4f48bbb4180756e6eb6c",
    "issued_at": "2015-11-06T14:32:17.893797Z",
}

methods 在上面的有效负载中是该收据的有效且已满足的身份验证方法。

Keystone 本身不需要太多数据,只要它知道用户 ID,就可以从数据库中获取。我们需要返回的是哪些方法已经过验证,何时颁发(用于有效期检查),以及收据适用于哪个用户(以便我们可以在身份验证请求中将其与用户匹配)。

收据处理

当使用收据继续身份验证时,用户必须在 OPENSTACK-AUTH-RECEIPT 标头中提供收据 ID。当 Keystone 看到带有该标头的身份验证尝试时,它将使用设置的收据提供程序来解密有效负载(ID),然后将收据中定义的 methods 作为身份验证过程中已经满足的部分进行处理,并使用新提供的用户方法继续身份验证。

如果给定的所有方法都有效,但包括收据中的所有有效方法仍然无法满足任何身份验证规则,则返回另一个收据。

如果收据已过期,甚至不要处理用户提供的身份验证方法,立即失败。

收据 user_id 与任何方法中的 user_id 不匹配,则身份验证失败。

用户提供的任何身份验证方法失败,则身份验证失败,即使一些新方法有效,也不会延长收据,但应包含失败详细信息。

如果用户提供的方法已经在收据中得到满足,则用户提供的方法优先,即使它失败也是如此。

所有这些失败都将返回 401

备选方案

在 Ocata 中,当引入身份验证规则时,另一种方法是简单地更改失败的 MFA 身份验证的错误消息,以告知用户身份验证失败的原因。任何服务还可以解析这些错误并推断出缺失的身份验证,并生成 GUI 或 cli 查询返回给用户。

这不起作用,原因如下。虽然我们可以构建可解析的响应,但它仍然需要为每次身份验证尝试提供所有方法。这意味着对于密码+totp 的 MFA 尝试,需要缓存密码以在确定也需要 totp 时重新提交它。

对于 Horizon 来说,这不起作用。我们无法在服务器端缓存密码,也不应该将其存储在 cookie 或浏览器中,并且要求用户再次提供密码不是一个好的用户体验。

这种替代方案也不是真正的挑战响应。

安全影响

使用一种成功的身份验证方法进行身份验证的用户现在知道可以为给定用户使用哪些身份验证规则。这并不是特别不安全,因为虽然他们知道规则,但他们无法使用它们进行身份验证。此外,可以安全地假设一种成功的身份验证方法足以证明用户的身份,但不足以满足身份验证要求。

如果任何方法失败,我们仍然会返回一个错误,并且只有至少一种方法有效时才会公开身份验证规则。

另一个安全问题是,可以在收据的有效期内使用给定的收据来创建多个令牌。鉴于用户已经可以拥有多个令牌,这只有在收据被拦截并由其他人完成时才是一个问题。然而,鉴于此收据存在于 MFA 的上下文中,第二个因素应该大大限制此问题。实际上,这并不是一个独特于身份验证收据的问题,但最终我们应该采取一种收据撤销形式,在将其转换为令牌时。

通知影响

将继续为成功和失败的身份验证发布通知,就像今天一样。颁发收据不会发布通知。

我们可能会在未来添加收据通知。

其他最终用户影响

用户现在可以处理返回的数据并利用收据进行多步身份验证。

重要的是要注意,此更改不会影响仅使用没有设置身份验证规则的身份验证的用户。默认身份验证用例不会更改,只有尚未完全实现或使用的 MFA 用例才会更改。

性能影响

预计负载和身份验证处理时间会因收据的添加加密和解密而略有增加。

其他部署者影响

根据我们如何处理 fernet/jwt 密钥存储库,部署者可能需要添加第二个密钥存储库。理想情况下,我们希望允许配置,以便他们最初不需要这样做,但可以选择这样做以提高安全性。

开发人员影响

这将只影响 OpenStack 中的身份验证工作流程以及处理它们的任何代码。然而,此更改将为我们提供一种良好的编程方式来处理 MFA,并将意味着这些工具可以以有用的方式处理失败。

实现

负责人

主要负责人

工作项

  1. 将身份验证收据的支持添加到 Keystone,并将身份验证插件层更改为在配置规则中成功进行一种身份验证方法时返回它,而不是错误,并使身份验证层能够处理收据以继续身份验证。

  2. 将支持添加到 KeystoneAuth 以正确处理此问题,并从该收据推断需要其他哪些方法,以及将适当的多方法支持添加到 KeystoneAuth。

  3. 与 CLI 和 Dashboard 团队合作,为使用 KeystoneAuth 所做的更改构建 MFA 支持。(可选后续步骤)

依赖项

N/A

文档影响

需要为新功能添加额外的文档,但现有的非 MFA 身份验证路径不会更改。

我们需要添加到文档中,MFA 收据也需要加密密钥,并且默认情况下它们与 fernet 共享。需要添加注释,fernet 密钥轮换会影响如果它们的存储库共享,则收据。

参考资料