主要介绍LDAP网络认证和授权。
OpenLDAP Server
轻量级目录访问协议(Lightweight Directory Access Protocol,简称LDAP)是一种用于查询和修改运行在TCP/IP上的基于X.500(构成全球分布式的名录服务系统的协议)的目录服务的协议。
现在使用的绝大部分版本都是由RFC4510标准定义的LDAPv3。
LDAP协议访问LDAP目录。以下是一些关键的概念和术语:
-
LDAP目录是一个具有层次结构的数据条目树,称为Directory Information Tree(DIT)。
-
每一个条目由一系列的属性组成。
-
属性具有类型(名称/描述)和一个或多个值。
-
每个属性必须在至少一个objectClass中定义。即不同的objectclass中定义由不同的属性。 LDAP中,一个条目必须包含一个objectClass属性,且需要赋予至少一个值。每一个值将对应一条LDAP条目进行数据存储的模板;模板中包含了一个条目必须被赋值的属性和可选的属性。objectClass有着严格的等级之分,最顶层是top和alias。例如,organizationalPerson这个objectClass就隶属于person,而person又隶属于top。
-
attribute和objectclass在schemas中定义(一个objectclass可以理解为一个特殊的属性)。
-
每一个条目都有一个唯一的标识符:Distinguished Name(DN/dn)。有RDN和父条目的DN组成。
-
DN并非条目属性,而是条目自身的一部分。
条目实例: -
DN is “cn=John Doe,dc=example,dc=com”
-
RDN is “cn=John Doe”
-
parent DN is “dc=example,dc=com”
dn: cn=John Doe,dc=example,dc=com
cn: John Doe
givenName: John
sn: Doe
telephoneNumber: +1 888 555 6789
telephoneNumber: +1 888 555 1232
mail: john@example.com
manager: cn=Larry Smith,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
以上条目采用LDIF格式(LDAP数据交换格式)。你提供给你的信息
DIT也必须是这种格式。它在RFC28492中定义。
本指南将描述如何将其用于中央身份验证,同时LDAP适用于任何涉及大量访问请求(主要是读取、attribute-based(name:value)的后端的情况。示例包括地址簿、电子邮件地址列表和邮件服务器的配置。
安装
安装OpenLDAP服务器守护进程和传统的LDAP管理实用程序。它们分别可以在slapd包和ldap-utils包中找到。
slapd的安装将创建一个工作配置。特别是,它将创建一个数据库实例,您可以使用它来存储数据。但是,该实例的后缀(或基本DN)将从主机的域名确定。如果您想要一些不同的东西,您可以在安装后仍然没有任何有用数据时立即更改它。
此教程使用的数据库后缀:dc=example,dc=com。
apt-get install slapd ldap-utils
如果您想更改DIT后缀,现在是一个很好的时机,因为更改它会丢弃现有的后缀。使用实例修改后缀。
dpkg-reconfigure slapd
例如,要将DIT后缀转换为dc=example,dc=com,以便更严格地遵循本指南,当被问及DNS域名时,输入example.com。
从ubuntu 8.0开始slapd被设计为在slapd内部通过专门的DIT来进行配置。这允许动态配置slapd,而不需要重新启动服务。这个配置数据库由位于/etc/ldap/slapd.d目录下的基于文本的LDIF文件集合组成
这种工作方式有几个名称:slapd-config方法、RTC方法(Real - Time
配置),或cn=config方法。您仍然可以使用传统的平面文件方法(slapd.conf),但不推荐这样做;这项功能最终将被淘汰。
在安装期间,系统提示您定义管理凭据。这些是数据库实例的rootDN的基于ldap的凭据。默认情况下,该用户的DN为cn=admin,dc=example,dc=com。另外,默认情况下,没有为slapd-config数据库创建管理帐户,因此您需要从外部对LDAP进行身份验证,以便访问它。稍后我们将看到如何做到这一点。
现在一些经典的模式(cosine, nis, inetorgperson)内置了slapd。“core” schema是任何模式工作的先决条件。
安装之后检查
安装进程设置两个DIT,一个是slapd-config,另一个是给自定义的数据(dc=example,dc=com)。
- 这是slapd-config数据库/DIT的样子。回想一下,这个数据库是基于ldif的:
/etc/ldap/slapd.d/
/etc/ldap/slapd.d/
/etc/ldap/slapd.d/cn=config.ldif
/etc/ldap/slapd.d/cn=config
/etc/ldap/slapd.d/cn=config/cn=schema
/etc/ldap/slapd.d/cn=config/cn=schema/cn={1}cosine.ldif
/etc/ldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif
/etc/ldap/slapd.d/cn=config/cn=schema/cn={2}nis.ldif
/etc/ldap/slapd.d/cn=config/cn=schema/cn={3}inetorgperson.ldif
/etc/ldap/slapd.d/cn=config/cn=module{0}.ldif
/etc/ldap/slapd.d/cn=config/olcDatabase={0}config.ldif
/etc/ldap/slapd.d/cn=config/olcDatabase={-1}frontend.ldif
/etc/ldap/slapd.d/cn=config/olcDatabase={1}mdb.ldif
/etc/ldap/slapd.d/cn=config/olcBackend={0}mdb.ldif
/etc/ldap/slapd.d/cn=config/cn=schema.ldif
不要直接编辑slapd-config数据库。通过LDAP协议(实用程序)进行更改。
这是slapd-config DIT通过LDAP协议的样子:
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn
dn: cn=config
dn: cn=module{0},cn=config
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: olcBackend={0}mdb,cn=config
dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}mdb,cn=config
条目解释:
- cn=config:全局配置
- cn=module{0},cn=config:动态加载的模块
- cn=schema,cn=config:包含硬编码的系统级模式
- cn={0}core,cn=schema,cn=config:硬编码的核心模式
- cn={1}cosine,cn=schema,cn=config:cosine模式
- cn={2}nis,cn=schema,cn=config:nis模式
- cn={3}inetorgperson,cn=schema,cn=config:inetorgperson模式
- olcbackend={0}mdb,cn=config:mdb后台存储类型
- olcDatabase={-1}frontend,cn=config:前端数据库,其他数据库的默认配置
- olcDatabase={0}config,cn=config:slapd配置数据库(cn=config)
- olcDatabase={1}mdb,cn=config:数据库实例(dc=example,dc=com)
这是dc=example,dc=com DIT的样子:
ldapsearch -x -LLL -H ldap:/// -b dc=example,dc=com dn
dn: dc=example,dc=com
dn: cn=admin,dc=example,dc=com
条目解释:
- dc=example,dc=com:域名DIT
- cn=admin,dc=example,dc=com:DIT管理员,在包安装过程中设置的。
修改/补充数据库
让我们向数据库介绍一些内容。我们将增加以下内容:
- 一个节点叫做People(存储用户)
- 一个节点叫做Group(存储组)
- 一个组叫做miners
- 一个用户叫做john
创建LDIF文件并命名为add_content.ldif:
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups
dn: cn=miners,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: miners
gidNumber: 5000
dn: uid=john,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: john
sn: Doe
givenName: John
cn: John Doe
displayName: John Doe
uidNumber: 10000
gidNumber: 5000
userPassword: johnldap
gecos: John Doe
loginShell: /bin/bash
homeDirectory: /home/john
重要的是,目录中的uid和gid值不要与本地值冲突。使用较大的数字范围,例如从5000开始。通过在ldap中设置高的uid和gid值,还可以更容易地控制本地用户与ldap用户之间的操作。稍后会详细介绍。
执行如下类容:
ldapadd -x -D cn=admin,dc=example,dc=com -W -f add_content.ldif
Enter LDAP Password: ********
adding new entry "ou=People,dc=example,dc=com"
adding new entry "ou=Groups,dc=example,dc=com"
adding new entry "cn=miners,ou=Groups,dc=example,dc=com"
adding new entry "uid=john,ou=People,dc=example,dc=com"
可通过ldapsearch来查看添加的操作是否全部执行正确:
ldapsearch -x -LLL -b dc=example,dc=com 'uid=john' cn gidNumber
dn: uid=john,ou=People,dc=example,dc=com
cn: John Doe
gidNumber: 5000
命令行实例解释:
- -x:简单绑定模式,不会使用默认的SASL方法
- -LLL:关闭打印外部信息
- uid=john:过滤器
- cn gidNumber: 请求显示某些属性(默认是显示所有属性)
修改slapd配置数据库
slapd-config DIT也可以被修改,以下是示例:
使用ldapmodify添加一个Index(DbIndex attribute)到{1}mdb,cn=config到数据库(dc=example,dc=com)。创建uid_index.ldif:
dn: olcDatabase={1}mdb,cn=config
add: olcDbIndex
olcDbIndex: mail eq,sub
执行命令:
ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f uid_index.ldif
modifying entry "olcDatabase={1}mdb,cn=config"
修改确认:
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
cn=config '(olcDatabase={1}mdb)' olcDbIndex
dn: olcDatabase={1}mdb,cn=config
olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
olcDbIndex: mail eq,sub
让我们添加一个模式。首先需要将其转换为LDIF格式。除了在/etc/ldap/schema目录中可以找到已转换的模式外,还可以找到未转换的模式。
- 从slapd-config数据库中删除一个模式并不简单。练习在测试系统上添加模式。
- 在添加任何模式之前,你应该检查哪些模式已经安装(显示的是默认的开箱即用的输出)
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \
cn=schema,cn=config dn
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
以下的示例是添加CORBA模式。
- 创建转换配置文件schema_convert.conf,其中包含以下行:
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/collective.schema
include /etc/ldap/schema/corba.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/duaconf.schema
include /etc/ldap/schema/dyngroup.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/java.schema
include /etc/ldap/schema/misc.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/openldap.schema
include /etc/ldap/schema/ppolicy.schema
include /etc/ldap/schema/ldapns.schema
include /etc/ldap/schema/pmi.schema
- 创建输出目录ldif_output
- 确定模式的索引:
slapcat -f schema_convert.conf -F ldif_output -n 0 | grep corba,cn=schema
cn={2}corba,cn=schema,cn=config
当slapd摄取具有相同父DN的对象时,它将为该对象创建一个索引。
索引包含在大括号:{X}中。
- 使用slapcat执行转换
slapcat -f schema_convert.conf -F ldif_output -n0 -H \
ldap:///cn={2}corba,cn=schema,cn=config -l cn=corba.ldif
现在转换的模式就存在cn=corba.ldif中。
- 编辑cn=corba.ldif:
dn: cn=corba,cn=schema,cn=config
...
cn: corba
同时从底部删除以下几行:
structuralObjectClass: olcSchemaConfig
entryUUID: 52109a02-66ab-1030-8be2-bbf166230478
creatorsName: cn=config
createTimestamp: 20110829165435Z
entryCSN: 20110829165435.935248Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20110829165435Z
你的属性值会有所不同。
- 最后,使用ldapadd将新模式添加到slapd-config DIT中。
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f cn\=corba.ldif
adding new entry "cn=corba,cn=schema,cn=config"
- 确认现在加载的模式
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: cn={4}corba,cn=schema,cn=config
对于要使用LDAP进行身份验证的外部应用程序和客户端,都需要为此进行专门配置。有关详细信息,请参考相应的客户端文档。
日志
在实现基于openldap的解决方案时,slapd的活动日志记录是必不可少的,但它必须在软件安装后手动启用。否则,日志中将只显示基本消息。
与任何其他slapd配置一样,日志记录是通过slapd-config数据库启用的
OpenLDAP 拥有多个日志子系统(级别),每个子系统包含一个低等级的,一个比较好的日志级别是stats。
创建logging.ldif with the following contents:
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats
实现更改:
sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f logging.ldif
这将产生大量的日志记录,一旦系统投入生产,您将希望控制到较低的详细级别。在这种详细模式下,您的主机的syslog引擎(rsyslog)可能很难跟上,可能会删除消息:
rsyslogd-2177: imuxsock lost 228 messages from pid 2547 due to rate-limiting
您可以考虑更改rsyslog的配置。在/etc/rsyslog.conf:
#Disable rate limiting
#(default is 200 messages in 5 seconds; below we make the 5 become 0)
$SystemLogRateLimitInterval 0
然后重启syslog daemon:
system restart syslog.service
副本
随着越来越多的联网系统开始依赖LDAP服务,它变得越来越重要。在这样的环境中,标准做法是在LDAP中构建冗余(高可用性),以防止LDAP服务器失去响应时造成的破坏。这是通过LDAP副本来实现。
复制是通过Syncrepl引擎实现的。这允许使用Consumer-Provider模式同步更改。在此实现特定类型的副本使用一下模式:
refreshAndPersist and delta-syncrepl。有数据发生端将数据推送到消费端。另外,只有实际的更改将被发送,而不是整个条目。
Provider配置
开始配置provider
- 创建provider_sync.ldif:
#Add indexes to the frontend db.
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryCSN eq
add: olcDbIndex
olcDbIndex: entryUUID eq
#Load the syncprov and accesslog modules.
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad syncprov
add: olcModuleLoad
olcModuleLoad: accesslog
#Accesslog database definitions
dn: olcDatabase={2}mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: {2}mdb
olcDbDirectory: /var/lib/ldap/accesslog
olcSuffix: cn=accesslog
olcRootDN: cn=admin,dc=example,dc=com
olcDbIndex: default eq
olcDbIndex: entryCSN,objectClass,reqEnd,reqResult,reqStart
#Accesslog db syncprov.
dn: olcOverlay=syncprov,olcDatabase={2}mdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpNoPresent: TRUE
olcSpReloadHint: TRUE
#syncrepl Provider for primary db
dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpNoPresent: TRUE
#accesslog overlay definitions for primary db
dn: olcOverlay=accesslog,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcAccessLogConfig
olcOverlay: accesslog
olcAccessLogDB: cn=accesslog
olcAccessLogOps: writes
olcAccessLogSuccess: TRUE
#scan the accesslog DB every day, and purge entries older than 7 days
olcAccessLogPurge: 07+00:00 01+00:00
更改LDIF文件中的rootDN以匹配您的目录中的rootDN。
- 创建目录
sudo -u openldap mkdir /var/lib/ldap/accesslog
- 添加新的内容
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f provider_sync.ldif
到现在为止,provider配置完毕。
配置Consumer
现在开始配置消费端:
- 确保slapd-config数据库与Provider的数据库相同。特别是,确保模式和数据库后缀是相同的。
- 创建consumer_sync.ldif
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: syncprov
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryUUID eq
add: olcSyncRepl
olcSyncRepl: rid=0 provider=ldap://ldap01.example.com bindmethod=simple
binddn="cn=admin,dc=example,dc=com"
credentials=secret searchbase="dc=example,dc=com" logbase="cn=accesslog"
logfilter="(&(objectClass=auditWriteObject)(reqResult=0))" schemachecking=on
type=refreshAndPersist retry="60 +" syncdata=accesslog
add: olcUpdateRef
olcUpdateRef: ldap://ldap01.example.com
确保以下的属性拥有正确的值:
- provider(Provider的主机名–ldap01.example.com或者ip地址)
- binddn(你使用的admin dn)
- credentials(binddn的密码)
- searchbase(你使用的数据库后缀)
- olcUpdateRef(Provider的主机名或者IP地址)
- rid(Replica ID,副本ID,唯一标识副本的3位数字。每个消费者应该至少有一个rid)
- 添加内容
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f consumer_sync.ldif
你就完成了。这两个数据库(后缀:dc=example,dc=com)现在应该同步。
测试
一旦副本启动,您可以通过运行来监视它:
ldapsearch -z1 -LLLQY EXTERNAL -H ldapi:/// -s base -b dc=example,dc=com contextCSN
dn: dc=example,dc=com
contextCSN: 20120201193408.178454Z#000000#000#000000
对提供者和使用者都有影响。一旦这两台机器的输出(上面示例中的20120201193408.178454z# 000000#000#000000)匹配,就有了复制。每次在提供者中进行更改时,此值将更改,消费者中的值也应更改。
如果您的连接很慢,并且/或您的ldap数据库很大,那么可能需要一段时间才能使使用者的contextCSN与提供者的匹配。但是,你会知道它正在进步,因为消费者的上下文csn将稳步增长。
如果使用者的contextCSN缺失或与提供者不匹配,您应该停止并在继续之前找出问题所在。尝试检查提供程序中的slapd (syslog)和auth日志文件,看看消费者的身份验证请求是否成功,或者它检索数据的请求(它们看起来像许多ldapsearch语句)是否返回错误。
要测试它是否工作,只需查询消费者,数据库中的DNs:
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com dn
你应该看到用户“john”和组“miners”以及节点“People”和“Groups”。