OpenLDAP Everywhere Reloaded,第一部分
目录服务是当今计算机技术中最有趣和至关重要的部分之一。它们为我们提供账户管理、基本身份验证、地址簿以及许多其他重要应用程序配置的后端存储库。
自从 Craig Swanson 和 Matt Lung 最初撰写了他们的文章 “OpenLDAP Everywhere”(《Linux Journal》,2002 年 12 月) 以来,已经过去了漫长的九年,距离他们的后续文章 “OpenLDAP Everywhere Revisited”(《Linux Journal》,2005 年 7 月) 也已经过去了将近六年。
在本系列文章中,我将介绍如何构建 OpenLDAP 目录服务,以创建一个用于异构环境的统一登录系统。借助当前的软件和现代服务器设计方法,目标是减少目录服务单点故障的数量。
在本文中,我将描述如何配置两台 Linux 服务器来托管客户端查询目录服务所需的核心网络服务。我将配置这些核心服务,使其通过使用故障转移池和/或复制来实现高可用性。

图 1. 核心网络服务的总体视图,包括 LDAP(注意:此图中硬盘图标的图像取自 Open Icon Library Project:http://openiconlibrary.sourceforge.net。)
假设和先决条件此设计在制定时考虑了中小型企业 (SME)。如果您是小型到中型企业 (SMB) 或大型企业,您可能希望定制此设计。
本文讨论的服务器安装了最新稳定版本的 Debian GNU/Linux。在撰写本文时,这是 Debian 6.0.2.1 (Squeeze)。虽然尚未在 Ubuntu 上进行测试,但 Ubuntu 用户应该能够以 root 身份登录(运行 sudo su -
)并且几乎不会遇到任何问题。
如图 1 所示,虚构的本地域名为 example.com。存在四个虚构的子网:192.168.1.0/24、192.168.2.0/24、192.168.3.0/24 和 192.168.4.0/24。假设四个子网之间的路由工作正常。在适当的地方,请将适用值替换为您的域名、IP 地址、子网掩码地址等等。
假定 LDAP 用户在 /export/home 而不是 /home 中拥有主目录。这使得 LDAP 凭据可以兼容除 Linux 之外的操作系统。例如,许多专有的 UNIX 系统使用 /export/home 作为默认主目录。Solaris 上的 /home 也保留用于其他目的(自动挂载目录)。
该设计假设 /export/home 实际上是一个共享磁盘。
这通常实现为挂载到主机或 NAS 上的 NFS 服务器的挂载点;但是,该设计并未决定如何实现共享磁盘,这超出了本文的范围,因此我将其留给读者决定如何实现。
您可以选择不实现共享磁盘,但是如果您不这样做,则会存在一些严重的缺点。所有 LDAP 用户都将需要管理员为他们希望登录的每台服务器手动创建他们的 $HOME 目录(在他们登录之前)。此外,用户在一台服务器上创建的文件将无法在其他服务器上使用,除非用户手动将它们复制到另一台服务器。这对用户来说是一个主要的不便,并且由于数据重复,造成了服务器磁盘空间(和备份磁带空间)的浪费。
所有示例密码都设置为“linuxjournal”,并且假定您将用您自己合理的密码替换这些密码。
安装软件包在 linux01.example.com 和 linux02.example.com 上,使用您首选的软件包管理器安装 ntp、bind9、bind9utils、dnsutils、isc-dhcp-server、slapd 和 ldap-utils 软件包。
从精确计时(NTP)开始两台 Linux 服务器之间精确计时是 DHCP 故障转移的要求。拥有精确时间还有其他好处,即
-
如果您打算实施(或已经实施)使用 Kerberos 的安全身份验证,则这是必需的。
-
如果您打算将 Linux 与 Microsoft Active Directory 集成,则这是必需的。
-
如果您打算在 OpenLDAP 中使用 N 路多主复制,则这是必需的。
-
它极大地帮助了故障排除,消除了比较服务器、网络设备和客户端设备之间日志文件时间戳时的猜测。
一旦在 linux01.example.com 和 linux02.example.com 上安装了 ntp,您实际上就完成了。Debian NTP 团队为 ntp.conf(5) 创建了非常合理的默认设置。诸如 0.debian.pool.ntp.org 和 1.debian.pool.ntp.org 之类的时间源对于大多数情况都足够用。
如果您更喜欢使用自己的时间源,您可以修改 /etc/ntp.conf 中以 server
开头的行。将地址替换为您首选的时间源的地址。
您可以使用 ntpq(1) 命令在两台服务器上检查您的 ntp 配置是否正确
root@linux01:~# ntpq -p
remote refid st t when poll reac
h delay offset jitter
====================================================
==========================
+warrane.connect 130.95.179.80 2 u 728 1024 377
74.013 -19.461 111.056
+a.pool.ntp.uq.e 130.102.152.7 2 u 179 1024 377
79.178 -14.069 100.659
*ntp4.riverwillo 223.252.32.9 2 u 749 1024 377
76.930 -13.306 89.628
+c122-108-78-111 121.0.0.42 3 u 206 1024 377
78.818 6.485 72.161
root@linux01:~#
如果您的 ntpq 输出显示一组不同的服务器,请不要担心。*.pool.ntp.org 地址是 DNS 轮询记录,可在数百台不同的 NTP 服务器之间平衡 DNS 查询。重要的是检查 ntp 是否可以联系到上游 NTP 服务器。
名称解析(DNS)如果 LDAP 客户端无法解析运行 OpenLDAP 的 Linux 服务器的主机名,则它们无法连接到它们提供的目录服务。这可能包括无法检索用于身份验证的基本 UNIX 帐户信息,这将阻止用户登录。
因此,配置 ISC bind 在两台 Linux 服务器之间以主/从组合方式提供 DNS 区域。示例工作站将被配置为(通过 DHCP)查询 linux01.example.com 上的 DNS,如果第一个查询失败,则查询 linux02.example.com。
注意:/etc/bind/named.conf 通常在 bind9 软件包升级时被软件包管理器替换。Debian 的默认 named.conf(5) 具有 include /etc/bind/named.conf.local
语句,以便在那里添加的站点本地区域配置在 bind9 软件包升级时不会丢失。
在 linux01.example.com 上,修改 /etc/bind/named.conf.local 以包含以下内容
//// excerpt of named.conf.local on linux01
// --- Above output suppressed
zone "168.192.in-addr.arpa" {
type master;
file "/etc/bind/db.168.192.in-addr.arpa";
notify yes;
allow-transfer { 192.168.2.10; }; // linux02
};
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
notify yes;
allow-transfer { 192.168.2.10; }; // linux02
};
// --- Below output suppressed
在 linux01.example.com 上,创建区域文件 /etc/bind/db.168.192.in-addr.arpa 和 /etc/bind/db.example.com,并使用适当的区域信息填充它们。有关区域文件的非常基本的示例,请参阅《Linux Journal》FTP 站点上提供的示例配置文件(有关链接,请参阅“资源”)。
在将更改提交到生产 DNS 服务器之前,始终检查是否存在错误。否则会导致 named(8) 守护进程在重新启动时中止。您不希望因小错误而导致生产用户的重大中断。在 linux01.example.com 上
# named-checkconf /etc/bind/named.conf
# named-checkconf /etc/bind/named.conf.local
# named-checkzone 168.192.in-addr.arpa /etc/bind/db.
168.192.in-addr.arpa
zone 168.192.in-addr.arpa/IN: loaded serial 20111003
01
OK
# named-checkzone example.com /etc/bind/db.example.c
om
zone example.com/IN: loaded serial 2011100301
OK
#
在 linux01.example.com 上,指示 named(8) 守护进程重新加载其配置文件,然后检查它是否未中止
root@linux01:~# /etc/init.d/bind9 reload
Reloading domain name service...: bind9.
root@linux01:~# ps -ef|grep named|grep -v grep
bind 1283 1 0 16:05 ? 00:00:00 /usr
/sbin/named -u bind
root@linux01:~#
在正常操作期间,linux01.example.com 上的 named(8) 守护进程可能会中止,而服务器的其余部分将继续正常运行(即,单服务故障,而不是整个服务器故障)。由于 linux02.example.com 将拥有区域的备份副本,因此 linux01.example.com 应使用 linux02.example.com 作为其辅助 DNS 服务器。
在 linux01.example.com 上,创建和/或修改 /etc/resolv.conf。使用以下内容填充它
search example.com
nameserver 127.0.0.1
nameserver 192.168.2.10
在 linux01.example.com 上,检查并在必要时修改 /etc/nsswitch.conf 以包含以下“hosts”定义。这一行已经为我设置好了,但如果它不存在,则严格来说您确实需要它
## /etc/nsswitch.conf on linux01 & linux02
# --- Above output suppressed
hosts: files dns
# --- Below output suppressed
最后,测试 linux01.example.com 是否可以从 DNS 服务器解析记录
root@linux01:~# dig linux02.example.com +short
192.168.2.10
root@linux01:~# dig -x 192.168.2.10 +short
linux02.example.com.
root@linux01:~# nslookup linux02.example.com
Server: 127.0.0.1
Address: 127.0.0.1#53
Name: linux02.example.com
Address: 192.168.2.10
root@linux01:~# nslookup 192.168.2.10
Server: 127.0.0.1
Address: 127.0.0.1#53
10.2.168.192.in-addr.arpa name = linux01.example.com.
root@linux01:~#
现在,将 linux02.example.com 配置为从服务器。首先,修改 /etc/bind/named.conf.local 以包含以下内容
//// excerpt of named.conf.local on linux02
// --- Above output suppressed
zone "168.192.in-addr.arpa" {
type slave;
file "/var/lib/bind/db.168.192.in-addr.arpa";
masters { 192.168.1.10; }; // the linux01 server
};
zone "example.com" {
type slave;
file "/var/lib/bind/db.example.com";
masters { 192.168.1.10; }; // the linux01 server
};
// --- Below output suppressed
请仔细注意从服务器区域文件在 /var/lib/bind 中的位置,而不是在 /etc/bind 中!
此更改有两个原因。首先,/etc/bind 被限制了严格的权限,因此 named(8) 无法在那里写入任何文件。linux02.example.com 上的 named(8) 不能也不应该在那里写入传输的区域文件。
其次,/var 分区有意指定用于随着时间推移而增长的文件。/var/lib/bind 是 Debian 选择的用于 named(8) 存储此类文件的目录。
请抵制更改权限以“修复”/etc/bind 的冲动!我再怎么强调也不为过。它不仅会危及您的 RNDC 密钥文件的安全性,而且 dpkg 软件包管理器很可能会在下次 bind9 软件包升级时恢复您对 /etc/bind 所做的任何更改。
如果您需要两个服务器都存储其区域文件的单个位置,则最好将 linux01.example.com 上的本地区域文件移动到 /var/lib/bind,而不是强制更改 linux02.example.com 上的 /etc/bind。不要忘记相应地更新 linux01.example.com 的 /etc/bind/named.conf.local 中区域文件的路径。
在 linux02.example.com 上,运行 named-checkconf(1) 以检查新配置,就像您之前为 linux01.example.com 所做的那样。如果新配置检查通过,请告诉 named(8) 通过运行 /etc/init.d/bind9 reload
命令重新加载。还要检查守护进程是否未中止,方法是像以前一样运行 ps -ef|grep named|grep -v grep
。
如果从 linux01.example.com 的区域传输成功,您应该在 linux02.example.com 上的 /var/log/syslog 中看到类似以下内容
# --- above output suppressed ---
Oct 3 20:37:11 linux02 named[1253]: transfer of '168
.192.in-addr.arpa/IN' from 192.168.1.10#53: connected
using 192.168.2.10#35988
--- output suppressed ---
Oct 3 20:37:11 linux02 named[1253]: transfer of '168
.192.in-addr.arpa/IN' from 192.168.1.10#53: Transfer
completed: 1 messages, 12 records, 373 bytes, 0.001
secs (373000 bytes/sec)
--- output suppressed ---
Oct 3 20:37:12 linux02 named[1253]: transfer of 'exa
mple.com/IN' from 192.168.1.10#53: connected using 1
92.168.2.10#41155
--- output suppressed ---
Oct 3 20:37:12 linux02 named[1253]: transfer of 'exa
mple.com/IN' from 192.168.1.10#53: Transfer complete
d: 1 messages, 12 records, 336 bytes, 0.001 secs (33
6000 bytes/sec)
# --- below output suppressed ---
在 linux02.example.com 上,创建和/或修改 /etc/resolv.conf。使用以下内容填充它
search example.com
nameserver 127.0.0.1
nameserver 192.168.1.10
这是网络上唯一将 linux02.example.com 作为其主 DNS 服务器的设备。这样做是为了提高性能,假设 linux01.example.com 将首先发生故障。当然,您永远无法预测哪台服务器会先发生故障。但是,如果 linux02.example.com 碰巧先发生故障,则工作站理论上不会注意到它 - DHCP 告诉它们在 linux02.example.com 之前查询 linux01.example.com。
现在,在 linux02.example.com 上,检查并在必要时修改 /etc/nsswitch.conf 以包含 hosts: files dns
,方式与之前执行的相同。检查 dig(1) 和 nslookup(1) 是否可以像以前一样解析 linux01.example.com。
如果您的 LDAP 客户端无法接收用于与网络通信的 IP 地址,则它们无法与 OpenLDAP 服务器通信。
因此,配置 ISC dhcpd 以在两台 Linux 服务器之间使用故障转移池。这确保了 IP 地址始终被分配给客户端。它还确保了两台 Linux 服务器不会将重复的地址分配给工作站。
在撰写本文时,ISC 仍在开发 dhcpd 的故障转移协议,但将来可能会发生更改。它在当前状态下大部分时间都能正常工作,并且它是降低目录服务服务器故障风险的重要组成部分。
通过运行命令 touch /etc/dhcp/dhcpd.conf.failover
在 linux01.example.com 和 linux02.example.com 上创建一个新文件。
将特定于故障转移的配置与主 /etc/dhcp/dhcpd.conf 文件分开。这样,/etc/dhcp/dhcpd.conf 可以在两台服务器之间同步,而不会破坏“failover peer”节中的唯一配置。您永远不应在两台 Linux 服务器之间同步 /etc/dhcp/dhcpd.conf.failover。
在 linux01.example.com 上,按如下方式填充 /etc/dhcp/dhcpd.conf.failover
failover peer "dhcp-failover" {
primary;
address linux01.example.com;
port 519;
peer address linux02.example.com;
peer port 520;
max-response-delay 60;
max-unacked-updates 10;
load balance max seconds 3;
mclt 3600;
split 128;
}
请注意,参数 split
和 mclt
仅在主服务器 linux01.example.com 上指定。
max-response-delay
控制一台服务器在假定发生故障之前等待另一台服务器通信的秒数。
split
控制池中可用的 IP 地址中有多少预先分配给每台 DHCP 服务器。唯一有效的值是 0 到 255。如示例所示,split 128;
值表示每台服务器占用整个池中 50% 的租约。
在 linux02.example.com 上,按如下方式填充 /etc/dhcp/dhcpd.conf.failover
failover peer "dhcp-failover" {
secondary;
address linux02.example.com;
port 520;
peer address linux01.example.com;
peer port 519;
max-response-delay 60;
max-unacked-updates 10;
load balance max seconds 3;
}
注意:在撰写本文时,IANA 尚未为 ISC dhcpd 故障转移分配保留的端口号。这意味着端口/对等端口号 519 和 520 可能会更改。
在 linux01.example.com 和 linux02.example.com 上,您现在应该使用适当的子网信息填充 /etc/dhcp/dhcpd.conf。有关 dhcpd.conf 的非常基本的示例,请参阅“资源”部分中提供的示例配置文件。
/etc/dhcp/dhcpd.conf 中需要包含的关键参数是
# excerpt of dhcpd.conf on linux01 and linux02
#-----------------
# Global DHCP parameters
#-----------------
# --- outputs heavily suppressed ----
#-----------------
# Failover parameters
#-----------------
include "/etc/dhcp/dhcpd.conf.failover";
# --- outputs heavily suppressed ---
subnet 192.168.3.0 netmask 255.255.255.0 {
option routers 192.168.3.1;
option subnet-mask 255.255.255.0;
option broadcast-address 255.255.255.255;
pool {
failover peer "dhcp-failover";
range 192.168.3.20 192.168.3.250;
}
}
subnet 192.168.4.0 netmask 255.255.255.0 {
option routers 192.168.4.1;
option subnet-mask 255.255.255.0;
option broadcast-address 255.255.255.255;
pool {
failover peer "dhcp-failover";
range 192.168.4.20 192.168.4.250;
}
}
仅这些参数不足以启动并运行新的 DHCP 服务器。但是,一旦为您的网络构建了可用的 dhcpd.conf,请添加上述参数以进行 DHCP 故障转移。
在 linux01.example.com 和 linux02.example.com 上重新启动 dhcpd(8)。通过运行命令 /etc/init.d/isc-dhcp-server restart
来执行此操作。检查 dhcpd(8) 进程是否未中止,方法是运行 ps -ef|grep dhcpd|grep -v grep
。
如果 dhcpd(8) 不再运行,则问题通常是拼写错误。在 dhcpd.conf 和 dhcpd.conf.failover 中重新检查每个左括号({ 字符)是否都有一个右括号(} 字符)。还要检查不以左/右括号结尾的行是否以分号 (;) 结尾。
检查两台服务器上的 /var/log/syslog 以查找来自 dhcpd 的消息。当 DHCP 故障转移工作时,两台服务器都应说明池“已平衡”,并且“我从通信中断状态变为正常状态”或“我从启动状态变为正常状态”。
每次修改 /etc/dhcp/dhcpd.conf 时,都将其从 linux01.example.com 同步到 linux02.example.com。这可以手动完成,可以通过 rsync(1) 脚本、通过 puppetd(8) 或通过网络信息服务(尽管我不建议使用 NIS - 它不安全并且已被 DNS/LDAP 和 rsync/puppet 取代)。
故障转移协议的缺点是,它离被认为是成熟的协议还有很长的路要走。在许多奇怪的情况下,该协议都无法完成其工作。但是,它不会永远年轻,并且当它确实工作时,它会很好地工作。我建议您监控您的日志并注册 ISC 的 dhcp-users 邮件列表,以便在出现问题时获得帮助(有关链接,请参阅“资源”)。
关于 DHCP 故障转移协议的最后一点说明:如果您的一个子网上的设备数量超过池范围中可用总量的 50%,请在实施 DHCP 故障转移之前认真考虑重新设计您的网络。
该协议本质上依赖于拥有过多的可用地址来分配,即使在池范围被 split 128;
减半之后也是如此。
在大多数情况下,C 类子网中 DHCP 可用的最大 IP 地址数量为 253 个(255 个地址,减去 1 个广播地址,减去 1 个路由器地址)。
如果您在一个故障转移子网中有超过 126 个设备,请将其拆分为更多子网(例如,每层楼一个子网),或者使用比 C 类更大的子网。在 /etc/dhcpd.conf 中配置子网声明以相应地增加其池范围。这将为您以后节省麻烦。
现在 DHCP 服务器已配置了故障转移池,最后要做的是配置 192.168.3.0/24 和 192.168.4.0/24,以通过 LAN/WAN 将 DHCP 客户端广播转发到 192.168.1.10 和 192.168.2.10。
这在 router03.example.com 上通过 IP Helper 地址完成。在 linux03.example.com 上,它通过 ISC 的 DHCP Relay Agent 完成。
假设 router03.example.com 是 Cisco Catalyst 多层交换机。通过进入特权模式(运行 enable
命令)来配置 IP Helper 地址。使用 ip helper-address
命令,将两个 DHCP 服务器 IP 地址应用于具有 192.168.3.1/24 地址的路由器接口。在我的实验室中的 Catalyst 3750G 上,这是接口“vlan20”。命令的应用方式如下
router03#show running-config
Building configuration...
--- output suppressed ---
interface Vlan20
description linuxjournal_vlan
ip address 192.168.3.1 255.255.255.0
end
--- output suppressed ---
router03#configure terminal
router03(config)#interface vlan 20
router03(config-if)#ip helper-address 192.168.1.10
router03(config-if)#ip helper-address 192.168.2.10
router03(config-if)#end
router03#copy running-config startup-config
Destination filename [startup-config]?
Building configuration...
[OK]
0 bytes copied in 8.715 secs (0 bytes/sec)
router03#show running-config interface vlan 20
Building configuration...
Current configuration : 154 bytes
!
interface Vlan20
description linuxjournal_vlan
ip address 192.168.3.1 255.255.255.0
ip helper-address 192.168.1.10
ip helper-address 192.168.2.10
end
router03#
在 linux03.example.com 上,您需要安装 isc-debian-relay 软件包。安装后,它将询问“是否将多个服务器名称作为空格分隔的列表提供”。输入“linux01.example.com linux02.example.com”,或者如果此主机未配置为从我们的 DNS 服务器对解析,则输入“192.168.1.10 192.168.2.10”。它将询问在哪个接口上侦听。如果您没有偏好,请将其留空并按 Enter 键。它将要求您指定其他选项,但您可以直接按 Enter 键。
如果您犯了错误,可以通过运行命令 dpkg-reconfigure isc-dhcp-relay
或修改 /etc/default/isc-dhcp-relay 中的 SERVERS
变量来重新配置。
现在,您的 DHCP 客户端应该能够联系到任何一台 DHCP 服务器。
在本系列的第二部分中,我将解释如何在两台 Linux 服务器上配置 OpenLDAP,并开始使用数据填充目录。
资源本文的示例配置文件: ftp://ftp.linuxjournal.com/pub/lj/listings/issue216/11148.tgz
Debian GNU/Linux: http://www.debian.org/distrib
下载 Debian 6.0.2.1: http://cdimage.debian.org/debian-cd/6.0.2.1
ntp.conf(5) 手册页: http://linux.die.net/man/5/ntp.conf
named.conf(5) 手册页: http://linux.die.net/man/5/named.conf
dhcpd.conf(5) 手册页: http://linux.die.net/man/5/dhcpd.conf
dhcp-options(5) 手册页: http://linux.die.net/man/5/dhcp-options
ISC dhcp-users 邮件列表: https://lists.isc.org/mailman/listinfo/dhcp-users
Cisco IOS 12.3 T 命令参考,针对 Idle 到 IP local-proxy-arp(包括 ip helper-address
): http://www.cisco.com/en/US/docs/ios/12_3t/ip_addr/command/reference/ip1_i1gt.html