OpenLDAP Everywhere Reloaded,第一部分

作者: Stewart Walters

目录服务是当今计算机技术中最有趣和至关重要的部分之一。它们为我们提供账户管理、基本身份验证、地址簿以及许多其他重要应用程序配置的后端存储库。

自从 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。

IP 地址分配 (DHCP)

如果您的 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;
}

请注意,参数 splitmclt 仅在主服务器 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

加载 Disqus 评论