安装使用
参考:
- http://ldapdoc.eryajf.net/pages/f081dc/
- https://github.com/behappy-project/behappy-docker-application/tree/master/ldap
LDAP 概念
LDAP 是轻量目录访问协议,英文全称是 Lightweight Directory Access Protocol,一般都简称为 LDAP。它是基于 X.500 标准的,但是简单多了并且可以根据需要定制。与 X.500 不同,LDAP 支持 TCP/IP,这对访问 Internet 是必须的。LDAP 的核心规范在 RFC 中都有定义,所有与 LDAP 相关的 RFC 都可以在 LDAPman RFC 网页中找到。简单说来,LDAP 是一个得到关于人或者资源的集中、静态数据的快速方式。LDAP 是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用,不过根据组织者的需要,它可以做得更加强大。
现在市场上有关 LDAP 的产品已有很多,各大软件公司都在他们的产品中集成了 LDAP 服务,如 Microsoft 的 ActiveDirectory、Lotus 的 Domino Directory、IBM 的 WebSphere 中也集成了 LDAP 服务。LDAP 的开源实现是 OpenLDAP,它比商业产品一点也不差,而且源码开放。
OpenLDAP 是最常用的目录服务之一,它是一个由开源社区及志愿者开发和管理的一个开源项目,提供了目录服务的所有功能,包括目录搜索、身份认证、安全通道、过滤器等等。大多数的 Linux 发行版里面都带有 OpenLDAP 的安装包。OpenLDAP 服务默认使用非加密的 TCP/IP 协议来接收服务的请求,并将查询结果传回到客户端。由于大多数目录服务都是用于系统的安全认证部分比如:用户登录和身份验证,所以它也支持使用基于 SSL/TLS 的加密协议来保证数据传送的保密性和完整性。OpenLDAP 是使用 OpenSSL 来实现 SSL/TLS 加密通信的。
LDAP 的信息模型是建立在"条目"(entries)的基础上。一个条目是一些属性的集合,并且具有一个全局唯一的"可区分名称"DN,一个条目可以通过 DN 来引用。每一个条目的属性具有一个类型和一个或者多个值。类型通常是容易记忆的名称,比如 cn 是通用名称(common name),或者 mail 是电子邮件地址。条目的值的语法取决于属性类型。比如,cn 属性可能具有一个值 Babs Jensen。一个 mail 属性可能包含 bbs@example.com。一个 jpegphoto 属性可能包含一幅 JPEG(二进制)格式的图片。
LDAP 常用关键字列表
LDAP 通过属性 objectClass 来控制哪一个属性必须出现或允许出现在一个条目中,它的值决定了该条目必须遵守的模式规则。
| 关键字 | 英文全称 | 含义 |
|---|---|---|
| dc | Domain Component | 域名的部分,其格式是将完整的域名分成几部分,如域名为 example.com 变成 dc=example,dc=com |
| uid | User Id | 用户 ID,如 tom |
| ou | Organization Unit | 组织单位,类似于 Linux 文件系统中的子目录,它是一个容器对象,组织单位可以包含其他各种对象(包括其他组织单元),如 market |
| cn | Common Name | 公共名称,如 Thomas Johansson |
| sn | Surname | 姓,如 Johansson |
| dn | Distinguished Name | 惟一辨别名,类似于 Linux 文件系统中的绝对路径,每个对象都有一个惟一的名称,如 uid=tom,ou=market,dc=example,dc=com,在一个目录树中 DN 总是惟一的 |
| rdn | Relative dn | 相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如 uid=tom 或 cn=Thomas Johansson |
| c | Country | 国家,如 CN 或 US 等 |
| o | Organization | 组织名,如 Example, Inc. |
LDAP 支持的目录操作
包括:查询目录、更新目录、增加条目、删除条目、改变条目名称,搜索信息,最常用的 LDAP 操作是搜索信息操作。LDAP 的搜索操作允许搜索目录的一部分,例如查找匹配某个搜索过滤器规则的条目,搜索在 dc=example,dc=com 条目之中或者之下的整个目录子树,查找一个名字叫做 Barbara Jensen 的个人,并且获取每一个找到的条目的电子邮件地址。
LDAP 协议介绍
目录是一组具有类似属性、以一定逻辑和层次组合的信息。常见的例子是通讯簿,由以字母顺序排列的名字、地址和电话号码组成。目录服务是一种在分布式环境中发现目标的方法。目录具有两个主要组成部分:
- 第一部分是数据库,数据库是分布式的,且拥有一个描述数据的规划。
- 第二部分则是访问和处理数据的各种协议。
目录服务其实也是一种数据库系统,只是这种数据库是一种树形结构,而不是通常使用的关系数据库。目录服务与关系数据库之间的主要区别在于:二者都允许对存储数据进行访问,只是目录主要用于读取,其查询的效率很高,而关系数据库则是为读写而设计的。
目录服务不适于进行频繁的更新,属于典型的分布式结构。
LDAP 是一个目录服务协议,目前存在众多版本的 LDAP,而最常见的则是 V2 和 V3 两个版本,它们分别于 1995 年和 1997 年首次发布。
LDAP 的基本模型
LDAP 的基本模型是建立在"条目"(Entry)的基础上。一个条目是一个或多个属性的集合,并且具有一个全局唯一的"可区分名称"(用 dn 表示)。与关系型数据(后面简称数据库)进行类比,一个条目相当于数据库中的一条记录,而 dn 相当于数据库中记录的关键字,属性相当于数据库中的字段。
dn 必须是全局唯一的。
LDAP 中,将数据组织成一个树形结构,这与现实生活中的很多数据结构可以对应起来,而不像设计关系型数据库的表,需要进行多种变化。如下图所展示的就是一个树形结构的数据。
1 | +-------------------------------------------+ |
在上图所示的树形结构中,树的根结点是一个组织的域名(example.com),其下分为 3 个部分,分别是 managers、people 和 group,可将这 3 个组看作组织中的 3 个部门:如 managers 用来管理所有管理人员,people 用来管理登录系统的用户,group 用来管理系统中的用户组。当然,在该图中还可继续增加其他分支。
对于图中所示的树形结构,使用关系数据库来保存数据的话,需要设置多个表,一层一层分别保存,当需要查找某个信息时,再逐层进行查询,最终得到结果。
若使用目录来保存该图中的数据,则更直观。图中每个结点用一个条目来保存,不同类型的结点需要保存的数据可能不同,在 LDAP 中通过一个称为 objectClass 的类型来控制不同结点需要的数据(称为属性)。
对于目录中的数据怎样进行引用呢?前面提到过,每一个条目都有一个 dn,因为 dn 是唯一的,因此就可找到需要结点的数据。dn 的构造方式如下:
首先得到条目自己的名称(rdn,称为相对 dn),然后开始向上逐级查找父结点,一直到根项为止。例如,对于图中最右下方的结点,其 dn 为:
1 | dn: cn=ldap,ou=group,o=dlw.com |
通过这样的方式,即可唯一标识每一个结点。在现实生活中,有很多这种树形结构的数据,如计算机文件系统的目录结构、Internet 中的域名等。这些类型的数据,只要不需要频繁的更新,都适合用目录来保存。
LDAP 主要的简称含义:
o→ organization(组织-公司)ou→ organization unit(组织单元-部门)c→ countryName(国家)dc→ domainComponent(域名)sn→ user name(真实名称)cn→ common name(常用名称)
LDAP 的功能
在 LDAP 的功能模型中定义了一系列利用 LDAP 协议的操作,主要包含以下 4 部分:
- 查询操作:允许查询目录和取得数据,其查询性能比关系数据库好。
- 更新操作:目录的更新操作没关系数据库方便,更新性能较差,但也同样允许进行添加、删除、修改等操作。
- 复制操作:前面也提到过,LDAP 是一种典型的分布式结构,提供复制操作,可将主服务器的数据的更新复制到设置的从服务器中。
- 认证和管理操作:允许客户端在目录中识别自己,并且能够控制一个会话的性质。
LDAP 的高级功能:
- 实现账号统一集中管理
- 权限控制策略管理
- 密码控制策略管理
- 密码审计管理
- 主机控制管理
- 同步机制管理
- TLS/SASL 加密传输
- 高可用负载均衡架构
- 自定义 schema
- 各种集中平台账号集中管理
LDAP 协议的特点
- LDAP 是一种目录服务,保存在特殊的数据库中,数据的读取速度远高于写入速度。
- LDAP 对查询做了优化,读取速度优于普通关系数据库。
- LDAP 不支持事务、不能进行回滚,需要进行这些操作的应用只有选择关系数据库。
- LDAP 采用服务器/客户端模式,服务器端用于存储数据,客户端提供操作目录信息树的工具,支持分布式结构。
- LDAP 中的条目以树形结构组织和存储。
- LDAP 基于 Internet 协议,直接运行在简单和通用的 TCP/IP 或其他可靠的传输协议层上,使连接的建立和包的处理简单、快捷,对于互联网和企业网应用都很方便。
- LDAP 协议简单,通过使用查找操作实现列表操作和读操作。
- LDAP 通过引用机制实现分布式访问,通过客户端 API 实现分布式操作(对于应用透明),平衡了负载。
- LDAP 实现具有低费用、易配置和易管理的特点,并提供了满足应用程序对目录服务所需求的特性。
LDAP 目录服务
目录是一个为查询、浏览和搜索而优化的专业分布式数据库,它呈树状结构组织数据,就好像 Linux/Unix 系统中的文件目录一样。目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好像它的名字一样。
目录服务是由目录数据库和一套访问协议组成的系统。类似以下的信息适合储存在目录中:
- 企业员工信息,如姓名、电话、邮箱等
- 公司的物理设备信息,如服务器,它的 IP 地址、存放位置、厂商、购买时间等
- 客户的联系信息
- 软件包的配置信息
- 公用证书和安全密匙
与 LDAP 一样提供类似的目录服务软件还有 ApacheDS、Active Directory、Red Hat Directory Service。
LDAP 组织数据的方式
1 | +----------------------+ |
身份认证在 LDAP 中提供三种认证机制
匿名认证:即不对用户进行认证,该方法仅对完全公开的方式适用
基本认证:通过用户名和密码进行身份识别,又分为简单密码和 MD5 密码认证
1
2
3
4
5# ldapadd -x -D "cn=root,dc=example,dc=cn" -W -f base.ldif
Enter LDAP Password: 输入admin123
adding new entry "dc=example,dc=cn"
adding new entry "ou=People,dc=example,dc=cn"
adding new entry "ou=Group,dc=example,dc=cn"SASL 认证:即 LDAP 提供的在 SSL 和 TLS 安全通道基础上进行的身份认证,包括数字证书的认证。
TLS 安全性
分布式 LDAP 是以明文的格式通过网络来发送信息的,包括 client 访问 SLDAP 的密码。TLS(SSL 的后继者,由 OpenSSL 包加密机制来解决这个问题。
LDAP 目录数据结构
- 在 LDAP 中目录是按照树型结构组织——目录信息树(DIT),DIT 是一个主要进行读操作的数据库
- DIT 由条目(Entry)组成,条目相当于关系数据库中表的记录;条目是具有分辨名 DN(Distinguished Name)的属性-值对(Attribute-value,简称 AV)的集合
在目录树中怎么组织数据:
1 | uid=test1,ou=People,dc=example,dc=com |
- 在 UNIX 文件系统中,最顶层是根目录(root),LDAP 目录也通常用 ROOT 做根,通常称为 BaseDN。
- 因为历史(X.500)的原因,LDAP 目录用 OU(Organization Unit)从逻辑上把数据分开来。OU 也是一种条目,容器条目。
- OU 下就是真正的用户条目。
什么是 dn?
dn 即 distinguished name 的简称,在 LDAP 中,一个条目的分辨名叫做 dn,dn 是该条目在整个树中的唯一名称标识;dn 相当于关系数据库表中的关键字(Primary Key);dn 是一个识别属性,通常用于检索。
常见的两种 dn 设置:
| 类型 | 示例 |
|---|---|
| 基于 cn(姓名) | cn=test1,ou=People,dc=example,dc=com(dn 就是这一串字符),最常见的 cn 是 /etc/group 转换的条目 |
| 基于 uid(User ID) | uid=test1,ou=People,dc=example,dc=com,最常见的 uid 是 /etc/passwd、/etc/shadow 转换的条目 |
1 | [root@ldap-server ~]# ldapsearch -x -LLL "uid=mac*" |
LDAP 基本管理
启动 OpenLDAP 服务器程序之后,接下来的操作就是通过客户端程序对目录进行操作,包括添加、修改、删除和搜索数据等操作。
Entry
条目,也叫记录项,是 LDAP 中最基本的颗粒,就像字典中的词条,或者是数据库中的记录。通常对 LDAP 的添加、删除、更改、检索都是以条目为基本对象的。
- dn:每一个条目都有一个唯一的标识名(distinguished Name,DN),如上述中一个 dn:
uid=mac,ou=People,dc=example,dc=cn。通过 DN 的层次型语法结构,可以方便地表示出条目在 LDAP 树中的位置,通常用于检索。 - rdn:一般指 dn 逗号最左边的部分,如
cn=baby。它与 RootDN 不同,RootDN 通常与 RootPW 同时出现,特指管理 LDAP 中信息的最高权限用户。 - Base DN:LDAP 目录树的最顶部就是根,也就是所谓的 "Base DN",如
dc=example,dc=com。
Schema
对象类(ObjectClass)、属性类型(AttributeType)、语法(Syntax)分别约定了条目、属性、值,他们之间的关系如下图所示。所以这些构成了模式(Schema)——对象类的集合。条目数据在导入时通常需要接受模式检查,它确保了目录中所有的条目数据结构都是一致的。
schema(一般在 /etc/ldap/schema/ 目录)在导入时要注意前后顺序。
对于 LDAP 目录中保存的信息,可以使用 LDIF(LDAP Interchange Format)格式来保存。这是一种标准文本文件格式,使用这种格式保存得的 LDAP 服务器数据库中的数据可方便读取和修改,这也是其他大多数服务配置文件所采取的格式。
LDIF 文件常用来向目录导入或更改记录信息,这些信息需要按照 LDAP 中 schema 的格式进行组织,并会接受 schema 的检查,不符合其要求的格式将会出现报错信息。
在 LDAP 中,schema 用来指定一个目录中所包含的对象(objects)的类型(objectClass),以及每一个类型(objectClass)中必须提供的属性(Attribute)和可选的属性。可将 schema 理解为面向对象程序设计中的类,通过类定义一个具体的对象。LDIF 中的数据条目可理解为是一个具体的对象,是通过 schema 来规划创建的。因此,schema 是一个数据模型,用来决定数据按什么方式存储,并定义存储在不同的条目(Entry)下的数据之间的关系。schema 需要在主配置文件 slapd.conf 中指定,以用来决定在目录中可以使用哪些 objectClass。
在 /etc/openldap/schema/ 目录中提供了许多 schema 文件,只需要在配置文件 slapd.conf 中使用 include 命令将需要使用的 schema 包含即可。例如,配置文件默认包含了以下 schema 文件:
1 | include /etc/openldap/schema/core.schema |
通常使用系统提供的 schema 就可解决大部分应用。管理员也可以自己设计制定 schema,一般包括属性定义(AttributeDefinition)、类定义(ClassDefinition)以及语法定义(SyntaxDefinition)等部分。
向目录数据库中添加数据
初始状态下,LDAP 是一个空目录,即没有任何数据。可通过程序代码向目录数据库中添加数据,也可使用 OpenLDAP 客户端工具 ldapadd 命令来完成添加数据的操作,该命令可将一个 LDIF 文件中的条目添加到目录。因此,需要首先创建一个 LDIF 文件,然后再进行添加操作。
LDIF 文本条目格式
LDIF(LDAP Data Interchange Format,数据交换格式)是 LDAP 数据库信息的一种文本格式,用于数据的导入导出,每行都是"属性: 值"对。
LDIF 用文本格式表示目录数据库的信息,以方便用户创建、阅读和修改。在 LDIF 文件中,一个条目的基本格式如下:
1 | # 注释 |
dn 行类似于关系数据库中一条记录的关键字,不能与其他 dn 重复。一个 LDIF 文件中可以包含多个条目,每个条目之间用一个空行分隔。例如,以下内容组成一个条目:
1 | dn: dc=example,dc=com |
在以上文本中,各行含义如下:
- 第 1 行的 dn 定义该条目的标识。
- 第 2~4 行定义该条目的 objectClass,可以定义多个属性,如上面代码中定义了 3 个 objectClass。条目的属性根据 objectClass 的不同而不同,有的 objectClass 有必须设置的属性。在 2~4 行的 3 个 objectClass 中,top 没有必须定义的属性,dcobject 必须定义属性 dc,用来表示一个域名的部分,而 organization 必须定义属性 o,用来表示一个组织的名称。
- 根据 objectClass 的要求,第 5、6 行分别定义属性 dc 和属性 o 的值。
objectClass
LDAP 中,一个条目必须包含一个 objectClass 属性,且需要赋予至少一个值。每一个值将用作一条 LDAP 条目进行数据存储的模板;模板中包含了一个条目必须被赋值的属性和可选的属性。objectClass 有着严格的等级之分,最顶层是 top 和 alias。例如,organizationalPerson 这个 objectClass 就隶属于 person,而 person 又隶属于 top。
objectClass 可分为以下 3 类:
- 结构型(Structural):如
person和organizationUnit - 辅助型(Auxiliary):如
extensibleObject - 抽象型(Abstract):如
top,抽象型的 objectClass 不能直接使用
对象类是属性的集合,LDAP 预想了很多人员组织机构中常见的对象,并将其封装成对象类。比如人员(person)含有姓(sn)、名(cn)、电话(telephoneNumber)、密码(userPassword)等属性,单位职工(organizationalPerson)是人员(person)的继承类,除了上述属性之外还含有职务(title)、邮政编码(postalCode)、通信地址(postalAddress)等属性。
通过对象类可以方便的定义条目类型。每个条目可以直接继承多个对象类,这样就继承了各种属性。如果 2 个对象类中有相同的属性,则条目继承后只会保留 1 个属性。对象类同时也规定了哪些属性是基本信息,必须含有(Must 或 Required,必要属性);哪些属性是扩展信息,可以含有(May 或 Optional,可选属性)。
对象类有三种类型:结构类型(Structural)、抽象类型(Abstract)和辅助类型(Auxiliary)。结构类型是最基本的类型,它规定了对象实体的基本属性,每个条目属于且仅属于一个结构型对象类。抽象类型可以是结构类型或其他抽象类型父类,它将对象属性中共性的部分组织在一起,称为其他类的模板,条目不能直接集成抽象型对象类。辅助类型规定了对象实体的扩展属性。每个条目至少有一个结构性对象类。
对象类本身是可以相互继承的,所以对象类的根类是 top 抽象型对象类。以常用的人员类型为例,他们的继承关系:
1 | +----------+ |
在 OpenLDAP 的 schema 中定义了很多 objectClass,下面列出部分常用的 objectClass 的名称。
- account
- alias
- dcobject
- domain
- ipHost
- organization
- organizationalRole
- organizationalUnit
- person
- organizationalPerson
- inetOrgPerson
- residentialPerson
- posixAccount
- posixGroup
Attribute
属性(Attribute)类似于程序设计中的变量,可以被赋值。在 OpenLDAP 中声明了许多常用的 Attribute(用户也可自己定义 Attribute)。
每个条目都可以有很多属性(Attribute),比如常见的人都有姓名、地址、电话等属性。每个属性都有名称及对应的值,属性值可以有单个、多个,比如你有多个邮箱。
属性不是随便定义的,需要符合一定的规则,而这个规则可以通过 schema 制定。比如,如果一个 entry 没有包含在 inetorgperson 这个 schema 中的 objectClass: inetOrgPerson,那么就不能为它指定 employeeNumber 属性,因为 employeeNumber 是在 inetOrgPerson 中定义的。
LDAP 为人员组织机构中常见的对象都设计了属性(比如 commonName、surname)。下面有一些常用的别名:
| 属性 | 别名 | 语法 | 描述 | 值(举例) |
|---|---|---|---|---|
| commonName | cn | Directory String | 姓名 | sean |
| surname | sn | Directory String | 姓 | Chow |
| organizationalUnitName | ou | Directory String | 单位(部门)名称 | IT |
| organization | o | Directory String | 组织(公司)名称 | example |
| telephoneNumber | Telephone Number | 电话号码 | 110 | |
| objectClass | 内置属性 | top |
常见的 Attribute 含义如下:
c:国家cn:common name,指一个对象的名字。如果指人,需要使用其全名dc:domain Component,常用来指一个域名的一部分givenName:指一个人的名字,不能用来指姓l:指一个地名,如一个城市或者其他地理区域的名字mail:电子信箱地址o:organizationName,指一个组织的名字ou:organizationalUnitName,指一个组织单元的名字sn:surname,指一个人的姓telephoneNumber:电话号码,应该带有所在的国家的代码uid:userid,通常指某个用户的登录名,与 Linux 系统中用户的 uid 不同
objectClass 是一种特殊的 Attribute,它包含其他用到的 Attribute 以及其自身。
对于不同的 objectClass,通常具有一些必设属性值和一些可选属性值。例如,可使用 person 这个 objectClass 来表示系统中一个用户的条目,对于系统中用户通常需要有这样一些信息:姓名、电话、密码、描述等。对于 person,通过 cn 和 sn 设置用户的名和姓,这是必须设置的,而其他属性则是可选的。
下面列出部分常用 objectClass 要求必设的属性:
- account:userid
- organization:o
- person:cn 和 sn
- organizationalPerson:与 person 相同
- organizationalRole:cn
- organizationUnit:ou
- posixGroup:cn、gidNumber
- posixAccount:cn、gidNumber、homeDirectory、uid、uidNumber
创建 LDIF 文件
对以上内容有一定了解之后,就可以编写输入 LDIF 文件,编辑需要向目录数据库添加的条目了。下面根据如下图所示的结构,创建 LDIF 文件 example.com.ldif。
1 | +----------------------+ |
对上图进行分析,该目录结构分为 3 层,有 4 个结点。根据上图可创建 LDIF 文件如下:
每个结点可用一个 dn 表示,对于每个结点,又可继续添加新的结点。如在根结点中可添加其他部门 ou,在
ou=managers结点也可继续添加其他管理人员的信息。
1 | dn: dc=example,dc=com |
以上文件中各行的含义如下:
- 第 1~6 行创建根结点,这部分在前面也有介绍,就不再重复了。
- 第 7、11、16 行为空行,用来分隔 4 个 dn 条目(4 个结点)。
- 第 8~10 行定义
ou=managers结点的条目,该条目的 objectClass 为organizationalUnit,因此需要用ou属性定义组织名称。 - 第 12~15 行定义
cn=admin结点的条目,该条目使用的 objectClass 为person,因此需设置cn和sn两个属性值。 - 第 17~20 行与第 12~15 行的意义相同。
在以上 LDIF 文件中,第 1、8、12、17 行以 dn 开头,这部分内容必须唯一,并且在向目录数据库添加这些数据时,也要确保这些数据不能与目录数据库中已有数据相同,否则,添加操作将中断。
LDAP 命令的使用
增加:ldapadd
1 | # 选项: |
删除:ldapdelete
1 | # 选项: |
修改:ldapmodify
1 | # 选项: |
查询:ldapsearch
1 | # 选项: |
设置密码:ldappasswd
1 | # 选项: |
数据导出:slapcat
1 | # 选项: |
从导出结果可看出,除了使用
ldapadd命令添加到目录数据库中的条目数据外,还导出了很多其他信息,包括条目 UUID、时间戳等信息。
