提供:ZStack云计算
如果对于相关工具以及LDAP所要求的信息及方法不太熟悉,LDAP系统的管理工作往往难度较高。在本教程中,我们将探讨如何利用由OpenLDAP团队开发的相关工具与LDAP目录服务器进行交互。
在开始之前,大家首先需要拥有一套安装并配置了OpenLDAP的系统,具体方法参阅此文。另外,大家还应当参阅此篇教程以掌握LDAP目录服务的各基本术语及概念。
在满足以上条件后,接下来安装本教程中需要用到的各类工具。
在Ubuntu或Debian系统当中,大家可以通过apt库安装这些工具。利用以下命令更新本地软件包目录并安装:
sudo apt-get update
sudo apt-get install ldap-utils
在CentOS或Fedora当中,大家可以使用yum命令获取对应文件:
安装完成后,继续下一步内容。
大多数OpenLDAP工具都非常灵活,拥有简洁的命令结构以实现不同角色与系统间的交互。正因为如此,用户必须选定各类参数以实现与LDAP服务器的对接。
下面,我们将着重探讨如何根据需要执行的操作类型设定参数。这里提及的参数可用于多种工具,但我们将立足于管理工作所必需的ldapsearch工具进行讨论。
OpenLDAP工具要求我们为每项操作指定验证方法与服务器位置,具体方法为在协议后添加-H标记,之后输入目标服务器的网络位置:
举例来说,对于基础性非加密通信且协议scheme为ldap://的场景,具体命令如下:
如果大家与本地服务器进行通信,则可不必填写服务器域名或IP地址(但仍然需要指定scheme)。
如果大家通过SSL使用LDAP以接入LDAP服务器,则应使用ldaps:// scheme(请注意,这是一种已经过时的处理方法。OpenLDAP项目建议大家在LDAP端口上使用STARTTLS。具体方法请参阅此文):
这些协议使用默认端口(常规LDAP为389,LDAP over SSL则为636)。如果大家使用非标准端口,则需要在末尾处添加逗号与端口数。
要对经由Linux IPC(即进程间通信)所查询的服务器上LDAP目录进行接入,大家可以使用ldapi://协议。这种作法更安全且在某些管理任务中属于必要选项:
由于ldapi scheme需要使用本地位置,因此我们在这里无需指定服务器名称。不过如果大家在LDAP服务器配置内变更了socket-file位置,则需要在地址中指定新的socket位置。
LDAP要求客户声明自己的身份,从而识别其请求权限等级。LDAP利用“binding”机制实现这一效果,其负责将用户与已知安全条目进行关联。LDAP能够理解的身份类型分为三种。
最为常见的身份类型就是“匿名”绑定。这是一种松散的验证身份,LDAP服务器能够将任意类型的操作分配给任意用户(不过在默认情况下,公开的DIT只供匿名用户读取)。如果大家使用匿名绑定,则可实现各常见操作。
OpenLDAP工具会默认使用SASL验证(我们稍后再进行深入讨论),因此我们需要添加-x参数以允许匿名绑定:
以上命令的运行结果为:
Output for ldapsearch with an anonymous bind
# extended LDIF
#
# LDAPv3
# base <> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# search result
search: 2
result: 32 No such object
# numResponses: 1
这意味着该工具找不到我们希望搜索的结果。由于我们没有提供任何查询参数,因此找不到结果也很正常。不过其会显示我们的匿名绑定已经被服务器所接受。
LDAP服务器的第二种验证方法为简单绑定。所谓简单绑定,是利用LDAP服务器内的一个条目进行请求验证。条目的DN(即专有名称)作为验证用户名,该条目中的一项属性则被定义为密码,并在请求过程中一并交付。
为了利用简单验证机制实现验证,大家需要了解DIT结构之上的父元素,即root、base或者suffix条目。另外,大家还需要知晓要绑定的目标DN。
一般来讲,在LDAP服务器的安装过程中,系统会设置一个初始DIT并利用管理条目进行配置,也就是rootDN。在系统启动完成后,其将成为惟一一个面向绑定配置的DN。
如果大家不了解所接入LDAP服务器的root条目,则可在普通LDAP DIT之外查询一条特殊的“meta”条目以获取DIT root条目相关信息(其被称为root DSE)。具体命令如下:
LDAP服务器会返回以下结果:
LDAP root entry results
dn:
namingContexts: dc=example,dc=com
其中高亮部分即为DIT的root。我们可以利用它搜索要绑定到的条目。其中admin条目通常会使用simpleSecurityObject objectClass以获得在条目内设置密码的能力。我们可以借此对条目进行搜索:
返回结果为一份条目列表:
simpleSecurityObject search results
dn: cn=admin,dc=example,dc=com
这正是我们能够绑定到的目标rootDN账户。大家应当在服务器安装过程中为此账户配置密码。如果不知道密码,请参阅本教程了解密码重置方法。
在拥有了条目与密码后,接下来就可以在请求中执行简单绑定以向LDAP服务器证明身份了。
再次强调 ,我们首先需要指定LDAP服务器位置,而后使用-x标记声明我们不希望使用SASL验证。要执行实际绑定,我们需要使用-D来指定作为绑定目标的DN,利用-w或者-W命令提供密码。其中-w选项允许大家将密码作为命令的一部分,而-W选项则要求我们单独输入密码内容。
以下为绑定至rootDN的请求示例:
我们应当我们得到的结果应该与匿名绑定相同,这意味着凭证已经通过了验证。绑定至条目往往能够提供更多权限,而绑定至rootDN允许大家对整个DIT进行读取/写入,而不受访问控制的影响。
SASL意为简单验证与安全层。这套框架用于将验证方法同协议相结合,从而提供一套独立于特定实现体系之外的灵活验证系统。大家可以参阅维基百科页面以了解各可用方法。
我们的LDAP服务器可能只支持SASL机制中的一套子集。要了解其具体支持范围,可使用以下命令:
返回的结果取决于大家用于连接的scheme。对于未加密ldap:// scheme,大多数系统默认允许:
ldap:// supportedSASLMechanisms
dn:
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: NTLM
supportedSASLMechanisms: CRAM-MD5
如果大家使用ldapi:// scheme,即使用安全进程间通信,返回的列表可能如下所示:
ldapsearch -H ldapi:// -x -LLL -s base -b “” supportedSASLMechanisms
ldapi:// supportedSASLMechanisms
dn:
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: EXTERNAL
supportedSASLMechanisms: NTLM
supportedSASLMechanisms: CRAM-MD5
supportedSASLMechanisms: LOGIN
supportedSASLMechanisms: PLAIN
大多数SASL验证方法的配置工作都很耗时间,因此我们这里就不做细节说明了。虽然SASL验证并非本文的主要内容,但接下来我们仍然会在ldapi:// scheme中用到EXTERNAL方法。
EXTERNAL机制表示验证与安全由其它机制负责处理。例如,我们可以利用SSL提供加密与验证机制。
通常来讲,我们会利用root或sudo用户使用ldapi://接口。由于ldapi://使用Unix socket,因此其能够获取到初始请求用户并借此验证特定操作。LDAP用于配置的DIT利用这一机制验证root用户对LDAP的读取及变更操作。这些请求如下所示:
我们可以利用以上命令修改LDAP配置,这部分配置通常处于DIT当中并以cn=config root条目作为开头。
到这里,我们已经在命令行中指定了大部分连接信息。然而,大家也可以在将部分常用连接值添加到配置文件内以节省时间。
全局客户端配置文件位于/etc/ldap/ldap.conf,不过大家要变更的主要是主目录下~/.ldaprc用户配置文件。在文本编辑器中创建并打开此文件:
其中我们需要配置的设定主要有BASE、URI与BINDDN:
如果大家使用SASL验证,则可检查man ldap.conf以查看SASL证书的配置选项。
如果我们的LDAP基础条目为dc=example,dc=com,该服务器位于本地计算机,而且我们使用cn=admin,dc=example,dc=com进行绑定,那么~/.ldaprc文件应如下所示:
~/.ldaprc
BASE dc=example,dc=com
URI ldap://
BINDDN cn=admin,dc=example,dc=com
如此一来,我们就能够仅指定非SASL验证并提供admin条目相关密码以执行基础搜索了。以下命令将提供次层级搜索结果,范围则为我们之前指定的默认基础DN:
这一方式能够帮助我们在使用LDAP工具时缩短“样板”连接选项。另外,其中的各组成部分皆可根据实际需求进行增删。
现在我们已经了解了如何声明身份并指定LDAP服务器。接下来将目光转向具体工具。在大多数示例中,我们假定立足于托管LDAP服务器的同一设备进行命令执行。这意味着我们可以将主机指定部分留空。我们还DIT的基础条目为dc=example,dc=com。其rootDn则为cn=admin,dc=example,dc=com。下面正式开始。
首先是ldapsearch,因为我们已经在之前的示例中使用过该工具。LDAP系统针对搜索、读取与查找操作进行了优化。如果大家使用LDAP目录,则日常操作应该主要为搜索或查找。
我们先来看看用于命名及接入服务器的语法表达:
这样我们就能够以最低限度接入并通过服务器上LDAP实例的验证,不过还没有真正进行搜索操作。
在LDAP当中,搜索的起始位置被称为搜索基础。这一条目存在于DIT当中,并作为锚点存在。我们利用-b标记提交条目名称以指定搜索基础。
例如根据dc=example,dc=com DIT,我们可以使用以下搜索基础:
这条命令会显示dc=example,dc=com条目下的每个条目。如果大家使用其它条目,则可获得对应的内容结构。例如,如果我们以admin条目为起始,则命令如下:
ldapsearch -H ldap:// -x -D “cn=admin,dc=example,dc=com” -w password -b “cn=admin,dc=example,dc=com”
search base at cn=admin,dc=example,dc=com
#
#
dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9ejN2UmHoRjdha09tQY96TC9IN0kxYUVCSjhLeXBsc3A=
search: 2
result: 0 Success
我们已经为这些示例指定了基础,但还可以指定搜索范围以提高结果精度。这一选项由-s实现,请提供以下几种选项:
使用-s与-b可以调整我们所要搜索的DIT内对应区域。例如,我们可以使用one范围查看基础条目内的所有一级子分支:
这里,我们添加了-LLL以过滤输出结果。我们将在稍后对其进行探讨。总之,输出结果如下:
output
dn: cn=admin,dc=example,dc=com
dn: ou=groups,dc=example,dc=com
dn: ou=people,dc=example,dc=com
如果我们希望查看ou=people条目下的全部内容,则应将其设定为搜索基础并使用children范围:
通过调整搜索基础与搜索范围,大家可以查看DIT中的任何部分。
现在我们聊聊如何删除无关的输出结果。
大部分额外输出结果可由-L标记进行控制。根据实际查看需求,大家可以使用0到3级-L标记,添加的-L标记越多,被过滤掉的信息也就越多。在普通操作情况下,使用3级过滤往往会带来更好的搜索体验。
如果大家使用SASL验证机制,那么在修改cn=config DIT时则可额外使用-Q标记。其将启用SASL的静默模式,即删除任何与SASL相关的输出结果。但请注意,如果大家使用的机制需要验证凭证,则可能因此也被一同移除在外(导致验证错误)。
为了实际执行更为复杂的搜索,大家还需要指定搜索过滤。
一般来讲,我们需要在命令行末尾添加过滤,其结构为一条属性类型、一个比较运算符外加一个值。我们大多将其添加在引号内以防止被shell当成注释。另外,使用括号以指示不同过滤条件之间的边界。下面来看具体示例。
我们可以查看dc=example,dc=com DIT当中是否存在一条被设定为“jsmith”的用户名(即uid)属性。以下命令会搜索每个条目以查看是否有属性被设定为该值:
我们使用等号运算符来测试属于值匹配情况。当然还有其它运算符可供选择,例如搜索各条目内是否包含一条属性时,则使用星号运算符,其作为通配符实现比较效果。以下命令能够搜索条目内是否包含密码属性:
其它搜索过滤条件还包括:
大家也可以利用“!”否定符号作为前缀来设置搜索过滤条件,从而反向查找大部分搜索结果。例如,要查找全部操作性单元条目:
"(ou=*)"
要搜索全部非操作性单元条目,则:
"(!(ou=*)"
否定符号负责反转其后过滤条件的含义。
在过滤条件之后,我们还可以添加属性输出过滤。这其实就是一份各匹配条目所需显示属性的列表。默认情况下,每项属性都会被显示出来。设定属性输出过滤则能够帮助我们更精确地查看希望了解的内容。
例如,我们可以搜索全部使用用户ID的条目,但仅显示各条目的相关常规名称:
输出结果如下:
Output
dn: uid=bwright,ou=People,dc=example,dc=com
cn: Brian Wright
dn: uid=jsmith1,ou=People,dc=example,dc=com
cn: Johnny Smith
dn: uid=sbrown2,ou=People,dc=example,dc=com
cn: Sally Brown
若要查看其条目描述,则可将其添加至属性显示列表:
输出结果如下:
Output
dn: uid=bwright,ou=People,dc=example,dc=com
cn: Brian Wright
description: Brian Wright from Marketing. Brian takes care of marketing, pres
s, and community. Ask him for help if you need any help with outreach.
dn: uid=jsmith1,ou=People,dc=example,dc=com
cn: Johnny Smith
description: Johnny Smith from Accounting. Johnny is in charge of the company
books and hiring within the Accounting department.
dn: uid=sbrown2,ou=People,dc=example,dc=com
cn: Sally Brown
description: Sally Brown from engineering. Sally is responsible for designing
the blue prints and testing the structural integrity of the design.
如果不提供属性过滤,则返回全部属性。我们可以使用“*”字符进行确认。要返回各操作性属性(特别是各条目后台中的元数据属性),大家可以使用“+”进行指定。例如,要查看rootDN中的操作性属性:
输出结果为:
Output
dn: cn=admin,dc=example,dc=com
structuralObjectClass: organizationalRole
entryUUID: cdc718a0-8c3c-1034-8646-e30b83a2e38d
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20150511151904Z
entryCSN: 20150514191233.782384Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20150514191233Z
entryDN: cn=admin,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE
复合搜索能够将两种甚至多种独立搜索过滤条件结合起来以实现精确搜索。各搜索条件之间以一组括号及关联运算符衔接。
这里提到的关联运算符为“&”符号,相当于逻辑关系上的“和(AND)”,而“|”符号则相当于“或(OR)”。它们通过一组外部括号定义前面提到的各过滤条件。
因此要对域内同样拥有描述及邮箱地址的条目进行搜索,则:
"(&(description=*)(mail=*@example.com))"
返回的结果必须同样拥有这两项秘。
OR符号则返回与任意一项过滤条件相匹配的结果。如果要获取具备联系人信息的条目,我们可以使用以下过滤条件:
"(|(telephoneNumber=*)(mail=*)(street=*))"
通过这两种逻辑关系,我们能够实现各种更为复杂的搜索模式。
除了读取需求之外,我们还需要使用其它工具对DIT中的对象进行变更。
这里我们可使用ldapmodify命令对LDIF文件修改以操作DIT。感兴趣的朋友可以参阅此文了解与LDIF文件及条目修改或添加相关的信息。
ldapmodify的基本格式与ldapsearch语法基本一致。例如,我们需要使用-H指定服务器,-Y利用SASL进行验证或者选择-x、-D与-W|w使用其它验证方式。
最常见的变更方式就是修改LDIF文件并将其应用于DIT。大家可以使用-f选项(如果不使用-f选项,则需要在命令行中直接使用LDIF格式输入变更)。利用之前提到的语法通过以下命令创建LDIF文件:
这条命令将读取LDIF文件并应用其中指定的变更。对于ldapmodify命令,每一项LDIF变更都应该指定一条changetype,即变更类型。
如果大家的LDIF文件用于添加新条目且不包含changetype,则在添加每一条目时可以使用-a标记或者直接使用ldapadd命令。下面来看包含有changetype的LDIF文件内容示例:
LDIF with changetype
dn: ou=newgroup,dc=example,dc=com
changetype: add
objectClass: organizationalUnit
ou: newgroup
直接使用ldapmodify处理该文件:
不过某些文件中可能不包含changetype,例如:
LDIF without changetype
dn: ou=newgroup,dc=example,dc=com
objectClass: organizationalUnit
ou: newgroup
在这种情况下,需要使用-a与ldapmodify的组合进行条目添加,或者直接使用ldapadd命令:
或者:
类似的命令还适用于删除(ldapdelete)与移动LDAP条目(ldapmodrdn)。使用这些命令要求大家在文件中分别明确指定changetype: delete与changetype: modrdn。具体操作格式则取决于大家是在LDIF文件内做出变更,抑或是直接进行命令行操作。
如果大家希望以尝试的方式运行LDIF文件,则可使用-n与-v标记。这样无需对DIT进行实际变更,大家就能了解变更的执行效果:
一般来讲,如果LDIF文件的处理引发错误,操作会立即中止。
不过如果大家希望命令继续执行完成并跳过错误变更,则可使用-c标记。另外,使用-S标记则可指明将错误信息写入哪个文件以备修复:
通过这种方式,大家可以在该日志文件内评估错误内容。
下面再来了解LDAP中的其它一些常见操作命令。
如果LDAP条目包含密码,则可使用ldappasswd命令修改这些条目。其适用于验证那些存在问题的账户或者为管理账户提供新密码(可同时选择保留旧密码)。
使用-a、-A或者-t指定旧密码,三者的作用分别为旧密码在行内作为下一条目、提示输入旧密码以及从该文件中读取旧密码并作为下一条目。
新密码则可通过-s、-S或-T指定,三者分别代表新密码在行内作为下一条目、提示输入新密码以及从该文件中读取新密码并作为下一条目。因此通常变更命令如下:
如果未指定条目,则正被用于绑定的条目则将作为变更目标。如果大家正在绑定至某管理条目,则可在命令之后添加其它拥有写入权限的条目进行直接变更。
要了解更多与密码变更及重置相关的内容,请参阅此篇教程。
ldapwhoami命令用于查看LDAP服务器验证完成后的当前用户身份。
如果大家使用匿名或者简单验证,则结果可能无甚作用。然而对于SASL验证来说,其能够帮助大家了解验证机制的识别结果。
例如,如果我们使用-Y EXTERNAL SASL机制通过sudo对cn=config DIT执行操作,则可利用ldapwhoami查看验证DN:
sudo ldapwhoami -H ldapi:// -Y EXTERNAL -Q
ldapwhoami output
dn:gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
这显然并非DIT中的条目,而是SASL验证如何被翻译为LDAP能够理解的内容。通过验证DN,我们就能够创建映射与访问限制。
ldapurl工具允许大家在查询中指定多种组件以建立LDAP URL。LDAP URL允许大家利用标准化URL对LDAP服务器中的资源进行访问。这些属于未授权连接且处于只读模式。很多LDAP解决方案都已经不再支持LDAP URL,因此这一工具的适用范围可能比较有限。
标准DLAP URL采用以下语法:
ldap://host:port/base_dn?attr_to_return?search_scope?filter?extension
各组成部分的作用为:
URL中的各部分以问号相隔。大家无需提供用不上的条目,但由于条目类型是由其在字符串中的位置决定的,因此必须适当留空。
例如,一条URL可能如下所示:
ldap://localhost:389/dc=example,dc=com?dn,ou?sub?(ou=*)
如果大家希望在ldapurl工具中引用,则可使用-H标记并将URL纳入引号内:
输出结果如下:
ldapurl output
scheme: ldap
host: localhost
port: 389
dn: dc=chilidonuts,dc=tk
selector: dn
selector: ou
scope: sub
filter: (ou=*)
大家也可以使用以下标记来反向处理并生成LDAP URL。其作用与LDAP URL中的各组成部分正好相反:
因此,我们可以构建以下命令:
其返回结果为一条构建完成的URL:
ldapurl output
ldap://localhost:389/dc=example,dc=com?dn,ou?sub?(ou=*)
大家可以利用这种格式构建起可供LDAP客户端作为通信之用的URL。
ldapcompare工具可用于将条目中的某项属性与给定值进行比对。
在绑定过程中,我们往往需要根据查询到的实际数据进行设置,包括提供条目DN及声明。其声明格式为先指定一项属性,而后是值,二者间由一个或两个冒号隔开。对于简单的字符串值,使用单冒号即可。双冒号通常用于base64编码值。
因此在声明John为“powerusers”群组的成员时,使用以下命令:
如果他在群组当中,则返回TRUE。如果不在,则返回FALSE。如果用于绑定的DN不具备读取该属性的权限,则返回UNDEFINED。
通过这种方式,我们能够检查群组成员顺序来执行请求操作,从而达到验证系统的目的。
到这里,大家应该已经了解了如何利用各LDAP工具接入、管理并使用LDAP服务器。其它客户端亦可提供用于LDAP系统日常管理的操作界面,但今天我们提到的工具能够帮助大家深入理解DIT中的数据访问与结构体系,从而立足于底层掌握其使用方式。
本文来源自DigitalOcean Community。英文原文:How To Manage and Use LDAP Servers with OpenLDAP Utilities By Justin Ellingwood
翻译:diradw