# Dec 17th, 2022: \[CN\] Elasticsearch：LDAP 用户鉴权

**URL:** <https://discuss.elastic.co/t/dec-17th-2022-cn-elasticsearch-ldap/320351>\
**Category:** Advent Calendar\
**Created:** [December 17, 2022, 8:01am UTC](https://discuss.elastic.co/t/dec-17th-2022-cn-elasticsearch-ldap/320351 "2022-12-17T08:01:00Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![xiaoguo.liu](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/xiaoguo.liu/32/79875_2.png) [@xiaoguo.liu](https://discuss.elastic.co/u/xiaoguo.liu)\
**Post date:** [December 17, 2022, 8:01am UTC](https://discuss.elastic.co/t/dec-17th-2022-cn-elasticsearch-ldap/320351/1 "2022-12-17T08:01:00Z")

</div>

使用凭证访问 Elasticsearch 集群。 凭证可以是存储在 Elasticsearch 内部的标准用户/密码，也可以使用更复杂的解决方案，例如 Active Directory 和轻量级目录访问协议 (LDAP)。

你可以将 Elastic Stack 安全功能配置为与轻量级目录访问协议（LDAP） 服务器通信以对用户进行身份验证。LDAP 分层存储用户和组，类似于在文件系统中对文件夹进行分组的方式。 LDAP 目录的层次结构由组织单元 ( organization unit, ou)、组织 ( organization, o) 和域组件 ( domain component, dc) 等容器构建而成。

条目的路径是唯一标识用户或组的专有名称 (distiguished name, DN)。 用户名和组名通常具有通用名称 (common name, cn) 或唯一 ID ( unique ID, uid) 等属性。 DN 指定为字符串，例如 “cn=admin,dc=example,dc=com”（忽略空格）。

ldap 领域支持两种操作模式，一种是用户搜索模式，另一种是为用户 DN 提供特定模板的模式。

# LDAP 简介

LDAP 全称为 Lightweight Directory Access Protocol, 轻量目录访问协议。简单地说， LDAP 就是用来访问目录数据库的一个协议。目录服务数据也是一种数据库，这种数据库相对于我们熟知的关系型数据库，比如 MySQL, Oracle，只有一下的几个方面的特点：

它成树状结构组织数据，类似文件目录一样  
它是为查询，浏览和搜索而优化的数据库，也就是说 LDAP 的可读性特别强，但是写性能差，而且不支持事务处理，回滚等负责功能  
举个例子：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/0/d/0d5c334a10683848c72717cb7c6f0c88e6d2d0a1.png)

1） **目标树** ：如上图所示，在一个目录服务器中，整个目录信息集可以表述为一个目录信息树，树中的每个节点是一个条目。

2） **条目** ：每个条目就是一条记录，每个条目有自己唯一可区别的名称（DN）。比如图中的每个圆圈都是一条记录。

3） **DN** ， **RDN** ：比如上图中的第一个叶子条目，它有一个唯一可区分的名称 DN：uid=bob,ou=people,dc=acme,dc=org。类似于文件目录的相对路径绝对路径。它除了 DN 之外，它还具有 RDN。RDN 与目录结构无关，比如之前提过的 uid=bob,ou=people,dc=acme,dc=org，他的 RDN 就是 uid=bob.

4） **属性** ：描述条目具体信息。比如 ’uid=bill,ou=people,dc=acme,dc=org‘，它有属性 name 为 bill，属性 age 为11，属性 school 为 xx：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/4/1/41f0bc62a5dbde1295272735511d71fa27703fd4.png)

在接下来的练习中，我将使用最新的 Elastic Stack 8.3.3 来进行展示。我将使用的系统架构如下：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/b/a/ba438a7880a2667ff0ef04668213dfdff238a9eb.png)

在上面，我使用两个机器。它们分别安装 Elastic Stack 及 Apache Directory。它们的 IP 地址如上所示。

# 安装

## Elastic Stack

我们必须安装好 Elasticsearch 及 Kibana。我们可以参考之前的文章：

- [如何在 Linux，macOS 及 Windows 上进行安装 Elasticsearch](https://elasticstack.blog.csdn.net/article/details/99413578)

- [Kibana：如何在 Linux，MacOS 及 Windows 上安装 Elastic 栈中的 Kibana](https://elasticstack.blog.csdn.net/article/details/99433732)

根据 Elastic 的[订阅 | Elastic Stack 产品和支持 | Elastic](https://www.elastic.co/cn/subscriptions)，我们知道 LDAP 是一个需要购买的功能：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/3/8/38030b2374790b03dfd93cf62ea8208e6c8b83d5.png)

在安装好 Elasticsearch 及 Kibana 之后，我们需要启动白金版试用功能：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/d/d/dd98a603253d96e2ab676db168c6089c46143643.png)

_emphasized text_## Apache Directory  
Apache Directory Studio 是一个完整的目录工具平台，旨在与任何 LDAP 服务器一起使用，但它是专门为与 ApacheDS 一起使用而设计的。 它是一个 Eclipse RCP 应用程序，由多个 Eclipse (OSGi) 插件组成，可以通过其他插件轻松升级。 这些插件甚至可以在 Eclipse 本身中运行。我们可以到地址 [Downloads — Apache Directory](https://directory.apache.org/studio/downloads.html) 根据自己的平台来进行下载并进行安装：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/1/9/19f4208b22afc06f7c8d39f077eab4cbff851090.png)

我们接下来需要使用 ApacheDS 来创建如下的一些用户及组。 我们在 dc=example,dc=com 下创建如下的 **ou** ：

- groups：这是一个 group，它含有cn=user1 及 cn=user2 条目。如果你想了解如何创建一个 group，请参考文档 “[Preparing the LDAP environment](https://www.ibm.com/docs/en/odm/8.9.2?topic=registries-task-preparing-ldap-environment)”。  

- users：这是一个 ou。它含有一些用户的信息。如果你想了解如何创建一个用户，请阅读文章 “[Preparing the LDAP environment](https://www.ibm.com/docs/en/odm/8.9.2?topic=registries-task-preparing-ldap-environment)”。  

- usrs：这是一个 ou。它被 groups 组所使用：  

对于上面的每个条目，我们都为其设置 uid 及密码。

为了验证一个 DN 及用户的正确性，我们可以使用如下的命令来进行检验：

```auto
ldapsearch -x -D "cn=liuxg,ou=users,dc=example,dc=com"\
       -W -H ldap://ubuntu:10389 -b "dc=example,doc=com"\
       -s sub '(sAMAccountName=liuxg)'

```

```auto
$ ldapsearch -x -D "cn=liuxg,ou=users,dc=example,dc=com"\
> -W -H ldap://ubuntu:10389 -b "dc=example,doc=com"\
> -s sub '(sAMAccountName=liuxg)'
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <dc=example,doc=com> with scope subtree
# filter: (sAMAccountName=liuxg)
# requesting: ALL
#
 
# search result
search: 2
result: 32 No such object
text: NO_SUCH_OBJECT: failed for MessageType : SEARCH_REQUEST
Message ID : 2
 
     SearchRequest
        baseDn : 'dc=example,doc=com'
        filter : '(|
 (sAMAccountName=liuxg)(objectClass=referral))'
        scope : whole subtree
 
        typesOnly : false
        Size Limit : no limit
        Time Limit 
 : no limit
        Deref Aliases : never Deref Aliases
        attributes : 
 
org.apache.directory.api.ldap.model.message.SearchRequestImpl@430edd43: ERR
 _268 Cannot find a partition for dc=example,doc=com
 
# numResponses: 1

```

在上面，我们输入 liuxg 的密码即可。

这样，我们的 Apache Directory 配置就完成了。

# 使用用户搜索配置 ldap 领域

ldap 领域支持两种操作模式，一种是用户搜索模式，另一种是为用户 DN 提供特定模板的模式。LDAP 用户搜索是最常见的操作模式。 在这种模式下，具有搜索 LDAP 目录权限的特定用户用于根据提供的用户名和 LDAP 属性搜索身份验证用户的 DN。 找到后，通过尝试使用找到的 DN 和提供的密码绑定到 LDAP 服务器来对用户进行身份验证。

我们首先打开 Elasticsearch 的配置文件 config/elasticsearch.yml 文件：

**config/elasticsearch.yml**

```auto
xpack:
  security:
    authc:
      realms:
        ldap:
          ldap1:
            order: 0
            url: "ldap://ubuntu:10389"
            bind_dn: "ou=users,dc=example,dc=com"
            bind_password: "123456"
            user_search:
              base_dn: "dc=example,dc=com"
              filter: "(cn={0})"
            group_search:
              base_dn: "ou=groups,dc=example,dc=com"
            files:
              role_mapping: "/Users/liuxg/elastic/elasticsearch-8.3.3/config/role_mapping.yml"
            unmapped_groups_as_roles: false

```

我们在文件的最后面添加如上所示的代码。其中 url 需要根据自己的实际安装来进行配置。在上面，我们配置时，设置的密码是 123456（这个在 ApacheDS 里进行设定）。可能很多人觉得在上面配置明文的密码在 elasticsearch.yml 中不是一个好主意。我们可以使用如下的命令把 _bind\_dn_ 的密码添加到 Elasticsearch keystore 里：

```auto
bin/elasticsearch-keystore add xpack.security.authc.realms.ldap.ldap1.secure_bind_password

```

一旦我们这样配置后，那么我就无需在 elasticsearch.yml 中配置。我们直接把 _bind\_dn_ 这一行去掉即可。

我们需要根据自己的 Elasticsearch 的安装路径修改上面的 role\_mapping 的配置。

**role\_mapping.yml**

```auto
# Role mapping configuration file which has elasticsearch roles as keys
# that map to one or more user or group distinguished names
 
#roleA: this is an elasticsearch role
# - groupA-DN this is a group distinguished name
# - groupB-DN
# - user1-DN this is the full user distinguished name
 
superuser:
  - "cn=liuxg,ou=users,dc=example,dc=com"
  - "cn=xgliu,ou=users,dc=example,dc=com"
  - "employeeNumber=1,ou=users,dc=example,dc=com"

```

如上所示，superuser 是在我们的 Elasticsearch 中已经定义好的 role。这个 role 可以是预置的。也可以是我们自己定义的。如果你还不知道如何定义 role，请阅读我之前的文章 “Elasticsearch：用户安全设置”。在这里，为了方便，我们选择了 superuser。 这个是一个预置的 role。在上面，我们配置：

```auto
  - "cn=liuxg,ou=users,dc=example,dc=com"
  - "cn=xgliu,ou=users,dc=example,dc=com"
  - "employeeNumber=1,ou=users,dc=example,dc=com"

```

这些 DN 所代表的用户为 superuser 用户。

我们接下来重新启动 Elasticsearch，并在 Kibana 的界面中进行登录：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/7/1/71d17f6b72cca6c27b065b76f933fbc7cc0b2b28.png)

很显然，我们可以使用 liuxg:123456 来成功地进行登录。 我们也可以使用如下的命令来进行检查：

```auto
curl -k -u xgliu:123456 https://localhost:9200

```

```auto
$ curl -k -u xgliu:123456 https://localhost:9200
{
  "name" : "liuxgm.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "zWDMrYU2RJm9RugZCZGhsQ",
  "version" : {
    "number" : "8.3.3",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "801fed82df74dbe537f89b71b098ccaff88d2c56",
    "build_date" : "2022-07-23T19:30:09.227964828Z",
    "build_snapshot" : false,
    "lucene_version" : "9.2.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

```

很显然，xgliu 账号也可以成功地访问 Elasticsearch。

接下来，我们展示如何把 groups 里的账号也进行 mapping，从而使得它们也具有 superuser 的 role。当然，我们也可以让它们映射到任何我们想要的 role。但是前提是这些 role，必须是预置的，或者是自己创建的。

我们有两种方法来进行展示。

# 通过 Kibana 界面

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/f/5/f532b1c851a6de3f3fed09e2f12cddcb2481a098.png)

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/4/d/4df548b7ceafb7d6b81af8b6886c0804922e356d.png)

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/4/7/470f24a6e10525aeaef9f9d59c363ac88541d7cf.png)

在上面，我们在 value 里填入如下的值：

`cn=user*,ou=groups,dc=example,dc=com`

在上面，我们使用了 wildcard 来匹配 user1 及 user2。我们可以在上面的 groups 里的截图可以看到。点击上面的 **Save role mapping** ：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/8/8/889b605558a03011294a1eb44fe60de77d774563.png)

我们可以在 console 里打入如下的命令：

`GET /_security/role_mapping/`

上面的命令返回结果：

```auto
{
  "users": {
    "enabled": true,
    "roles": [
      "superuser"
    ],
    "rules": {
      "all": [
        {
          "field": {
            "groups": "cn=user*,ou=groups,dc=example,dc=com"
          }
        }
      ]
    },
    "metadata": {}
  }
}

```

它说明，所有 DN 匹配 cn=user\*,ou=groups,dc=example,dc=com 的用户都将具有 superuser 这个role。我们接下来使用 jim:123456 来进行登录：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/b/6/b69022522afd3b36bebbab9aabd381dc76f0fdf5.png)

显然我们的登录是成功的。当然这个组里的另外一个用户 sue:123456 也可以成功登录。

为了展示下面的 API 的使用，我们先删除刚才创建的 users role mapping：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/a/a/aa7dd5681f52de41fdce53da4867bdd29bddfefd.png)

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/b/8/b8b9c435da92c8db253cc43154d1f5011ad82533.png)

这样我们没有任何的 role mapping，当然 jim 及 sue 都不可以进行登录了。如果我们使用 jim 的账号登录，我们可以看到如下的画面：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/a/4/a4dfba433ef1e4dae9503a4c41e76baed15c29e9.png)

# 使用 API

我们使用如下的 API 来实现 role mapping：

```auto
PUT /_security/role_mapping/admins
{
  "roles" : ["superuser"],
  "rules" : { "field" : {
    "groups" : "cn=user*,ou=groups,dc=example,dc=com" 
  } },
  "enabled": true
}

```

我们可使用如下的命令来进行查看：

`GET /_security/role_mapping/`

上面的命令生成：

```auto
{
  "admins": {
    "enabled": true,
    "roles": [
      "superuser"
    ],
    "rules": {
      "field": {
        "groups": "cn=user*,ou=groups,dc=example,dc=com"
      }
    },
    "metadata": {}
  }
}

```

很显然，它生成了一个叫做 admins 的 role mapping。我们可以回到之前的 role mapping 界面：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/b/1/b1d2c1730d6ab155523695b62ed20faf7741fd92.png)

很显然，有一个新的 admins 的 role mapping 已经生成了。

我们接下来再次使用 jim:123456 来进行登录：

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/1/2/12f2b96d91d640fe2e6b79b47e21a00e5541799d.png)

很显然，我们又可以成功地登录了。

参考：

【1】[https://www.jianshu.com/p/4b3c89ce6ac3](https://www.jianshu.com/p/4b3c89ce6ac3)

【2】[LDAP user authentication | Elasticsearch Guide [8.3] | Elastic](https://www.elastic.co/guide/en/elasticsearch/reference/8.3/ldap-realm.html#ldap-realm-configuration)

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [January 14, 2023, 8:01am UTC](https://discuss.elastic.co/t/dec-17th-2022-cn-elasticsearch-ldap/320351/2 "2023-01-14T08:01:22Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
