2. OpenLDAP
OpenLDAP 是一个
轻型目录访问协议 的一个开源实施方案。 我们可以使用它来建立一个域用户、组和计算机的中央信息库, 并且可以让 Samba (和所有其它的 LDAP-aware 服务) 用此信息来进行认证和管理。
2.1 LDAP协议
轻型的目录访问协议 (LDAP) 是一个用来访问基于 X.500 目录服务的网络协议。一个这里所说的目录是一个经过特殊优化数据库,它便于读取、浏览、搜索和支持先进的过滤功能 ([
OLDAP])。
和 Unix 文件系统以及
域名系统 类似, 这个数据库的结构类似于一棵分级的倒置的树, 树根在顶部; 例如:
如上图所示, LDAP树的顶部的通常是基于域名的, 这样可以使用域名系统排列目录服务的布局。
在LDAP树内的每个节点被称为一个entry(leo: 这里可理解为词条或者项),每个entry 是唯一的且对应于它的 Distinguished Name (DN), 每个entry由自己的名称 (被称为Relative Distinguished Name, RDN, 通常有这个entry的属性派生), 逗号连接着它的父系的名称构成。例如, 下图中突出显示的 entry 的 DN :
由序列 "uid=Danix", "ou=Users", "dc=kernel-panic" and "dc=it" 构成, 因此写作 "uid=Danix,ou=Users,dc=kernel-panic,dc=it" (请参阅 [
RFC4514] 以了解详细的DN格式描述)。
一个 entry 由一组属性构成; 每条属性有一个名称 (或者类型) 以及一个或多个值。 这个entry的名称通常是一个助记字符串, 像 "dc" 代表 "Domain Component" 或者 "cn" 代表r "Common Name", 以及确定相应值的语法。ObjectClasses(目标类性) 定义了LDAP的entry的属性结构, 也就是说,一个特定 LDAP 的 entry 必须指定哪些属性是
must 、哪些属性是
may 。ObjectClasses 和属性都在Schemas里定义。
尽管 LDAP 是一个二进制协议, 但是可以将这些 entries 可以表示为人可以阅读的LDIF格式; 例如:
代码: 全选
dn: uid=danix,ou=Users,dc=kernel-panic,dc=it
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
objectClass: sambaSamAccount
cn: Daniele Mazzocchio
sn: Mazzocchio
givenName: Daniele
uid: Danix
uidNumber: 2000
gidNumber: 513
homeDirectory: /home/danix
loginShell: /bin/ksh
gecos: Daniele Mazzocchio
structuralObjectClass: inetOrgPerson
[ ... ]
LDAP查询可用URLs的形式来表示, 你可以通过此方式指定搜索和搜索查询范围并选择返回哪种属性。LDAP URL的查询语法是:
代码: 全选
ldap://[host[:port]]/[DN[?[attributes][?[scope][?[filter][?extensions]]]]]
这里大部分的URL子项是可选项:
- host是要查询的LDAP服务器的域名或者IP地址;
- port是LDAP服务器监听的网络端口 (默认是TCP 389端口);
- DN是指 Distinguished Name(标识名),作为LDAP查询的基本目标 (默认是root DN);
- attributes指定了从entries里返回哪些属性 (默认是全部属性);
- scope是指搜索的范围。有效的范围是 "base" (默认) 代表搜索一个基本目标, "one" 代表对某一级的搜索, 而 "sub" 表示搜索子树;
- filter代表在特定的搜索中应用到entries的搜索过滤 (默认为 "(objectClass=*)");
- extensions表示对LDAP URL格式的扩展 (默认是没有扩展)。
例如, 下面的 URL:
代码: 全选
ldap://ldap.kernel-panic.it/uid=Danix,ou=Users,dc=kernel-panic,dc=it
是指某一特定用户entry的所有属性, 而一个类似这样的URL:
代码: 全选
ldap:///dc=kernel-panic,dc=it?sn?sub?(givenName=Daniele)
是指 givename 是 "Daniele" 的所有 sn (surname、姓) 属性。更多的细节请参阅 [
RFC4516].
2.2 安装和配置
我们已经讲了不少理论了, 现在开始实战! OpenLDAP可以通过 OpenBSD's
packages and ports system 获取(
note: unfortunately, the bdb flavor, providing support for the bdb and hdb backends, is marked as broken since OpenBSD 4.3); 下面是需要安装的packages清单:
- cyrus-sasl-x.x.x.tgz
- openldap-client-x.x.x.tgz
- openldap-server-x.x.x.tgz
安装完毕后! OpenLDAP的配置文件储存在 /etc/openldap。客户端的配置包含在文件
ldap.conf(5) 里; 以下是一个配置文件范例:
文件 /etc/openldap/ldap.conf
代码: 全选
# URI of the LDAP server to which the LDAP library should connect
URI ldap://ldap.kernel-panic.it
# The default base DN to use when performing LDAP operations
BASE dc=kernel-panic,dc=it
# Size limit to use when performing searches
SIZELIMIT 12
# Time limit to use when performing searches
TIMELIMIT 15
# Never derefernce aliases
DEREF never
slapd.conf(5) 文件提供了独立运行的LDAP进程
slapd(8C) 的配置信息:
文件 /etc/openldap/slapd.conf
代码: 全选
# Include the necessary schema files. core.schema is required by default, the
# other ones are needed for sambaSamAccount. The samba.schema file can be found
# here and must be copied in /etc/openldap/schema/.
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/samba.schema
# Absolute path to the PID file
pidfile /var/run/openldap/slapd.pid
# Absolute path to the file that will hold slapd's command line options
argsfile /var/run/openldap/slapd.args
# Type of database backend
database ldbm
# DN suffix of queries that will be passed to this backend database
suffix "dc=kernel-panic,dc=it"
# Database directory
directory /var/openldap-data
# The Distinguished Name of the administrator of this database
rootdn "cn=Manager,dc=kernel-panic,dc=it"
# Password (or password hash) for the rootdn. Clear-text passwords are allowed
# but strongly discouraged; the password hash can be generated using the
# slappasswd(8C) command; e.g.:
# # slappasswd
# New password: <password>
# Re-enter new password: <password>
# {SSHA}d1bjQZEA43NFKNL7g48XjaNv/W6DG0fY
rootpw {SSHA}d1bjQZEA43NFKNL7g48XjaNv/W6DG0fY
# Maintain indices on the most useful attributes to speed up searches made on
# the sambaSamAccount, posixAccount and posixGroup objectClasses
index objectClass eq
index cn pres,sub,eq
index sn pres,sub,eq
index uid pres,sub,eq
index displayName pres,sub,eq
index uidNumber eq
index gidNumber eq
index memberUid eq
index sambaSID eq
index sambaPrimaryGroupSID eq
index sambaDomainName eq
index default sub
# Access control configuration. The rootdn can always read and write everything
access to attrs=userpassword,sambaLMPassword,sambaNTPassword
by anonymous auth
by self write
by * none
access to *
by self write
by * read
我们可以用
slaptest(8C) 命令检查
slapd.conf(5) 文件的有效性:
代码: 全选
# install -d -o _openldap /var/run/openldap
# slaptest -u
config file testing succeeded
#
这个
slapd.conf(5) 文件包含了root密码, 应该限制其访问权限:
代码: 全选
# chgrp _openldap /etc/openldap/slapd.conf
# chmod 640 /etc/openldap/slapd.conf
好了, 应该可以运行
slapd(8C) 了。初次运行时你可能像加上 "-d" 选项来开启debug模式。这样可以让进程保持在前台运行以便观察所有的出错信息:
代码: 全选
# /usr/local/libexec/slapd -4 -d 256 -u _openldap -g _openldap
[ ... ]
slapd starting
你可以通过运行
ldapsearch(1) 命令确保一切正常:
代码: 全选
# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
# extended LDIF
#
# LDAPv3
# base <> with scope baseObject
# filter: (objectclass=*)
# requesting: namingContexts
#
#
dn:
namingContexts: dc=kernel-panic,dc=it
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
#
如果一切正常, 我们就可以将
slapd(8C) 配置为随系统启动, 只要将下行和参数加入
/etc/rc.conf.local(8):
文件 /etc/rc.conf.local
代码: 全选
slapd_flags="-4 -u _openldap -g _openldap"
然后将下列命令加入到
/etc/rc.local(8):
文件 /etc/rc.local
代码: 全选
if [ "$slapd_flags" != "NO" -a -x /usr/local/libexec/slapd ]; then
echo -n ' slapd'
install -d -o _openldap /var/run/openldap
/usr/local/libexec/slapd $slapd_flags
fi
2.3 LDAP over TLS/SSL
OpenLDAP内置了对 TLS/SSL 协议的支持,通过public-key加密为LDAP连接提供了完整性和保密性。启用 TLS/SSL 可以防止在网络上以明文的方式传输数据, 这样可以避免用户密码被窃听。
2.3.1 设置 PKI
TLS要靠public key证书进行认证,所以你需要先建立一套基本的 Public Key 框架 (PKI) 以便管理数字证书。首先是准备工作, 我们将创建一些保存证书的目录:
代码: 全选
# install -m 700 -d /etc/openldap/ssl/private
建立PKI的第一步是先用
openssl(1) 创建一个 CA 认证 (/etc/openldap/ssl/ca.crt) 和 private key (/etc/ssl/private/ca.key) :
代码: 全选
# openssl req -days 3650 -nodes -new -x509 -keyout /etc/ssl/private/ca.key \
> -out /etc/openldap/ssl/ca.crt
[ ... ]
Country Name (2 letter code) []: IT
State or Province Name (full name) []: Italy
Locality Name (eg, city) []: Milan
Organization Name (eg, company) []: Kernel Panic Inc.
Organizational Unit Name (eg, section) []: LDAP CA
Common Name (eg, fully qualified host name) []: ca.lan.kernel-panic.it
Email Address []: <enter>
#
接下来是为服务器创建 private key (/etc/openldap/ssl/private/server.key) 和 Certificate Signing Request (认证签名请求,/etc/openldap/ssl/private/server.csr) :
代码: 全选
# openssl req -days 3650 -nodes -new -keyout /etc/openldap/ssl/private/server.key \
> -out /etc/openldap/ssl/private/server.csr
[ ... ]
Country Name (2 letter code) []: IT
State or Province Name (full name) []: Italy
Locality Name (eg, city) []: Milan
Organization Name (eg, company) []: KP Inc.
Organizational Unit Name (eg, section) []: LDAP Server
Common Name (eg, fully qualified host name) []: ldap.kernel-panic.it
Email Address []: <enter>
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: <enter>
An optional company name []: <enter>
#
最后, CA将由签名请求生成签名认证:
代码: 全选
# openssl x509 -req -days 3650 -in /etc/openldap/ssl/private/server.csr \
> -out /etc/openldap/ssl/server.crt -CA /etc/openldap/ssl/ca.crt \
> -CAkey /etc/ssl/private/ca.key -CAcreateserial
Signature ok
subject=/C=IT/ST=Italy/L=Milan/O=Kernel Panic Inc./OU=LDAP Server/CN=ldap.kernel-panic.it
Getting CA Private Key
#
你可以通过重新最后两步生成客户端认证:
代码: 全选
# openssl req -days 3650 -nodes -new -keyout /etc/openldap/ssl/private/client.key \
> -out /etc/openldap/ssl/private/client.csr
[ ... ]
Country Name (2 letter code) []: IT
State or Province Name (full name) []: Italy
Locality Name (eg, city) []: Milan
Organization Name (eg, company) []: KP Inc.
Organizational Unit Name (eg, section) []: LDAP Client
Common Name (eg, fully qualified host name) []: ldap.kernel-panic.it
Email Address []: <enter>
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: <enter>
An optional company name []: <enter>
# openssl x509 -req -days 3650 -in /etc/openldap/ssl/private/client.csr \
> -out /etc/openldap/ssl/client.crt -CA /etc/openldap/ssl/ca.crt \
> -CAkey /etc/ssl/private/ca.key
Signature ok
subject=/C=IT/ST=Italy/L=Milan/O=Kernel Panic Inc./OU=LDAP Client/CN=ldap.kernel-panic.it
Getting CA Private Key
#
扫尾工作, 我们要限制 private keys 的访问权:
代码: 全选
# chown -R _openldap:_openldap /etc/openldap/ssl/private
# chmod 600 /etc/openldap/ssl/private/*
2.3.2 OpenLDAP 配置
要配置TLS的
slapd(8C) 进程,你只需在
slapd.conf(5) 文件里的 rootpw 参数后面添加几行内容, 包含接受的CipherSuite以及认证的路径:
文件 /etc/openldap/slapd.conf
代码: 全选
# TLS configuration
TLSCipherSuite HIGH:MEDIUM:+SSLv3
TLSCACertificateFile /etc/openldap/ssl/ca.crt
TLSCertificateFile /etc/openldap/ssl/server.crt
TLSCertificateKeyFile /etc/openldap/ssl/private/server.key
关于客户端的文件
ldap.conf(5), 你必须将方案从 URI 修改为 "ldaps" ,而且还要指出CA证书的路径和接受的 cipher suites:
文件 /etc/openldap/ldap.conf
代码: 全选
[ ... ]
URI ldaps://ldap.kernel-panic.it
# TLS configuration
TLS_CACERT /etc/openldap/ssl/ca.crt
TLS_CIPHER_SUITE HIGH:MEDIUM:+SSLv3
最后一步是给
slapd(8C) 命令添加选项 "-h ldaps:///" 以确保进程只监听来自端口636上的TCP通讯,这些通讯是经过TLS加密的LDAP数据:
文件 /etc/rc.conf.local
代码: 全选
# Only listen for LDAP over TLS (port 636)
slapd_flags="-4 -u _openldap -g _openldap -h ldaps:///"
然后重新启动
slapd(8C)。