PKI 用户身份验证

编辑

您可以配置 Elasticsearch 以使用公钥基础设施 (PKI) 证书来验证用户身份。在这种情况下,直接连接到 Elasticsearch 的客户端必须提供 X.509 证书。首先,证书必须在 Elasticsearch 的 SSL/TLS 层上被接受进行身份验证。然后,它们可以选择性地通过 PKI 领域进行进一步验证。请参阅直接连接到 Elasticsearch 的客户端的 PKI 身份验证

您还可以使用 PKI 证书来验证 Kibana 的身份,但这需要一些额外的配置。在 Elasticsearch 上,此配置使 Kibana 能够充当 SSL/TLS 身份验证的代理,并将客户端证书提交给 Elasticsearch,以便由 PKI 领域进行进一步验证。请参阅连接到 Kibana 的客户端的 PKI 身份验证

直接连接到 Elasticsearch 的客户端的 PKI 身份验证

编辑

要在 Elasticsearch 中使用 PKI,您需要配置一个 PKI 领域,在所需的网络层(传输或 http)上启用客户端身份验证,并将用户证书中 Subject 字段中的专有名称 (DN) 映射到角色。您可以在角色映射文件中创建映射,或者使用角色映射 API。

  1. xpack.security.authc.realms.pki 命名空间下,将 pki 领域的领域配置添加到 elasticsearch.yml。您必须显式设置 order 属性。有关您可以为 pki 领域设置的所有选项,请参阅PKI 领域设置

    例如,以下代码片段显示了最基本的 pki 领域配置

    xpack:
      security:
        authc:
          realms:
            pki:
              pki1:
                order: 1

    使用此配置,任何受 Elasticsearch SSL/TLS 层信任的证书都将被接受进行身份验证。用户名是从最终实体证书的 Subject 字段中的 DN 中提取的通用名称 (CN)。此配置不足以允许对 Kibana 进行 PKI 身份验证;需要额外的步骤。

    当您在 elasticsearch.yml 中配置领域时,仅使用您指定的领域进行身份验证。如果您还想使用 nativefile 领域,则必须将其包含在领域链中。

  2. 可选:用户名由 username_pattern 定义。如果您想使用 Subject DN 的 CN 以外的其他内容作为用户名,则可以指定一个正则表达式来提取所需的用户名。该正则表达式应用于 Subject DN。

    例如,以下配置中的正则表达式从 Subject DN 中提取电子邮件地址

    xpack:
      security:
        authc:
          realms:
            pki:
              pki1:
                order: 1
                username_pattern: "EMAILADDRESS=(.*?)(?:,|$)"

    如果正则表达式过于严格,并且与客户端证书的 Subject DN 不匹配,则该领域不会验证该证书。

  3. 可选:如果您希望相同的用户在连接到 Kibana 时也使用证书进行身份验证,则必须将 Elasticsearch PKI 领域配置为允许委派。请参阅连接到 Kibana 的客户端的 PKI 身份验证
  4. 重新启动 Elasticsearch,因为领域配置不会自动重新加载。如果您要继续执行后续步骤,您可能希望将重新启动保留到最后。
  5. 启用 SSL/TLS.
  6. 在所需的网络层(传输或 http)上启用客户端身份验证。

    要在客户端直接连接到 Elasticsearch 时使用 PKI,您必须启用带有客户端身份验证的 SSL/TLS。也就是说,您必须将 xpack.security.transport.ssl.client_authenticationxpack.security.http.ssl.client_authentication 设置为 optionalrequired。如果设置值为 optional,则没有证书的客户端可以使用其他凭据进行身份验证。

    当客户端直接连接到 Elasticsearch 并且未通过代理进行身份验证时,PKI 领域依赖于节点网络接口的 TLS 设置。可以将该领域配置为比底层网络连接更具限制性。也就是说,可以配置节点,以便某些连接被网络接口接受,但随后无法通过 PKI 领域进行身份验证。但是,反之则不然。PKI 领域无法验证已被网络接口拒绝的连接。

    特别是,这意味着

    • 传输或 http 接口必须通过将 client_authentication 设置为 optionalrequired 来请求客户端证书。
    • 该接口必须通过配置 truststorecertificate_authorities 路径,或通过将 verification_mode 设置为 none信任客户端提供的证书。
    • 该接口支持的协议必须与客户端使用的协议兼容。

    有关这些设置的说明,请参阅常规 TLS 设置

    必须配置相关的网络接口(传输或 http)以信任要在 PKI 领域中使用的任何证书。但是,可以将 PKI 领域配置为仅信任网络接口接受的证书的子集。当 SSL/TLS 层信任由与签署用户证书的 CA 不同的 CA 签署的证书的客户端时,这非常有用。

    要使用自己的信任存储配置 PKI 领域,请指定 truststore.path 选项。该路径必须位于 Elasticsearch 配置目录 (ES_PATH_CONF) 中。例如

    xpack:
      security:
        authc:
          realms:
            pki:
              pki1:
                order: 1
                truststore:
                  path: "pki1_truststore.jks"

    如果信任存储受密码保护,则应通过将相应的 secure_password 设置添加到 Elasticsearch 密钥库来配置密码。例如,以下命令为上面的示例领域添加密码

    bin/elasticsearch-keystore add \
    xpack.security.authc.realms.pki.pki1.truststore.secure_password

    当证书文件采用 PEM 格式时,可以使用 certificate_authorities 选项来替代 truststore.path 设置。该设置接受列表。这两个选项是互斥的,不能同时使用。

  7. 映射 PKI 用户的角色。

    您可以通过角色映射 API 或使用存储在每个节点上的文件来映射 PKI 用户的角色。这两个配置选项会合并在一起。当用户针对 PKI 领域进行身份验证时,该用户的权限是由用户映射到的角色定义的所有权限的并集。

    您可以通过其证书中的专有名称来识别用户。例如,以下映射配置使用角色映射 API 将 John Doe 映射到 user 角色

    resp = client.security.put_role_mapping(
        name="users",
        roles=[
            "user"
        ],
        rules={
            "field": {
                "dn": "cn=John Doe,ou=example,o=com"
            }
        },
        enabled=True,
    )
    print(resp)
    const response = await client.security.putRoleMapping({
      name: "users",
      roles: ["user"],
      rules: {
        field: {
          dn: "cn=John Doe,ou=example,o=com",
        },
      },
      enabled: true,
    });
    console.log(response);
    PUT /_security/role_mapping/users
    {
      "roles" : [ "user" ],
      "rules" : { "field" : {
        "dn" : "cn=John Doe,ou=example,o=com" 
      } },
      "enabled": true
    }

    PKI 用户的专有名称 (DN)。

    或者,使用角色映射文件。例如

    user: 
      - "cn=John Doe,ou=example,o=com" 

    角色的名称。

    PKI 用户的专有名称 (DN)。

    该文件的路径默认为 ES_PATH_CONF/role_mapping.yml。您可以使用 files.role_mapping 领域设置(例如,xpack.security.authc.realms.pki.pki1.files.role_mapping)指定不同的路径(该路径必须在 ES_PATH_CONF 内)。

    PKI 用户的专有名称遵循 X.500 命名约定,该约定将最具体的字段(如 cnuid)放置在名称的开头,而将最一般的字段(如 odc)放置在名称的结尾。某些工具(如 openssl)可能会以不同的格式打印出主题名称。

    您可以确定证书的正确 DN 的一种方法是使用身份验证 API(使用相关的 PKI 证书作为身份验证的方式)并检查结果中的元数据字段。用户的专有名称将填充在 pki_dn 键下。您还可以使用身份验证 API 来验证您的角色映射。

    有关更多信息,请参阅将用户和组映射到角色

    PKI 领域支持授权领域作为角色映射的替代方案。

连接到 Kibana 的客户端的 PKI 身份验证

编辑

默认情况下,PKI 领域依赖于节点的网络接口来执行 SSL/TLS 握手并提取客户端证书。此行为要求客户端直接连接到 Elasticsearch,以便其 SSL 连接由 Elasticsearch 节点终止。如果 SSL/TLS 身份验证要由 Kibana 执行,则必须将 PKI 领域配置为允许委派。

具体而言,当提供 X.509 证书的客户端连接到 Kibana 时,Kibana 执行 SSL/TLS 身份验证。然后,Kibana 会转发客户端的证书链(通过调用 Elasticsearch API),以便由已配置为进行委派的 PKI 领域进一步验证它们。

要允许特定 Elasticsearch PKI 领域的身份验证委派,请首先按照直接连接到 Elasticsearch 的客户端的 PKI 身份验证部分中详述的通常情况配置该领域。在这种情况下,当您启用 TLS 时,必须加密 HTTP 客户端通信

您还必须显式配置 truststore(或等效地配置 certificate_authorities),即使它与您在网络层上配置的信任配置相同。 xpack.security.authc.token.enableddelegation.enabled 设置也必须为 true。例如

xpack:
  security:
    authc:
      token.enabled: true
      realms:
        pki:
          pki1:
            order: 1
            delegation.enabled: true
            truststore:
              path: "pki1_truststore.jks"

重新启动 Elasticsearch 后,此领域可以验证委派的 PKI 身份验证。然后,您必须配置 Kibana 以允许 PKI 证书身份验证

具有 delegation.enabled 的 PKI 领域对于直接连接到 Elasticsearch 的客户端仍然可以正常工作。直接身份验证的用户和通过委派给 Kibana 的 PKI 身份验证的用户都遵循相同的角色映射规则授权领域配置

但是,如果您使用角色映射 API,则可以区分通过委派进行身份验证的用户和直接进行身份验证的用户。前者在用户的元数据中具有额外的字段 pki_delegated_by_userpki_delegated_by_realm。在身份验证委派给 Kibana 的常见设置中,这些字段的值分别为 kibanareserved。例如,以下角色映射规则将 role_for_pki1_direct 角色分配给所有已通过 pki1 领域直接进行身份验证的用户,他们通过连接到 Elasticsearch 而不是通过 Kibana

resp = client.security.put_role_mapping(
    name="direct_pki_only",
    roles=[
        "role_for_pki1_direct"
    ],
    rules={
        "all": [
            {
                "field": {
                    "realm.name": "pki1"
                }
            },
            {
                "field": {
                    "metadata.pki_delegated_by_user": None
                }
            }
        ]
    },
    enabled=True,
)
print(resp)
const response = await client.security.putRoleMapping({
  name: "direct_pki_only",
  roles: ["role_for_pki1_direct"],
  rules: {
    all: [
      {
        field: {
          "realm.name": "pki1",
        },
      },
      {
        field: {
          "metadata.pki_delegated_by_user": null,
        },
      },
    ],
  },
  enabled: true,
});
console.log(response);
PUT /_security/role_mapping/direct_pki_only
{
  "roles" : [ "role_for_pki1_direct" ],
  "rules" : {
    "all": [
      {
        "field": {"realm.name": "pki1"}
      },
      {
        "field": {
          "metadata.pki_delegated_by_user": null 
        }
      }
    ]
  },
  "enabled": true
}

如果设置了此元数据字段(也就是说,它不是 null),则表示用户已在委派方案中进行身份验证。