配置 Keystone 以进行无令牌授权

定义

  • X.509 无令牌授权: 提供了一种使用 X.509 SSL 客户端证书在 Keystone 中授权客户端操作的方式,而无需颁发令牌。

    此功能旨在通过消除对服务用户令牌进行身份验证和授权的需求,从而降低 Keystone auth_token 中间件中用户令牌验证的复杂性。因此,无需创建和维护服务用户帐户,仅用于用户令牌验证。此外,此功能通过避免服务用户令牌处理(即请求、缓存和续订)来提高效率。通过无需在配置文件中处理服务用户凭据,部署者无需承担在整个部署生命周期中保护服务器用户密码的负担。此功能还通过使用 X.509 证书而不是密码进行身份验证来提高安全性。

    有关详细信息,请参阅规范 使用 X.509 客户端 SSL 证书进行无令牌授权

  • 公钥基础设施或 PKI: 一种利用公钥密码学实现身份验证、授权、机密性、完整性、不可否认性的系统。在该系统中,身份由公钥证书表示。公钥证书处理受 X.509 标准管理。

    有关更多信息,请参阅 公钥基础设施X.509

  • X.509 证书: 一种有时间限制的数字身份,由其颁发者使用加密方式进行认证或数字签名,如 X.509 标准所定义。它包含可用于唯一标识其所有者的信息。例如,证书的所有者由 Subject 属性标识,而颁发者由 Issuer 属性标识。

    在操作中,证书通常以 隐私增强邮件 (PEM) 格式存储。

    以下是一个证书通常包含的内容的示例

    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 4098 (0x1002)
        Signature Algorithm: sha256WithRSAEncryption
            Issuer: DC = com, DC = somedemo, O = openstack, OU = keystone, CN = Intermediate CA
            Validity
                Not Before: Jul  5 18:42:01 2019 GMT
                Not After : Jul  2 18:42:01 2029 GMT
            Subject: DC = com, DC = somedemo, O = Default, OU = keystone, CN = glance
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    Public-Key: (2048 bit)
                    Modulus:
                        00:cf:35:8b:cd:4f:17:28:38:25:f7:e2:ac:ce:4e:
                        d7:05:74:2f:99:04:f8:c2:13:14:50:18:70:d6:b0:
                        53:62:15:60:59:99:90:47:e2:7e:bf:ca:30:4a:18:
                        f5:b8:29:1e:cc:d4:b8:49:9c:4a:aa:d9:10:b9:d7:
                        9f:55:85:cf:e3:44:d2:3c:95:42:5a:b0:53:3e:49:
                        9d:6b:b2:a0:9f:72:9d:76:96:55:8b:ee:c4:71:46:
                        ab:bd:12:71:42:a0:60:29:7a:66:16:e1:fd:03:17:
                        af:a3:c7:26:c3:c3:8b:a7:f9:c0:22:08:2d:e4:5c:
                        07:e1:44:58:c1:b1:88:ae:45:5e:03:10:bb:b4:c2:
                        42:52:da:4e:b5:1b:d6:6f:49:db:a4:5f:8f:e5:79:
                        9f:73:c2:37:de:99:a7:4d:6f:cb:b5:f9:7e:97:e0:
                        77:c8:40:21:40:ef:ab:d3:55:72:37:6c:28:0f:bd:
                        37:8c:3a:9c:e9:a0:21:6b:63:3f:7a:dd:1b:2c:90:
                        07:37:66:86:66:36:ef:21:bb:43:df:d5:37:a9:fa:
                        4b:74:9a:7c:4b:cd:8b:9d:3b:af:6d:50:fe:c9:0a:
                        25:35:c5:1d:40:35:1d:1f:f9:10:fd:b6:5c:45:11:
                        bb:67:11:81:3f:ed:d6:27:04:98:8f:9e:99:a1:c8:
                        c1:2d
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Basic Constraints:
                    CA:FALSE
                Netscape Cert Type:
                    SSL Client, S/MIME
                Netscape Comment:
                    OpenSSL Generated Client Certificate
                X509v3 Subject Key Identifier:
                    EE:38:FB:60:65:CD:81:CE:B2:01:E3:A5:99:1B:34:6C:1A:74:97:BB
                X509v3 Authority Key Identifier:
                    keyid:64:17:77:31:00:F2:ED:90:9A:A8:1D:B5:7D:75:06:03:B5:FD:B9:C0
    
                X509v3 Key Usage: critical
                    Digital Signature, Non Repudiation, Key Encipherment
                X509v3 Extended Key Usage:
                    TLS Web Client Authentication, E-mail Protection
        Signature Algorithm: sha256WithRSAEncryption
             82:8b:17:c6:f4:63:eb:8d:69:03:7a:bf:54:7f:37:02:eb:94:
             ef:57:fd:27:8f:f8:67:e9:0e:3b:0a:40:66:11:68:e6:04:1a:
             8a:da:47:ed:83:eb:54:34:3b:5b:70:18:cf:62:e2:6d:7c:74:
             4c:cf:14:b3:a9:70:b2:68:ed:19:19:71:6f:7d:87:22:38:8d:
             83:c6:59:15:74:19:5b:a2:64:6f:b9:9a:81:3d:0a:67:58:d1:
             e2:b2:9b:9b:8f:60:7a:8c:0e:61:d9:d7:04:63:cc:58:af:36:
             a4:61:86:44:1c:64:e2:9b:bd:f3:21:87:dd:18:81:80:af:0f:
             d6:4c:9f:ae:0f:01:e0:0e:38:4d:5d:71:da:0b:11:39:bd:c3:
             5d:0c:db:14:ca:bf:7f:07:37:c9:36:bd:22:a5:73:c6:e1:13:
             53:15:de:ac:4a:4b:dc:48:90:47:06:fa:d4:d2:5d:c6:d2:d4:
             3f:0f:49:0f:27:de:21:b0:bd:a3:92:c3:cb:69:b6:8d:94:e1:
             e3:40:b4:80:c7:e6:e2:df:0a:94:52:d1:16:41:0f:bc:29:a8:
             93:40:1b:77:28:a3:f2:cb:3c:7f:bb:ae:a6:0e:b3:01:78:09:
             d3:2b:cf:2f:47:83:91:36:37:43:34:6e:80:2b:81:10:27:95:
             95:ae:1e:93:42:94:a6:23:b8:07:c0:0f:38:23:70:b0:8e:79:
             14:cd:72:8a:90:bf:77:ad:74:3c:23:9e:67:5d:0e:26:15:6e:
             20:95:6d:d0:89:be:a3:6c:4a:13:1d:39:fb:21:e3:9c:9f:f3:
             ff:15:da:0a:28:29:4e:f4:7f:5e:0f:70:84:80:7c:09:5a:1c:
             f4:ac:c9:1b:9d:38:43:dd:27:00:95:ef:14:a0:57:3e:26:0b:
             d8:bb:40:d6:1f:91:92:f0:4e:5d:93:1c:b7:3d:bd:83:ef:79:
             ee:47:ca:61:04:00:e6:39:05:ab:f0:cd:47:e9:25:c8:3a:4c:
             e5:62:9f:aa:8a:ba:ea:46:10:ef:bd:1e:24:5f:0c:89:8a:21:
             bb:9d:c7:73:0f:b9:b5:72:1f:1f:1b:5b:ff:3a:cb:d8:51:bc:
             bb:9a:40:91:a9:d5:fe:95:ac:73:a5:12:6a:b2:e3:b1:b2:7d:
             bf:e7:db:cd:9f:24:63:6e:27:cf:d8:82:d9:ac:d8:c9:88:ea:
             4f:1c:ae:7d:b7:c7:81:b2:1c:f8:6b:6b:85:3b:f2:14:cb:c7:
             61:81:ad:64:e7:d9:90:a3:ea:69:7e:26:7a:0a:29:7b:1b:2a:
             e0:38:f7:58:d1:90:82:44:01:ab:05:fd:68:0c:ab:9e:c6:94:
             76:34:46:8b:66:bb:02:07
    

    有关更多信息,请参阅 公钥证书

  • 颁发者: X.509 证书的颁发者。它也被称为 证书颁发机构 (CA) 或认证机构。颁发者通常以 RFC 2253 格式表示。在本文档中,issuerissuer DNCAtrusted issuer 可以互换使用。

先决条件

此功能要求 Keystone API 代理 SSL 终止器验证传入的 X.509 SSL 客户端证书,并将证书信息(即主题 DN、颁发者 DN 等)作为请求环境的一部分传递给 Keystone 应用程序。在撰写本文时,此功能仅使用 HAProxy 或 Apache 作为 Keystone API 代理 SSL 终止器进行了测试。

本文档的其余部分要求读者熟悉

配置此功能需要 OpenSSL 命令行工具 (CLI)。请参阅各自的操作系统安装指南,了解如何安装它。

Keystone 配置

此功能利用 Keystone 联合能力来确定与传入的 X.509 SSL 客户端证书关联的授权,方法是将证书属性映射到 Keystone 身份。因此,客户端证书的直接颁发者或受信任的证书颁发机构 (CA) 是远程身份提供者 (IDP),并且颁发者专有名称 (DN) 的 SHA256 哈希的十六进制输出用作 IDP ID。

注意

客户端证书颁发者 DN 的格式可能因 SSL 终止器而异。例如,Apache mod_ssl 可能会使用 RFC 2253,而 HAProxy 可能会使用旧格式。旧格式由链接到 OpenSSL 旧版本的应用程序使用,其中专有名称的字符串表示形式尚未成为事实标准。有关旧格式的更多信息,请参阅 OpenSSL CLI 手册中的 nameopt。因此,在整个配置中保持格式一致非常重要,因为 Keystone 在比较证书属性时会进行精确的字符串匹配。

如何获取受信任的颁发者 DN

如果 SSL 在 HAProxy 或 Apache 处终止,则可以使用 OpenSSL CLI 获取客户端证书颁发者 DN。

从版本 2.3.11 开始,Apache mod_ssl 默认使用 RFC 2253 处理证书专有名称。但是,部署者可以通过配置 LegacyDNStringFormat 选项来使用旧格式。

另一方面,HAProxy 仅支持旧格式。

要以 RFC 2253 格式获取颁发者 DN

$ openssl x509 -issuer -noout -in client_cert.pem -nameopt rfc2253 | sed 's/^\s*issuer=//'

要以旧格式获取颁发者 DN

$ openssl x509 -issuer -noout -in client_cert.pem -nameopt compat | sed 's/^\s*issuer=//'

如何从受信任的颁发者 DN 计算 IDP ID

受信任颁发者 DN 的 SHA256 哈希的十六进制输出正在 Keystone 中用作身份提供者 ID。可以使用 OpenSSL CLI 获取它。

要为 RFC 2253 格式的颁发者 DN 计算 IDP ID

$ openssl x509 -issuer -noout -in client_cert.pem -nameopt rfc2253 | tr -d '\n' | sed 's/^\s*issuer=//' | openssl dgst -sha256 -hex | awk '{print $2}'

要为旧格式的颁发者 DN 计算 IDP ID

$ openssl x509 -issuer -noout -in client_cert.pem -nameopt compat | tr -d '\n' | sed 's/^\s*issuer=//' | openssl dgst -sha256 -hex | awk '{print $2}'

Keystone 配置文件更改

Keystone 配置文件 keystone.conftokenless_auth 部分中的以下选项用于启用 X.509 无令牌授权功能

  • trusted_issuer - X.509 SSL 客户端证书的受信任颁发者列表。更具体地说,是 如何获取受信任的颁发者 DN 部分中提到的受信任颁发者 DN 列表。受信任颁发者 DN 的格式必须与 SSL 终止器传递到请求环境中的格式完全匹配。例如,如果 SSL 在 Apache mod_ssl 中终止,则颁发者 DN 应该采用 RFC 2253 格式。如果 SSL 在 HAProxy 中终止,则预计颁发者 DN 将采用旧格式。这是一个多字符串列表选项。没有任何受信任的颁发者意味着实际上禁用了 X.509 无令牌授权功能。

  • protocol - 与选项 issuer_attribute 结合使用,用于查找其对应的映射的 X.509 无令牌授权协议名称。默认值为 x509

  • issuer_attribute - 作为 X.509 无令牌授权的 IdP ID 的颁发者属性,并与协议结合使用以查找其对应的映射。它是 WSGI 环境中的环境变量,引用客户端证书的颁发者。默认值为 SSL_CLIENT_I_DN

这是一个包含两个 trusted_issuer 和将 protocol 设置为 x509 的示例配置。

[tokenless_auth]
trusted_issuer = emailAddress=admin@foosigner.com,CN=Foo Signer,OU=eng,O=abc,L=San Jose,ST=California,C=US
trusted_issuer = emailAddress=admin@openstack.com,CN=OpenStack Cert Signer,OU=keystone,O=openstack,L=Sunnyvale,ST=California,C=US
protocol = x509

设置映射

与联合身份验证一样,X.509 无令牌授权也利用映射机制来确定与传入的 X.509 SSL 客户端证书关联的身份,方法是将证书属性映射到 Keystone 身份。因此,身份提供者对应于 X.509 SSL 客户端证书的颁发者。默认情况下,给定身份的协议为 x509,但可以进行配置。

创建身份提供者 (IDP)

如前所述,身份提供者 ID 是颁发者专有名称 (DN) 的 SHA256 哈希的十六进制输出。

注意

如果有多个受信任的颁发者,则必须创建多个 IDP,每个受信任的颁发者一个。

要为给定的受信任颁发者创建 IDP,请遵循 如何从受信任的颁发者 DN 计算 IDP ID 部分中的说明来计算 IDP ID。然后使用 OpenStack CLI 创建 IDP。例如:

$ openstack identity provider create --description 'IDP foo' <IDP ID>

创建映射

需要创建映射,将客户端证书中的 Subject DN 映射为用户,如果用户的 type 在映射中定义为 local,则产生有效的本地用户。例如,如果客户端证书具有 Subject DNCN=alex,OU=eng,O=nice-network,L=Sunnyvale, ST=California,C=US,在以下示例中,user_name 将映射到``alex``,domain_name 将映射到 nice-network。并且用户的 type 设置为 local。如果未定义用户的 type,则默认设置为 ephemeral

请参阅 mod_ssl,了解详细的映射属性。

[
    {
        "local": [
            {
                "user": {
                    "name": "{0}",
                    "domain": {
                        "name": "{1}"
                    },
                    "type": "local"
                }
            }
        ],
        "remote": [
            {
                "type": "SSL_CLIENT_S_DN_CN",
                "whitelist": ["glance", "nova", "swift", "neutron"]
            },
            {
                 "type": "SSL_CLIENT_S_DN_O",
                 "whitelist": ["Default"]
            }
        ]
    }
]

当用户的 type 未定义或设置为 ephemeral 时,映射的用户不必是有效的本地用户,但映射必须产生至少一个有效的本地组。例如

[
    {
        "local": [
            {
                "user": {
                    "name": "{0}",
                    "type": "ephemeral"
                },
                "group": {
                    "domain": {
                        "name": "{1}"
                    },
                    "name": "openstack_services"
                }
            }
        ],
        "remote": [
            {
                "type": "SSL_CLIENT_S_DN_CN",
                "whitelist": ["glance", "nova", "swift", "neutron"]
            },
            {
                 "type": "SSL_CLIENT_S_DN_O",
                 "whitelist": ["Default"]
            }
        ]
    }
]

注意

上述映射假定 openstack_services 组已存在并具有适当的角色分配(即允许令牌验证)。如果不是,则需要创建它。

要使用 OpenStack CLI 创建映射,假设映射已保存到文件 x509_tokenless_mapping.json

$ openstack mapping create --rules x509_tokenless_mapping.json x509_tokenless

注意

映射 ID 是任意的,它可以是任何字符串,与 IDP ID 不同。

创建协议

协议名称必须与 tokenless_auth 部分 Keystone 配置文件的 protocol 选项指定的名称相同。协议名称由用户设计,可以采用任何名称,与 IDP ID 不同。

协议名称和 IDP ID 将唯一标识映射。

要使用 OpenStack CLI 创建协议

$ openstack federation protocol create --identity-provider <IDP ID>
  --mapping x509_tokenless x509

注意

如果有多个受信任的颁发者,则必须为每个 IDP 创建多个协议。所有 IDP 可以共享相同的映射,但 IDP ID 和协议的组合必须是唯一的。

SSL 终止器配置

Apache 配置

如果 SSL 在 Apache mod_ssl 处终止,则 Apache 必须配置为处理双向 SSL,并将 SSL 证书信息作为请求环境的一部分传递给 Keystone 应用程序。

客户端身份验证属性 SSLVerifyClient 应设置为 optional 以允许其他令牌身份验证方法,并且属性 SSLOptions 需要设置为 +StdEnvVars 以允许传递证书属性。例如,

<VirtualHost *:443>
    WSGIScriptAlias / /var/www/cgi-bin/keystone/main
    ErrorLog /var/log/apache2/keystone.log
    CustomLog /var/log/apache2/access.log combined
    SSLEngine on
    SSLCertificateFile    /etc/apache2/ssl/apache.cer
    SSLCertificateKeyFile /etc/apache2/ssl/apache.key
    SSLCACertificatePath /etc/apache2/capath
    SSLOptions +StdEnvVars
    SSLVerifyClient optional
</VirtualHost>

HAProxy 和 Apache 配置

如果 SSL 在 HAProxy 处终止,而 Apache 是 Keystone 应用程序的 API 代理,则 HAProxy 必须配置为处理双向 SSL,并通过请求标头传递 SSL 证书信息。Apache 反过来需要将这些请求标头引入请求环境。

以下是如何配置 HAProxy 以处理双向 SSL 并通过请求标头传递 SSL 证书信息的示例。

frontend http-frontend
    mode http
    option forwardfor
    bind 10.1.1.1:5000 ssl crt /etc/keystone/ssl/keystone.pem ca-file /etc/keystone/ssl/ca.pem verify optional

    reqadd X-Forwarded-Proto:\ https if { ssl_fc }
    http-request set-header X-SSL                   %[ssl_fc]
    http-request set-header X-SSL-Client-Verify     %[ssl_c_verify]
    http-request set-header X-SSL-Client-SHA1       %{+Q}[ssl_c_sha1]
    http-request set-header X-SSL-Client-DN         %{+Q}[ssl_c_s_dn]
    http-request set-header X-SSL-Client-CN         %{+Q}[ssl_c_s_dn(cn)]
    http-request set-header X-SSL-Client-O          %{+Q}[ssl_c_s_dn(o)]
    http-request set-header X-SSL-Issuer            %{+Q}[ssl_c_i_dn]
    http-request set-header X-SSL-Issuer-CN         %{+Q}[ssl_c_i_dn(cn)]

当请求到达 Apache Keystone API 代理时,Apache 需要将这些 SSL 标头引入请求环境。以下是如何配置 Apache 以实现此目的的示例。

<VirtualHost 192.168.0.10:5000>
    WSGIScriptAlias / /var/www/cgi-bin/keystone/main

    # Bring the needed SSL certificate attributes from HAProxy into the
    # request environment
    SetEnvIf X-SSL-Issuer "^(.*)$" SSL_CLIENT_I_DN=$0
    SetEnvIf X-SSL-Issuer-CN "^(.*)$" SSL_CLIENT_I_DN_CN=$0
    SetEnvIf X-SSL-Client-CN "^(.*)$" SSL_CLIENT_S_DN_CN=$0
    SetEnvIf X-SSL-Client-O "^(.*)$" SSL_CLIENT_S_DN_O=$0
</VirtualHost>

设置 auth_token 中间件

为了将 auth_token 中间件用作 X.509 无令牌授权的服务客户端,需要设置可配置的选项和范围信息。

可配置的选项

应将 auth_token 中间件中的以下可配置选项设置为正确的值

  • auth_type - 必须设置为 v3tokenlessauth

  • certfile - 设置为证书文件的完整路径。

  • keyfile - 设置为私钥文件的完整路径。

  • cafile - 设置为受信任的 CA 证书文件的完整路径。

  • project_nameproject_id - 设置为作用域项目。

  • project_domain_nameproject_domain_id - 如果指定了 project_name

这是一个使用 X.509 无令牌授权进行用户令牌验证的 auth_token 中间件配置的示例。

[keystone_authtoken]
memcached_servers = localhost:11211
cafile = /etc/keystone/ca.pem
project_domain_name = Default
project_name = service
auth_url = https://192.168.0.10/identity/v3
auth_type = v3tokenlessauth
certfile = /etc/glance/certs/glance.pem
keyfile = /etc/glance/private/glance_private_key.pem