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)上启用客户端认证,并将用户证书“主体”字段中的可分辨名称 (DN) 映射到角色。您可以在角色映射文件中创建映射,或使用角色映射 API。

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

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

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

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

    当您在 elasticsearch.yml 中配置领域时,只有您指定的领域将用于身份验证。如果您还想使用 nativefile 领域,则必须将它们包含在领域链中。

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

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

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

    如果正则表达式过于严格且与客户端证书的“主体”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 时,必须 加密 Elasticsearch 的 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 后,此 Realm 可以验证委托的 PKI 身份验证。然后,您必须配置 Kibana 以允许 PKI 证书身份验证

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

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

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),则用户已在委托方案中进行了身份验证。