Link Search Menu Expand Document Documentation Menu

Active Directory 和 LDAP

Active Directory 和 LDAP 既可用于认证(配置的 authc 节),也可用于授权(authz 节)。认证检查用户是否输入了有效的凭证。授权则检索用户的任何后端角色。

在大多数情况下,您会希望同时配置认证和授权。您也可以仅使用认证,并将从 LDAP 检索到的用户直接映射到安全插件角色。

Docker 示例

我们提供了一个功能齐全的示例,可以帮助您了解如何使用 LDAP 服务器进行认证和授权。

  1. 下载并解压示例 zip 文件
  2. admin 用户更新 .env 文件,设置一个强密码。
  3. 在命令行中,运行 docker compose up
  4. 查看文件

    • docker-compose.yml 定义了一个 OpenSearch 单节点、一个 LDAP 服务器以及一个用于 LDAP 服务器的 PHP 管理工具。

      您可以通过 https://:6443 访问管理工具。确认安全警告并使用 cn=admin,dc=example,dc=orgchangethis 登录。

    • directory.ldif 使用三个用户和两个组来初始化 LDAP 服务器。

      psantos 属于 AdministratorDevelopers 组。jroejdoe 属于 Developers 组。安全插件将这些组加载为后端角色。

    • roles_mapping.ymlAdministratorDevelopers LDAP 组(作为后端角色)映射到安全角色,以便用户在认证后获得相应的权限。

    • internal_users.yml 删除所有默认用户,除了 administratorkibanaserver

    • config.yml 包含所有必要的 LDAP 设置。

  5. psantos 身份索引文档

    curl -XPUT 'https://:9200/new-index/_doc/1' -H 'Content-Type: application/json' -d '{"title": "Spirited Away"}' -u 'psantos:password' -k
    

    如果您以 jroe 身份尝试相同的请求,它将失败。Developers 组映射到 readallmanage_snapshotskibana_user 角色,并且没有写入权限。

  6. jroe 身份搜索文档

    curl -XGET 'https://:9200/new-index/_search?pretty' -u 'jroe:password' -k
    

    此请求成功,因为 Developers 组映射到 readall 角色。

  7. 如果您想检查各个容器的内容,运行 docker ps 找到容器 ID,然后运行 docker exec -it <container-id> /bin/bash

连接设置

要启用 LDAP 认证和授权,请将以下行添加到 config/opensearch-security/config.yml

内部用户数据库认证也应启用,因为 OpenSearch Dashboards 使用 kibanaserver 内部用户连接到 OpenSearch。

authc:
  internal_auth:
    order: 0
    description: "HTTP basic authentication using the internal user database"
    http_enabled: true
    transport_enabled: true
    http_authenticator:
      type: basic
      challenge: false
    authentication_backend:
      type: internal
  ldap:
    http_enabled: true
    transport_enabled: true
    order: 1
    http_authenticator:
      type: basic
      challenge: false
    authentication_backend:
      type: ldap
      config:
        ...
authz:
  ldap:
    http_enabled: true
    transport_enabled: true
    authorization_backend:
      type: ldap
      config:
      ...

认证和授权的连接设置相同,并添加到 config 节中。

主机名和端口

要配置您的 Active Directory 服务器的主机名和端口,请使用以下设置:

config:
  hosts:
    - primary.ldap.example.com:389
    - secondary.ldap.example.com:389

您可以在此处配置多个服务器。如果安全插件无法连接到第一个服务器,它将尝试按顺序连接到其余服务器。

超时

要配置到您的 Active Directory 服务器的连接和响应超时(值以毫秒为单位),请使用以下设置:

config:
  connect_timeout: 5000
  response_timeout: 0

如果您的服务器支持双因素认证 (2FA),默认的超时设置可能会导致登录错误。您可以增加 connect_timeout 以适应 2FA 过程。将 response_timeout 设置为 0(默认值)表示无限期等待。

绑定 DN 和密码

要配置安全插件在向您的服务器发出查询时使用的 bind_dnpassword,请使用以下设置:

config:
  bind_dn: cn=admin,dc=example,dc=com
  password: password

如果您的服务器支持匿名认证,bind_dnpassword 都可以设置为 null

TLS 设置

使用以下参数配置连接到服务器的 TLS:

config:
  enable_ssl: <true|false>
  enable_start_tls: <true|false>
  enable_ssl_client_auth: <true|false>
  verify_hostnames: <true|false>
名称 描述
enable_ssl 是否使用基于 SSL 的 LDAP (LDAPS)。
enable_start_tls 是否使用 STARTTLS。不能与 LDAPS 结合使用。
enable_ssl_client_auth 是否将客户端证书发送到 LDAP 服务器。
verify_hostnames 是否验证服务器 TLS 证书的主机名。

证书验证

默认情况下,安全插件会根据 opensearch.yml 中配置的根 CA(作为 PEM 证书或信任库)来验证 LDAP 服务器的 TLS 证书。

plugins.security.ssl.transport.pemtrustedcas_filepath: ...
plugins.security.ssl.transport.truststore_filepath: ...

如果您的服务器使用由不同 CA 签名的证书,请将此 CA 导入您的信任库,或将其添加到每个节点的受信任 CA 文件中。

您也可以使用单独的 PEM 格式的根 CA。

为 LDAP 配置单独的根 CA 时,请确保在所有 LDAP config: 设置实例中包含该设置,包括配置的 authcauthz 选项。

要配置单独的根 CA,请使用以下配置选项之一:

config:
  pemtrustedcas_filepath: /full/path/to/trusted_cas.pem
config:
  pemtrustedcas_content: |-
    -----BEGIN CERTIFICATE-----
    MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQUFADCBjzETMBEGCgmSJomT8ixk
    ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
    bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
    ...
    -----END CERTIFICATE-----
名称 描述
pemtrustedcas_filepath 包含您的 Active Directory/LDAP 服务器根 CA 的 PEM 文件的绝对路径。
pemtrustedcas_content 您的 Active Directory/LDAP 服务器的根 CA 内容。当设置了 pemtrustedcas_filepath 时,不能使用此项。

客户端认证

如果您使用 TLS 客户端认证,安全插件会发送节点在 opensearch.yml 中配置的 PEM 证书。设置以下配置选项之一:

config:
  pemkey_filepath: /full/path/to/private.key.pem
  pemkey_password: private_key_password
  pemcert_filepath: /full/path/to/certificate.pem

config:
  pemkey_content: |-
    -----BEGIN PRIVATE KEY-----
    MIID2jCCAsKgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBlTETMBEGCgmSJomT8ixk
    ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
    bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
    ...
    -----END PRIVATE KEY-----
  pemkey_password: private_key_password
  pemcert_content: |-
    -----BEGIN CERTIFICATE-----
    MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHRZwzwGlP2FvL
    oEzNeDu2XnOF+ram7rWPT6fxI+JJr3SDz1mSzixTeHq82P5A7RLdMULfQFMfQPfr
    WXgB4qfisuDSt+CPocZRfUqqhGlMG2l8LgJMr58tn0AHvauvNTeiGlyXy0ShxHbD
    ...
    -----END CERTIFICATE-----
名称 描述
pemkey_filepath 包含您的证书私钥的文件的绝对路径。
pemkey_content 您的证书私钥的内容。当设置了 pemkey_filepath 时,不能使用此项。
pemkey_password 私钥的密码(如果有)。
pemcert_filepath 客户端证书的绝对路径。
pemcert_content 客户端证书的内容。当设置了 pemcert_filepath 时不能使用。

启用的密码套件和协议

您可以限制 LDAP 连接允许的密码套件和 TLS 协议。例如,您可以只允许强密码套件并将 TLS 版本限制为最新版本:

ldap:
  http_enabled: true
  transport_enabled: true
  ...
  authentication_backend:
    type: ldap
    config:
      enabled_ssl_ciphers:
        - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
        - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"
      enabled_ssl_protocols:
        - "TLSv1.1"
        - "TLSv1.2"
名称 描述
enabled_ssl_ciphers 数组,启用的 TLS 密码套件。仅支持 Java 格式。
enabled_ssl_protocols 数组,启用的 TLS 协议。仅支持 Java 格式。

使用 Active Directory 和 LDAP 进行认证

要使用 Active Directory/LDAP 进行认证,首先在 config/opensearch-security/config.ymlauthc 节中配置相应的认证域:

authc:
  ldap:
    http_enabled: true
    transport_enabled: true
    order: 1
    http_authenticator:
      type: basic
      challenge: true
    authentication_backend:
      type: ldap
      config:
        ...

接下来,将 Active Directory/LDAP 服务器的连接设置添加到认证域的配置节中。

config:
  enable_ssl: true
  enable_start_tls: false
  enable_ssl_client_auth: false
  verify_hostnames: true
  hosts:
    - ldap.example.com:8389
  bind_dn: cn=admin,dc=example,dc=com
  password: passw0rd

认证的工作方式是,针对 LDAP 树的用户子树发出包含用户名的 LDAP 查询。

安全插件首先获取配置的 LDAP 查询,并将占位符 {0} 替换为用户凭证中的用户名。

usersearch: '(sAMAccountName={0})'

然后,它针对用户子树发出此查询。目前,将搜索配置的 userbase 下的整个子树。

userbase: 'ou=people,dc=example,dc=com'

如果查询成功,安全插件将从 LDAP 条目中检索用户名。您可以指定安全插件应使用 LDAP 条目中的哪个属性作为用户名。

username_attribute: uid

如果此键未设置或为 null,则使用 LDAP 条目的专有名称 (DN)。

配置摘要

名称 描述
userbase 指定目录中存储用户信息子树的位置。
usersearch 安全插件在尝试认证用户时执行的实际 LDAP 查询。变量 {0} 将被替换为用户名。
username_attribute 安全插件使用目录条目的此属性查找用户名。如果设置为 null,则使用 DN(默认)。

完整认证示例

ldap:
  http_enabled: true
  transport_enabled: true
  order: 1
  http_authenticator:
    type: basic
    challenge: true
  authentication_backend:
    type: ldap
    config:
      enable_ssl: true
      enable_start_tls: false
      enable_ssl_client_auth: false
      verify_hostnames: true
      hosts:
        - ldap.example.com:636
      bind_dn: cn=admin,dc=example,dc=com
      password: password
      userbase: 'ou=people,dc=example,dc=com'
      usersearch: '(sAMAccountName={0})'
      username_attribute: uid

使用 Active Directory 和 LDAP 进行授权

要使用 Active Directory/LDAP 进行授权,首先在 config.ymlauthz 节中配置相应的授权域:

authz:
  ldap:
    http_enabled: true
    transport_enabled: true
    authorization_backend:
      type: ldap
      config:
      ...

授权是从 LDAP 服务器为认证用户检索后端角色的过程。这通常与您用于认证的服务器相同,但您也可以使用不同的服务器。唯一的要求是您用于获取角色的用户确实存在于 LDAP 服务器上。

因为安全插件始终检查 LDAP 服务器中是否存在用户,所以您还必须在 authz 节中配置 userbaseusersearchusername_attribute

授权的工作方式与认证类似。安全插件针对 LDAP 树的角色子树发出包含用户名的 LDAP 查询。

作为替代,安全插件还可以获取在用户子树中定义为用户条目直接属性的角色。

方法 1:查询角色子树

安全插件首先获取用于获取角色的 LDAP 查询(“rolesearch”),并替换查询中找到的任何变量。例如,对于标准的 Active Directory 安装,您将使用以下角色搜索:

rolesearch: '(member={0})'

您可以使用以下变量:

  • {0} 被替换为用户的 DN。
  • {1} 被替换为用户名,由 username_attribute 设置定义。
  • {2} 被替换为认证用户目录条目中的任意属性值。

变量 {2} 指的是用户目录条目中的一个属性。您应该使用的属性由 userroleattribute 设置指定。

userroleattribute: myattribute

然后,安全插件针对配置的角色子树发出替换后的查询。rolebase 下的整个子树都会被搜索。

rolebase: 'ou=groups,dc=example,dc=com'

如果您使用嵌套角色(其他角色的成员角色),您可以配置安全插件来解析它们。

resolve_nested_roles: false

获取所有角色后,安全插件从角色条目的可配置属性中提取最终的角色名称。

rolename: cn

如果未设置此项,则使用角色条目的 DN。您现在可以使用此角色名称将其映射到一个或多个安全插件角色,如 roles_mapping.yml 中所定义。

方法 2:使用用户属性作为角色名称

如果您将角色存储为用户子树中用户条目的直接属性,则只需配置属性名称。

userrolename: roles

您可以配置多个属性名称。

userrolename: roles, otherroles

此方法可以与查询角色子树结合使用。安全插件从用户的角色属性中获取角色,然后执行角色搜索。

如果您不使用或没有角色子树,可以完全禁用角色搜索。

rolesearch_enabled: false

(高级)控制 LDAP 用户属性

默认情况下,安全插件读取所有 LDAP 用户属性,并将其用于索引名称变量替换和 DLS 查询变量替换。如果您的 LDAP 条目有很多属性,您可能希望控制哪些属性可用。属性越少,性能越好。

请注意,此设置在 config.yml 文件的认证 authc 节中进行。

名称 描述
custom_attr_allowlist 字符串数组。指定应可用于变量替换的 LDAP 属性。
custom_attr_maxval_len 整数。指定每个属性的最大允许长度。所有超过此长度的属性都将被丢弃。值为 0 会完全禁用自定义属性。默认值为 36。

示例

authc:
  ldap:
    http_enabled: true
    transport_enabled: true
    authentication_backend:
      type: ldap
      config:
        custom_attr_allowlist:
          - attribute1
          - attribute2
        custom_attr_maxval_len: 36
      ...

(高级)从角色查找中排除特定用户

如果您使用多种认证方法,从 LDAP 角色查找中排除某些用户可能是有意义的。

考虑一个典型的 OpenSearch Dashboards 设置的以下场景:所有 OpenSearch Dashboards 用户都存储在 LDAP/Active Directory 服务器中。

但是,您还有一个 OpenSearch Dashboards 服务器用户。OpenSearch Dashboards 使用此用户管理存储的对象并执行监控和维护任务。您不希望将此用户添加到您的 Active Directory 安装中,而是将其存储在安全插件的内部用户数据库中。

在这种情况下,将 OpenSearch Dashboards 服务器用户从 LDAP 授权中排除是合理的,因为我们已经知道没有相应的条目。您可以使用 skip_users 配置设置来定义应跳过哪些用户。支持通配符和正则表达式。

skip_users:
  - kibanaserver
  - 'cn=Jane Doe,ou*people,o=TEST'
  - '/\S*/'

(高级)从嵌套角色查找中排除角色

如果您的 LDAP 安装中的用户拥有大量角色,并且您需要解析嵌套角色,则可能会遇到性能问题。

然而,在大多数情况下,并非所有用户角色都与 OpenSearch 和 OpenSearch Dashboards 相关。您可能只需要少数几个角色。在这种情况下,您可以使用嵌套角色过滤功能来定义一个角色列表,这些角色将从用户角色列表中过滤掉。支持通配符和正则表达式。

这仅在 resolve_nested_rolestrue 时才有效。

nested_role_filter:
  - 'cn=Jane Doe,ou*people,o=TEST'
  - ...

配置摘要

名称 描述
rolebase 指定目录中存储角色/组信息的子树位置。
rolesearch 安全插件在尝试确定用户角色时执行的实际 LDAP 查询。您可以在此处使用三个变量(见下文)。
userroleattribute 用户条目中用于 {2} 变量替换的属性。
userrolename 如果用户的角色/组未存储在组子树中,而是作为用户目录条目的属性存储,请在此处定义此属性名称。
rolename 应作为角色名称使用的角色条目的属性。
resolve_nested_roles 布尔值。是否解析嵌套角色。默认值为 false
max_nested_depth 整数。当 resolve_nested_rolestrue 时,此项定义要遍历的最大嵌套角色数。设置较小的值可以减少从 LDAP 检索的数据量并缩短认证时间,但代价是可能无法发现深度嵌套的角色。默认值为 30
skip_users 检索角色时应跳过的用户数组。支持通配符和正则表达式。
exclude_roles 检索角色时应排除的角色数组。支持通配符。
nested_role_filter 在解析嵌套角色之前应过滤的角色 DN 数组。支持通配符和正则表达式。
rolesearch_enabled 布尔值。启用或禁用角色搜索。默认值为 true
custom_attr_allowlist 字符串数组。指定应可用于变量替换的 LDAP 属性。
custom_attr_maxval_len 整数。指定每个属性的最大允许长度。所有超过此长度的属性都将被丢弃。值为 0 会完全禁用自定义属性。默认值为 36。
custom_return_attributes 字符串数组。指定要从 LDAP 服务器请求的属性。

完整授权示例

authz:
  ldap:
    http_enabled: true
    transport_enabled: true
    authorization_backend:
      type: ldap
      config:
        enable_ssl: true
        enable_start_tls: false
        enable_ssl_client_auth: false
        verify_hostnames: true
        hosts:
          - ldap.example.com:636
        bind_dn: cn=admin,dc=example,dc=com
        password: password
        userbase: 'ou=people,dc=example,dc=com'
        usersearch: '(uid={0})'
        username_attribute: uid
        rolebase: 'ou=groups,dc=example,dc=com'
        rolesearch: '(member={0})'
        userroleattribute: null
        userrolename: none
        rolename: cn
        resolve_nested_roles: true
        skip_users:
          - kibanaserver
          - 'cn=Jane Doe,ou*people,o=TEST'
          - '/\S*/'

(高级)配置多个用户和角色基础

在 authc 和/或 authz 部分配置多个用户库时,请使用以下语法

        ...
        bind_dn: cn=admin,dc=example,dc=com
        password: password
        users:
          primary-userbase:
             base: 'ou=people,dc=example,dc=com'
             search: '(uid={0})'
          secondary-userbase:
             base: 'cn=users,dc=example,dc=com'
             search: '(uid={0})'
        username_attribute: uid
        ...

类似地,在 authz 部分配置多个角色库时,请使用以下设置

        ...
        username_attribute: uid
        roles:
          primary-rolebase:
            base: 'ou=groups,dc=example,dc=com'
            search: '(uniqueMember={0})'
          secondary-rolebase:
            base: 'ou=othergroups,dc=example,dc=com'
            search: '(member={0})'
        userroleattribute: null
        ...

包含多个用户和角色库的完整身份验证和授权示例

authc:
  ...
  ldap:
    http_enabled: true
    transport_enabled: true
    order: 1
    http_authenticator:
      type: basic
      challenge: true
    authentication_backend:
      type: ldap
      config:
        enable_ssl: true
        enable_start_tls: false
        enable_ssl_client_auth: false
        verify_hostnames: true
        hosts:
          - ldap.example.com:636
        bind_dn: cn=admin,dc=example,dc=com
        password: password
        users:
          primary-userbase:
             base: 'ou=people,dc=example,dc=com'
             search: '(uid={0})'
          secondary-userbase:
             base: 'cn=users,dc=example,dc=com'
             search: '(uid={0})'
        username_attribute: uid
authz:
  ldap:
    http_enabled: true
    transport_enabled: true
    authorization_backend:
      type: ldap
      config:
        enable_ssl: true
        enable_start_tls: false
        enable_ssl_client_auth: false
        verify_hostnames: true
        hosts:
          - ldap.example.com:636
        bind_dn: cn=admin,dc=example,dc=com
        password: password
        users:
          primary-userbase:
             base: 'ou=people,dc=example,dc=com'
             search: '(uid={0})'
          secondary-userbase:
             base: 'cn=users,dc=example,dc=com'
             search: '(uid={0})'
        username_attribute: uid
        roles:
          primary-rolebase:
            base: 'ou=groups,dc=example,dc=com'
            search: '(uniqueMember={0})'
          secondary-rolebase:
            base: 'ou=othergroups,dc=example,dc=com'
            search: '(member={0})'
        userroleattribute: null
        userrolename: none
        rolename: cn
        resolve_nested_roles: true