身份验证插件¶
介绍¶
身份验证插件提供了一种通用的方式来扩展 OpenStack 客户端已知的身份验证机制。
在绝大多数情况下,使用的身份验证插件将是为与 OpenStack Identity Service (Keystone) 一起使用而编写的,但是,这并非唯一可能的情况,并且身份验证插件的使用和实现机制应该足够通用,以涵盖完全自定义的身份验证解决方案。
旨在与 OpenStack Identity 服务器(例如 Keystone)一起使用的身份验证插件子集称为 Identity 插件。
可用插件¶
Keystoneauth 附带许多插件,特别是 Identity 插件。
V2 Identity 插件¶
标准的 V2 identity 插件定义在模块中:keystoneauth1.identity.v2
它们包括
Password:使用用户名和密码对 V2 identity 服务进行身份验证。Token:使用现有 token 对 V2 identity 服务进行身份验证。
V2 identity 插件必须使用一个 auth_url,该 URL 指向 V2 identity 服务器 URL 的根目录,例如:http://hostname:5000/v2.0。
V3 Identity 插件¶
标准的 V3 identity 插件定义在模块 keystoneauth1.identity.v3 中。
V3 Identity 插件与 V2 对应插件略有不同,因为 V3 身份验证请求可以包含多种身份验证方法。为了处理这种情况,V3 定义了许多不同的 AuthMethod 类
PasswordMethod:使用用户名和密码对 V3 identity 服务进行身份验证。TokenMethod:使用现有 token 对 V3 identity 服务进行身份验证。ReceiptMethod:使用现有的 auth-receipt 对 V3 identity 服务进行身份验证。此方法必须与其他至少一种方法结合使用。TOTPMethod:使用基于时间的一次性密码 (TOTP) 对 V3 identity 服务进行身份验证。TokenlessAuth:使用无 token 身份验证对 V3 identity 服务进行身份验证。ApplicationCredentialMethod:使用应用程序凭证对 V3 identity 服务进行身份验证。KerberosMethod:使用 Kerberos 对 V3 identity 服务进行身份验证。OAuth2ClientCredentialMethod:使用 OAuth2.0 客户端凭证对 V3 identity 服务进行身份验证。OAuth2mTlsClientCredential:使用 OAuth2.0 互信 TLS 客户端凭证对 V3 identity 服务进行身份验证。
然后将 AuthMethod 对象传递给 Auth 插件
>>> from keystoneauth1 import session
>>> from keystoneauth1.identity import v3
>>> password = v3.PasswordMethod(username='user',
... password='password',
... user_domain_name='default')
>>> auth = v3.Auth(auth_url='http://my.keystone.com:5000/v3',
... auth_methods=[password],
... project_id='projectid')
>>> sess = session.Session(auth=auth)
甚至可以在创建后向现有的 auth 实例添加其他方法
>>> totp = v3.TOTPMethod(username='user',
... passcode='123456',
... user_domain_name='default')
>>> auth.add_method(totp)
或者使用 MultiFactor 辅助插件一次性完成所有操作,下面部分存在一个示例。
对于您只想使用一个 AuthMethod 的常见情况,还有针对各种 AuthMethod 的辅助身份验证插件,这些插件可以更像 V2 插件一样使用
Password:仅使用PasswordMethod进行身份验证。Token:仅使用TokenMethod进行身份验证。TOTP:仅使用TOTPMethod进行身份验证。Kerberos:仅使用KerberosMethod进行身份验证。
>>> auth = v3.Password(auth_url='http://my.keystone.com:5000/v3',
... username='username',
... password='password',
... project_id='projectid',
... user_domain_name='default')
>>> sess = session.Session(auth=auth)
这将与使用上面单个 PasswordMethod 产生完全相同的影响。
V3 identity 插件必须使用一个 auth_url,该 URL 指向 V3 identity 服务器 URL 的根目录,例如:http://hostname:5000/v3。
V3 Identity 插件的多因素身份验证¶
多因素身份验证的基本示例是在一开始提供所有必需的身份验证方法。
可以通过使用方法实例构建 Auth 类来完成
from keystoneauth1 import session
from keystoneauth1.identity import v3
auth = v3.Auth(
auth_url='http://my.keystone.com:5000/v3',
auth_methods=[
v3.PasswordMethod(
username='user',
password='password',
user_domain_id="default",
),
v3.TOTPMethod(
username='user',
passcode='123456',
user_domain_id="default",
)
],
project_id='projectid',
)
sess = session.Session(auth=auth)
或者让辅助插件为您完成
from keystoneauth1 import session
from keystoneauth1.identity import v3
auth = v3.MultiFactor(
auth_url='http://my.keystone.com:5000/v3',
auth_methods=['v3password', 'v3totp'],
username='user',
password='password',
passcode='123456',
user_domain_id="default",
project_id='projectid',
)
sess = session.Session(auth=auth)
注意:MultiFactor 辅助插件不支持在 auth_methods 中使用 auth receipts,但可以使用 auth.add_method 添加。
当您在需要多种方法时只提供一种方法时,将引发 MissingAuthMethods 错误。可以捕获此错误,并根据该错误推断出缺少的哪些方法,并从中提取 receipt 以继续身份验证
auth = v3.Password(auth_url='http://my.keystone.com:5000/v3',
username='username',
password='password',
project_id='projectid',
user_domain_id='default')
sess = session.Session(auth=auth)
try:
sess.get_token()
except exceptions.MissingAuthMethods as e:
receipt = e.receipt
methods = e.methods
required_methods = e.required_auth_methods
一旦知道继续所需的身份验证方法,就可以使用其他方法扩展现有的身份验证插件
auth.add_method(
v3.TOTPMethod(
username='user',
passcode='123456',
user_domain_id='default',
)
)
sess.get_token()
或者,如果您没有现有的身份验证方法,但有 receipt,也可以继续
auth = v3.TOTP(
auth_url='http://my.keystone.com:5000/v3',
username='user',
passcode='123456',
user_domain_id='default',
project_id='projectid',
)
auth.add_method(v3.ReceiptMethod(receipt=receipt))
sess = session.Session(auth=auth)
sess.get_token()
独立插件¶
服务可以部署在独立环境中,而无需与身份服务集成。提供以下插件以支持独立服务
HTTPBasicAuth:HTTP Basic 身份验证NoAuth:无身份验证
独立插件必须提供一个 endpoint,该 endpoint 指向正在使用的服务的 URL,因为没有服务目录来查找 endpoint
from keystoneauth1 import session
from keystoneauth1 import noauth
auth = noauth.NoAuth(endpoint='http://hostname:6385/')
sess = session.Session(auth=auth)
HTTPBasicAuth 也需要一个 username 和 password
from keystoneauth1 import session
from keystoneauth1 import http_basic
auth = http_basic.HTTPBasicAuth(endpoint='http://hostname:6385/',
username='myUser',
password='myPassword')
sess = session.Session(auth=auth)
联合身份验证¶
提供以下 V3 插件以支持联合身份验证
MappedKerberos:联合(映射)Kerberos。Password:SAML2 密码身份验证。v3:OpenIDConnectAccessToken:插件,用于重用现有的 OpenID Connect 访问令牌。v3:OpenIDConnectAuthorizationCode:OpenID Connect 授权码类型。v3:OpenIDConnectClientCredentials:OpenID Connect 客户端凭证类型。v3:OpenIDConnectPassword:OpenID Connect 资源所有者密码凭证类型。Keystone2Keystone:Keystone 到 Keystone 联合身份验证。
Keystone2Keystone 插件是特殊的,因为它将一个 Keystone 实例的 Password auth 作为 Identity Provider 的输入,以便在作为 Service Provider 的 Keystone 上创建会话,例如
from keystoneauth1 import session
from keystoneauth1.identity import v3
from keystoneauth1.identity.v3 import k2k
pwauth = v3.Password(auth_url='http://my.keystone.com:5000/v3',
username='username',
password='password',
project_id='projectid',
user_domain_name='Default')
k2kauth = k2k.Keystone2Keystone(pwauth, 'mysp',
project_id='federated_projectid')
k2ksession = session.Session(auth=k2kauth)
OpenIDConnectPassword 插件也支持 OTP。在 Identity Provider 需要超过密码才能对用户进行身份验证的情况下,需要此选项。由于 OTP 通常是不断变化的短时间代码,因此在激活此选项时,将提示用户在执行身份验证过程时输入 OTP 代码。
要启用此选项,用户需要导出环境变量“OS_IDP_OTP_KEY”,其中包含 Identity Provider 身份验证 API 使用的 OTP 密钥。
例如:如果 Identity Provider 的身份验证 API 需要如下 JSON
{
"username": "user1",
"password": "passwd",
"totp": "763907"
}
那么,您将在“OS_IDP_OTP_KEY”中使用“totp”值,例如“export OS_IDP_OTP_KEY=totp”。
配置“OS_IDP_OTP_KEY”环境变量后,每次通过 python openstack-client 登录时,都会显示一个提示,要求您输入 OTP 代码。
版本无关的 Identity 插件¶
标准的版本无关的 identity 插件定义在模块 keystoneauth1.identity.generic 中。
对于同时存在于 identity V2 和 V3 API 下的插件,存在一种抽象,允许插件确定服务器支持的可用版本,并使用最合适的 API。
这些插件是
Password:使用用户/密码对 v2 或 v3 API 进行身份验证。Token:使用现有 token 对 v2 或 v3 API 进行身份验证。
这些插件首先通过查询 identity 服务器来确定可用的版本,因此与这些插件一起使用的 auth_url 应指向 identity 服务器的基本 URL。如果 auth_url 指向 V2 或 V3 端点,它将限制插件仅与该 API 版本一起工作。
简单插件¶
除了 Identity 插件之外,还有一个始终使用相同的提供的 token 和 endpoint 的简单插件。这对于您拥有 token 并想要绕过身份验证以获取后续请求的新 token 的情况非常有用。测试、代理和代表用户进行服务到服务身份验证是此身份验证插件的良好用例示例。
它可以在 keystoneauth1.token_endpoint.Token 处找到。
例如
>>> from keystoneauth1 import token_endpoint
>>> from keystoneauth1 import session
>>> a = token_endpoint.Token('http://my.keystone.com:5000/v3',
... token=token)
>>> s = session.Session(auth=a)
V3 OAuth 1.0a 插件¶
还存在一个 OAuth 1.0a 身份验证插件。我们提供一个辅助身份验证插件:V3OAuth1。该插件需要 OAuth 消费者的密钥和密钥,以及 OAuth 访问令牌的密钥和密钥。例如
>>> from keystoneauth1.extras import oauth1
>>> from keystoneauth1 import session
>>> a = oauth1.V3OAuth1('http://my.keystone.com:5000/v3',
... consumer_key=consumer_id,
... consumer_secret=consumer_secret,
... access_key=access_token_key,
... access_secret=access_token_secret)
>>> s = session.Session(auth=a)
应用程序凭证¶
有一个特定的身份验证方法,用于与支持应用程序凭证身份验证的 Identity 服务器交互。由于应用程序凭证与特定项目的用户相关联,因此某些参数是不需要的,因为使用传统的密码身份验证会发生这种情况。可以使用以下方法使用应用程序凭证进行 token 身份验证
ApplicationCredential:
以下示例显示了与会话一起使用该方法
>>> from keystoneauth1 import session
>>> from keystone.identity import v3
>>> auth = v3.ApplicationCredential(
application_credential_secret='application_credential_secret',
application_credential_id='c2872b920853478292623be94b657090'
)
>>> sess = session.Session(auth=auth)
OAuth2.0 客户端凭证¶
警告
根据 RFC6749,访问令牌只能添加到使用 HTTPS 的请求中。
有一个特定的身份验证方法,用于与支持 OAuth2.0 客户端凭证授权的 Identity 服务器交互。与其他身份验证方法的主要区别是,在通过身份验证后,session 将添加带有 OAuth2.0 访问令牌的“Authorization”标头,以发送后续请求。可以使用以下方法使用 OAuth2.0 客户端凭证进行 token 身份验证
OAuth2ClientCredential:
以下示例显示了与会话一起使用该方法
>>> from keystoneauth1 import session
>>> from keystone.identity import v3
>>> auth = v3.OAuth2ClientCredential(
oauth2_endpoint='https://keystone.host/identity/v3/OS-OAUTH2/token'
oauth2_client_id='f96a2fec117141a6b5fbaa0485632244',
oauth2_client_secret='client_credential_secret'
)
>>> sess = session.Session(auth=auth)
OAuth2.0 互信 TLS 客户端凭证¶
警告
根据 RFC8705,访问令牌只能添加到使用互信 TLS 的请求中。
有一个特定的身份验证方法,用于与支持 OAuth 2.0 互信 TLS 客户端身份验证的 Identity 服务器交互。与其他身份验证方法的主要区别是,在通过身份验证后,session 将添加带有 OAuth2.0 证书绑定访问令牌的“Authorization”标头,以发送后续请求。可以使用以下方法使用 OAuth2.0 互信 TLS 客户端凭证进行 token 身份验证
OAuth2mTlsClientCredential:
以下示例显示了与会话一起使用该方法
>>> from keystoneauth1 import session
>>> from keystone.identity import v3
>>> auth = v3.OAuth2mTlsClientCredential(
auth_url='http://keystone.host:5000/v3'
oauth2_endpoint='https://keystone.host/identity/v3/OS-OAUTH2/token'
oauth2_client_id='f96a2fec117141a6b5fbaa0485632244'
)
>>> sess = session.Session(auth=auth)
无 Token 身份验证¶
还存在一个用于无 token 身份验证的插件。它提供了一种使用 X.509 TLS 客户端证书在 Identity 服务器内授权客户端操作,而无需颁发 token 的方法。我们提供一个无 token 身份验证插件:
TokenlessAuth
它主要由服务客户端用于 token 验证,以下是一个此插件实际使用的示例
>>> from keystoneauth1 import session
>>> from keystoneauth1.identity import v3
>>> auth = v3.TokenlessAuth(auth_url='https://keystone:5000/v3',
... domain_name='my_service_domain')
>>> sess = session.Session(
... auth=auth,
... cert=('/opt/service_client.crt',
... '/opt/service_client.key'),
... verify='/opt/ca.crt')
按名称加载插件¶
在 auth_token 中间件和一些服务到服务的通信中,可以通过名称指定要加载的插件。可用的身份验证选项取决于您指定的插件。目前 keystoneauth 中可用的身份验证插件是
http_basic:
keystoneauth1.http_basic.HTTPBasicAuthnone:
keystoneauth1.noauth.NoAuthpassword:
keystoneauth1.identity.generic.Passwordtoken:
keystoneauth1.identity.generic.Tokenv2password:
keystoneauth1.identity.v2.Passwordv2token:
keystoneauth1.identity.v2.Tokenv3applicationcredential:
keystoneauth1.identity.v3.ApplicationCredentialv3password:
keystoneauth1.identity.v3.Passwordv3token:
keystoneauth1.identity.v3.Tokenv3fedkerb:
keystoneauth1.extras.kerberos.MappedKerberosv3kerberos:
keystoneauth1.extras.kerberos.Kerberosv3oauth1:
keystoneauth1.extras.oauth1.v3.OAuth1v3oidcaccesstoken:
keystoneauth1.identity.v3:OpenIDConnectAccessTokenv3oidcauthcode:
keystoneauth1.identity.v3:OpenIDConnectAuthorizationCodev3oidcdeviceauthz:
keystoneauth1.loading._plugins.identity.v3:OpenIDConnectDeviceAuthorizationv3oidcclientcredentials:
keystoneauth1.identity.v3:OpenIDConnectClientCredentialsv3oidcpassword:
keystoneauth1.identity.v3:OpenIDConnectPasswordv3samlpassword:
keystoneauth1.extras._saml2.v3.Passwordv3tokenlessauth:
keystoneauth1.identity.v3.TokenlessAuthv3totp:
keystoneauth1.identity.v3.TOTPv3oauth2clientcredential:
keystoneauth1.identity.v3.OAuth2ClientCredentialv3oauth2mtlsclientcredential:
keystoneauth1.identity.v3.OAuth2mTlsClientCredential
创建身份验证插件¶
创建身份插件¶
如果您已在 Identity 服务中实现新的身份验证机制,那么您可以重用现有 Identity 机制可用的许多基础设施。由于 V2 identity API 基本上是冻结的,因此预计新的插件是针对 V3 API 的。
要实现一个可以与其他插件结合使用的新 V3 插件,您应该实现基础类 keystoneauth1.identity.v3.AuthMethod 并实现 get_auth_data() 函数。如果您的插件不能与现有的 keystoneauth1.identity.v3.AuthMethod 一起使用,那么您应该直接覆盖 keystoneauth1.identity.v3.Auth。
新的 AuthMethod 应该通过 __init__() 接收所有必需的参数,并从 get_auth_data() 返回一个元组,其中包含此插件的唯一标识符(例如 *password*)和一个包含要发送到身份验证服务器的有效负载值的字典。会话、调用 auth 对象和请求标头也传递给此函数,以便插件可以使用或操作它们。
您还应该提供一个继承自 keystoneauth1.identity.v3.Auth 的类,并将您的新 AuthMethod 的实例作为 auth_methods 参数传递给 keystoneauth1.identity.v3.Auth。
按照惯例(和上面一样),这些命名为 PluginType 和 PluginTypeMethod(例如 Password 和 PasswordMethod)。
创建自定义插件¶
要实现一个全新的插件,您应该实现基础类 keystoneauth1.plugin.BaseAuthPlugin 并提供 get_endpoint()、get_token() 和 invalidate() 方法。
get_token() 用于从插件检索字符串令牌。预期插件会缓存收到的令牌,因此如果令牌仍然有效,则应该重用它,而不是获取新的令牌。提供了一个会话对象,插件可以使用它来联系其服务器。(注意:在进行这些请求时使用 authenticated=False,否则它将最终被递归调用)。返回值应该是字符串形式的令牌。
get_endpoint() 用于确定特定服务请求的基本 URL。传递给该函数作为关键字参数的是由 keystoneauth1.session.Session.request() 中的 endpoint_filter 变量给出的参数。还提供了一个会话对象,以便插件可以联系外部源来确定端点。同样,这通常每请求调用一次,因此插件如果合适,应该缓存这些响应。返回值应该是用于通信的基本 URL。
invalidate() 也应该实现,以清除当前用户凭据,以便在下一次 get_token() 调用时可以检索新的令牌。
最简单的插件示例是 keystoneauth1.token_endpoint.Token 插件。