当某个组织添加应用程序和服务时,集中进行认证和密码服务可以提高安全性,并减少管理和开发人员的难题。但是,将所有服务合并到一台服务器会导致可靠性问题。高可用性对于企业认证服务尤为重要,因为在许多情况下,当认证停止工作时,整个企业将陷于停顿。本文描述了我们该如何使用开放源码软件创建可靠的、高度可用的认证服务器。
我们使用的开放源码软件
我们使用 LDAp(轻量级目录访问协议(Lightweight Directory Access protocol))服务器来提供各种应用程序都可以订阅的认证服务。为了提供高度可用的 LDAp 服务器,我们使用了 Linux-HA 倡议(www.linux-ha.org)的 heartbeat 软件包。我们还提供了一个设置 Apache web 服务器以使用 LDAp 认证的示例。
有关 LDAp 的一些背景知识
我们使用 OpenLDAp 软件包(www.openldap.org),几个 Linux 分发版(distribution)都包含该软件包。它同 RedHat 7.1 一起提供,目前可下载的版本是 2.0.11。
RFC 2251 和 2253 定义了 LDAp 标准。现有的几个 LDAp 商业实现包括密歇根大学和 Netscape 实现。创建 OpenLDAp 基金会是要“共同致力于开发健壮的、商业级别的、功能完善的和开放源码的 LDAp 应用程序和开发工具套件”(请参阅 www.openldap.org)。OpenLDAp 版本 1.0 发布于 1998 年 8 月。目前的主要版本是 2.0,发布于 2000 年 8 月 31 日,并且添加了 LDApv3 支持。
象任何优秀的网络服务一样,LDAp 被设计成可以跨多个服务器运行。本文使用了 LDAp 的两个功能 ― 复制和参照。
参照机制允许您跨多个服务器分割 LDAp 名称空间,并且以层次结构的方式安排 LDAp 服务器。对于特定的目录名称空间,LDAp 只允许有一个主服务器。
复制是由 OpenLDAp 复制守护程序 slurpd 驱动的。Slurpd 会定期运行,检查主服务器的日志文件以获知任何更新。然后将更新推送到从服务器。读取请求可以由任一服务器应答,而更新只能由主服务器执行。对从服务器的更新请求会生成一个参照消息,该消息将提供主服务器的地址。跟踪参照及重新尝试更新是客户机的职责。OpenLDAp 无内置的方法来分发跨复制服务器的查询,因此您必须使用 Ip 喷射器(sprayer)/扇出(fanout)程序,例如 balance。
为了实现可靠性目标,我们将两台服务器连在一起形成群集。我们可以使用服务器之间共享的存储器和一份可维护的数据副本。但是为了简单起见,我们选择执行非共享实现。LDAp 数据库通常很小,且更新频率很低(提示:如果您的 LDAp 数据集是大型的,请考虑利用参照将名称空间划分成多个较小的部分)。当重新启动故障节点时,非共享设置确实需要多费心一些:在重新启动之前,任何新的更改都必须添加到发生故障的节点的数据库中。稍后我们将显示一个示例。
群集软件和配置
首先,让我们澄清一个小小的混淆。大多数 HA(高可用性)群集都带有称为“心跳(heartbeat)”的系统持活功能。HA 软件使用心跳来监控群集中节点的“健康”状况。Linux-HA(www.linux-ha.org)小组提供了开放源码群集软件。他们的软件包称为 Heartbeat(目前是 Heartbeat-0.4.9)。这会导致一些可以理解的混淆(是的,它有时就令我困惑)。本文将 Linux-HA 软件包称为“Heartbeat”,而将一般的概念称为“心跳”。
Linux-HA 项目开始于 1998 年,是 Linux-HA HOWTO(Haranld Milz 著)的产物。该项目目前由 Alan Robertson 领导,许多其他代码提供者也参与其中。版本 0.4.9 于 2001 年初发布。
Heartbeat 通过通信介质(通常是串行设备和以太网)监控节点的“健康”状况。最好有多个冗余介质,以便我们既可以使用串行线又可以使用以太网链接。每个节点运行一个守护程序进程(称为“心跳”)。主守护程序派生出读和写每个心跳介质的子进程,以及状态进程。当检测到某个节点发生故障时,Heartbeat 运行 shell 脚本来启动(或停止)辅助节点上的服务。按照设计,这些脚本使用与系统 init 脚本(通常位于 /etc/init.d 中)相同的语法。缺省脚本是为文件系统、Web 服务器和虚拟 Ip 故障转移提供的。
假定有两个匹配的 LDAp 服务器,我们可以使用几个配置。首先,我们可以进行“冷备用(cold standby)”。主节点拥有一个虚拟 Ip 和一个运行的服务器。辅助节点将处于空闲状态。一旦主节点发生故障,服务器实例和 Ip 将转移到“冷”节点。这实现起来很简单,但是主服务器和辅助服务器之间的数据同步可能是个问题。为了解决这个问题,我们可以利用两个节点上的活动服务器配置群集。主节点运行主 LDAp 服务器,辅助节点运行从实例。对主服务器的更新会立即通过 slurpd 推送到从服务器。
主节点发生故障后,由辅助节点响应查询,但是现在我们还不能更新。为了能够进行更新,在故障转移时,我们将重新启动辅助服务器,并将它提升为主服务器。
这为我们提供了完整的 LDAp 服务,但是增加了 gotcha 问题 ― 如果更新是对辅助服务器进行的,则在允许主服务器重新启动之前,我们将不得不对其进行修正。Heartbeat 支持“良好的故障回复”选项,它可以禁止故障节点在故障转移后重新获取资源,我们可以将其设为首选项。本文将演示用手工进行的重新启动。我们的样本配置将使用 Heartbeat 提供的虚拟 Ip 工具。如果需要支持繁重的查询负载,则利用 Ip 喷射器代替虚拟 Ip,将查询分摊给主和从服务器。在这样的情况下,对从服务器的更新请求将产生一个参照。对参照的后继操作不是自动的;该功能必须内置到客户机应用程序中。除了复制伪指令外,主节点和从节点的其余配置是相同的。主配置文件指明复制日志文件的位置(第 16 行)并包含从服务器的清单,这些服务器是带有凭证信息的复制对象。(第 34-36 行)。
34
replica host=slave5:389
35
binddn="cn=Manager,dc=lcc,dc=ibm,dc=com";
36
bindmethod=simple credentials=secret
从配置文件未指明主服务器;而是列出了复制所需的凭证。(第 33 行)
33
updatedn "cn=Manager,dc=lcc,dc=ibm,dc=com"
一般 Heartbeat 准备
可用的基本 Heartbeat 配置有几个很好的示例(请参阅本文结尾处的参考资料)。下面是我们配置中的一些相关内容。我们的配置非常简单,所以内容也不多。缺省情况下,所有配置文件都保存在 /etc/ha.d/ 中。
ha.cf 包含群集的全局定义。对于所有超时,我们都使用缺省值。
# Timeout intervals
keepalive 2
# keepalive could be set to 1 second here
deadtime 10
initdead 120
# define our communications
#
serial
serialportname ...
serial
/dev/ttyS0
baud
19200
# Ethernet information
udpport 694
udp
eth1
# and finally, our node id's
#
node
nodename ...
-- must match uname -n
node
slave5
node
slave6
haresources 这是配置故障转移的地方。令人感兴趣的内容位于该文件的底部。
slave6 192.168.10.51 slapd
这里我们表明了三件事。资源的主要所有者是节点“slave6”(该名称必须与您打算将其作为主节点的机器的“uname -n”输出相符)。服务地址(虚拟 Ip)是“192.168.10.51”(该示例是在专用实验室网络上完成的,因此使用 192.168 这样的地址)。服务脚本称为“slapd”。Hearbeat 将在 /etc/ha.d/resource.d 和 /etc/init.d 中查找脚本。
服务脚本
对于简单的冷备用案例,我们可以使用标准的 /etc/init.d/slapd 脚本而无需做更改。但是我们希望执行特别的功能,所以我们创建了自己的 slapd 脚本,该脚本存储在 /etc/ha.d/resource.d/ 中。Heartbeat 将该目录作为它搜索路径中的第一个,因此我们无需担心会运行 /etc/init.d/slapd 脚本。但是,您应当检查以确定在引导时不再启动 slapd(从您的 /etc/rc.d 树除去任何 S*slapd 文件)。首先,在第 17 和 18 行我们指明 slapd 服务器的启动配置文件。
该脚本遵循标准 init.d 语法,因此启动信息包含在从第 21 行开始的 test_start() 函数中。首先我们停止所有当前正在运行的 slapd 实例。在第 39 行我们利用主配置文件启动主服务器。我们的设计将遵循这样的规则:如果主节点和辅助节点都在运行,则在主节点上启动 slapd 作为主服务器,在辅助节点上启动 slapd 作为从服务器,并启动复制守护程序。如果仅有一个节点在运行,则启动 slapd 作为主服务器。虚拟 Ip 依赖于 slapd 主服务器。为了完成该操作,我们必须知道哪个节点正在执行脚本,并且如果我们位于主节点,那么我们需要知道辅助节点的状态。重要的内容位于脚本的“start”分支。因为我们已经在 Heartbeat 配置中指明了主节点,所以我们知道,当 test_start() 函数运行时,它是在 Heartbeat 的主节点上运行的(因为 Heartbeat 使用了 /etc/init.d/ 脚本,所以所有脚本都是利用参数“start|stop|restart”调用的)。当调用脚本时,Heartbeat 会设置许多环境变量。下面是一个我们感兴趣的环境变量:
HA_CURHOST=slave6
我们可以使用“HA_CURHOST”值来告诉我们,何时正在主节点(slave6)上执行,何时正在进行故障转移(此时 HA_CURHOST 的值为“slave5”)。现在我们需要