本文紧接《常用的Linux 可插拔认证模块(PAM)应用举例(一)》,继续介绍其他常用的Linux 可插拔认证模块(PAM)。
pam_tally.so 模块
pam_tally.so 模块也是在系统中经常使用的一个 pam 模块。其主要作用是监控用户的不成功登录尝试的次数,在达到模块限制的次数时会锁定用户一段时间以防止一些黑客软件的暴力破解。
pam_tally.so 模块的使用方法和刚才一样,也是需要通过修改 /etc/pam.d/system-auth 来实现相关功能。
例如要实现这样的功能:用户登录时候可以允许三次输入错误密码尝试,如果三次密码输入都错误会锁定用户并且将其登录行为记录到 /var/log/faillog 文件(或者可以自定义日志文件)中。
具体的修改方法是将下面的这两行分别加入 auth 和 account 部分:
auth required /lib/security/pam_tally.so onerr=fail no_magic_root account required /lib/security/pam_tally.so deny=3 no_magic_root reset
另外在顺序方面最好能够将刚才的配置项放到 sufficient 之前,修改之后的全文如下:
[root@localhost log]# cat /etc/pam.d/system-auth #%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. auth required /lib/security/$ISA/pam_env.so auth required /lib/security/pam_tally.so onerr=fail no_magic_root auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok auth required /lib/security/$ISA/pam_deny.so account required /lib/security/$ISA/pam_unix.so account required /lib/security/pam_tally.so deny=3 no_magic_root reset account sufficient /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet account required /lib/security/$ISA/pam_permit.so password requisite /lib/security/$ISA/pam_cracklib.so retry=3 password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow password required /lib/security/$ISA/pam_deny.so session required /lib/security/$ISA/pam_limits.so session required /lib/security/$ISA/pam_unix.so
并且手工建立 /var/log/faillog 文件用以记录多次尝试登录的用户信息。
在测试的时候可以发现,如果用户使用错误的密码连续登录三次,该账号将被锁定 lock_time 所定义的时间。如果用户使用正确的密码登录,再退出使用错误的密码连续登录三次,之后返回再次使用正确的密码登录也会出现 authentication fail 的错误提示,同时登录的控制台被记录到了 /var/log/faillog 文件中。
[root@localhost log]# strings faillog tty2 tty2
在刚才的例子中 deny 表示三次错误输入密码则认证失败,reset 表示一旦成功输入密码则允许。
pam_winbind.so 模块:
pam_winbind.so 模块一般用于混和集中式认证环境的用户认证中。所谓混合集中式认证一般指的是当在企业环境中拥有大量不同类型的操作系统,例如不同数量的 Windows,Linux,Unix 服务器,此时通过一些配置方案,可以使用户能够通过一个账户口令登录和访问所有类型的操作系统。典型的实现方式是使用 Windows Server 自带的活动目录来存放和管理用户,而将所有的其它服务器和操作系统都加入到 Windows 的认证域中,这样这些操作系统上的登录用户不光可以支持本地的用户登录,还可以通过 LDAP 查找和支持目录服务中的用户登录。
而 Winbind 就是应用于这种环境的典型方案之一。Winbind 实际上是 Samba 软件包的一款组件,在 RHEL 系统下被包含在了 samba-common 包中。Winbind 在 Linux 上实现了对微软产品通讯的 RPC 调用、可插拔验证模块和名字服务切换,通过 Samba 接口与 Windows 域控制器获得联系,可以使 Windows 域用户能在 Linux 主机上以 Linux 用户身份方式进行操作。通过设定 Linux 服务器的 name service switch 配置可以让系统通过 Winbind 程序来解析用户信息。最终实现的效果就是可以使用 Windows 的活动目录来集中存放用户,这些用户只要通过活动目录认证就可以同时在 Windows 服务器和 Linux 服务器上登录以及使用相关的系统资源。
为了说明 winbind 组件和 winbind.so 模块的用法,下面我们将介绍一个结合 Windows Server 2008 和 RHEL 5 实现的集中式认证环境的配置案例。Windows Server 2003 通过自带的活动目录(Active Directory)充当目录服务器,而 RHEL 5 会利用其自带的 Samba 软件包提供的 winbind 组件从活动目录中获取用户和认证信息进行认证。
下面我们将开始正式进入实际操作部分。按照以往的惯例,在动手之前有必要介绍一下拓扑结构、目标和大致的操作步骤。
例如:我将构建一个叫做 jerrywjl.com 的域作为一个公司基本的管理单位,并且在该域中安装了 W2K8E 的服务器将升级为域控制器和 KDC 服务器,由于微软活动目录需要依靠 DNS 命名空间定位资源,所以升级域控制器的操作需要事先有 DNS 服务器的支持。考虑到升级过程中活动目录会动态更新 DNS 服务器的各种资源记录,为了简化配置的难度,我将域控制器和 DNS 服务器放置在同一台主机上。即需要在该服务器上事先建立 DNS 服务。
所有其它本网络内的服务器都安装 RHEL5U2 系统,并通过配置加入到这个域网络环境中。由于硬件数量有限,所以服务器 server.jerrywjl.com 同时充当文件服务器、邮件服务器以及 FTP 服务器。这个需求可以通过在 DNS 服务器上指派多个别名来实现。所有的 Linux 服务器加入到 Windows 域内意味着对这些服务的访问要通过活动目录中的 Kerberos 认证,只有通过认证的域内用户才可以访问活动目录之内上述资源。
而其中比较特殊的是 squid.jerrywjl.com 是代理服务器,该服务器有两个接口,是内部网络用户访问外部的唯一合法出口。为了提高安全性,要求所有用户在使用该代理服务器之前先通过基本认证核实域内用户身份,通过认证的用户才能使用代理服务器访问外部网络。
现在正式开始。
第一步操作:构建和配置 Windows Server 2008 Enterprise Edition 服务器,并将该服务器升级为域控制器。
W2K8E 的安装和以前版本有很大差异,首先在硬件方面,要求针对 32bit 版本至少要有 512M 内存和 16G 以上硬盘空间。在安装系统完成之后首次登录会以 administrator 身份进行,但必须要修改 administrator 用户的密码并满足包含字母、数字、特殊符号和最小七位的复杂度需求。由于这一部分操作比较简单,所以我就不花时间做过多介绍。在系统安装完成之后需要进行基本的网络配置。选择“start”并点击“network”之后选择“network and sharing center”然后是“manage network connections”开启“local area connections”最后选择“properties”,将 IP 地址修改为 192.168.10.100,DNS 地址指向本机,同时修改主机名为 w2k8e,采用的域名后缀为 jerrywjl.com。方法是选择“start”并右键点击“computer”并选择“properity”,在“system”属性中选择“advanced system setting”,之后点击“computer name”标签并选择“change”输入新的主机名并选择“more”来更改 dns suffix。这一步操作在完成之后需要重启系统以生效。
在系统重启之后,点击“start”选择“cmd”并输入“dcpromo”,该命令即将把本服务器升级为域控制器。点击“next”之后点击“create a new domain in a new forest”,表示该域控制器将是整个域林的第一台域控制器。然后输入要添加的域名 jerrywjl.com 并选择下一步,在域的兼容模式中使用 windows server 2008。进入下一步是 DNS 服务器的配置,众所周知升级活动目录必须要在网络中有 DNS 的支持,和 W2K3E 不同的是 W2K8E 将 DNS 的配置过程集成到了域控制器的升级过程中,所以只需要声明 DNS 服务器的地址,域控制器在升级完成之后也自动完成了 DNS 服务器的配置。确定之后将会弹出一个要求建立 DNS 委派的对话框,可以一路确定继续进行下去。
下面的接口就要求指定域控制器数据库、日志和系统文件的位置,这里都保持默认即可。在下面的步骤中将要指定一个还原模式的密码,也就是说如果该服务器从域控制器降级为普通服务器,需要输入该密码之后方可进行。到此为止,所有的信息都已经收集完成,下一步会给出一个信息汇总,之后点击“Next”将开始升级域控制器。在升级完成之后必须要按照要求重启系统以使所有配置生效。重启完成之后,系统的架构将发生重大改变,该服务器已经由一台普通的工作组中的计算机提升为域控制器。原来的管理员 administrator 也由普通的工作组内管理员提升为集域、企业、架构管理员权限于一身的 administrator。在重启完成之后,有几个重要的标志用以确认该服务器的角色提升成功。如查看计算机名称的时候将发现该计算机已经加入域内,并且在“administrative tools”中看到增加了一些新的工具,如“Active Directory Users and Computers”和“Active Directory Site and Services”等。到此为止,在 W2K8E 上的域控制器升级的工作则顺利完成。
在配置其它的 Red Hat 服务器之前,由于 W2K8E 也是 DNS 服务器,所以需要在该服务器上增加 RHEL 所有服务器的 A(主机)记录和 CNAME(别名)记录,这样所有的域内资源都可以域名的方式去访问。具体的方法是在 W2K8E 上点击“start”并点击“run”在出现的命令行对话框中输入“dnsmgmt.msc”以开启 DNS 管理配置工具。然后在 jerrywjl.com 下中的空白区域右键点击并选择“New Host(A or AAAA)”然后输入相应主机名和 IP 地址,分别是 server.jerrywjl.com 和 squid.jerrywjl.com,再为 server.jerrywjl.com 建立别名 ftp,mail。完成之后可以在命令行中执行 nslookup 进行解析测试,如果能够正向解析到所有记录则表明 DNS 和各种资源记录都没有问题。另外,如果需要的话可以在 DNS 管理配置工具中建立反向区域和添加相应的 PTR 指针与 CNAME 记录。
到此为止在 W2K8E 上的配置就暂时告一段落。下面开始配置第一台 RHEL5U2 服务器。 首先指定基本信息,包括指定本机的 IP 地址和 DNS 服务器地址,同时比较重要的是保证 RHEL 和 W2K8E 的系统时间吻合,因为在 Kerberos 的工作流程中需要依靠时间戳来作为认证流程中的一个重要依据。所以我制定一个简单的任务计划使 RHEL 作为时间客户端并每隔十分钟到服务器同步并校正自己的时钟。
下面将要修改 /etc/krb5.conf 文件。如果 Linux 系统要配置通过 Kerberos 认证,/etc/krb5.conf 文件十分重要。该文件包含了所有的 Kerberos 的基本配置信息。其中所谓的 realm 也称为 Kerberos 的认证领域,在大多数情况下 Kerberos 认证领域和 DNS 解析到的域名空间一致,只不过在 /etc/krb5.conf 中 Kerberos 认证领域需要大写,所以该档修改之后的结果如下:
[logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmind.log [libdefaults] default_realm = JERRYWJL.COM dns_lookup_realm = false dns_lookup_kdc = false ticket_lifetime = 24h forwardable = yes [realms] JERRYWJL.COM = { kdc = w2k8e.jerrywjl.com:88 admin_server = w2k8e.jerrywjl.com:749 default_domain = jerrywjl.com } [domain_realm] .jerrywjl.com = JERRYWJL.COM jerrywjl.com = JERRYWJL.COM [appdefaults] pam = { debug = false ticket_lifetime = 36000 renew_lifetime = 36000 forwardable = true krb4_convert = false }
然后进入 /etc/samba 目录下,备份保存原有配置文件 smb.conf,然后修改该配置文件并加入新的内容。其中 security = ads 指定该服务器的验证源为 Windows 2003 以上版本的域控制器,password server 用于指定该域控制器的地址以及相应的 Kerberos realm。
security = ads password server = 192.168.10.100 realm = JERRYWJL.COM
接着是指定使用 Winbind 服务所需要的信息。
在下面的 Winbind 配置信息中的“idmap uid”和“idmap gid”指定了一个用户 ID 范围。该 ID 范围实际上是 Winbind 从 Windows 的活动目录中获取用户信息之后该用户和相应组在 Linux 系统的 id 值映像范围,“winbind enum users”和“winbind enum groups”表示是否通过 winbind 列举活动目录中的用户和组。而“winbind separator”则用于指定映像的用户或者是服务器名称和 Kerberos realm 名称之间所使用的连接符号,默认是\,如果改成 + 则表示通过 Winbind 获得的用户名称格式是“DOMAIN + user”以及“DOMAIN + group”而“template homedir”,“template shell”表示通过 winbind 获得的域用户在 Linux 系统中登录所使用的主目录位置以及登录 shell,“winbind use default domain”表示用户名称将以何种方式被转换或映射。所以我对 Winbind 部分的配置如下:
idmap uid = 100000-200000 idmap gid = 100000-300000 winbind enum groups = yes winbind enum users = yes winbind separator = + template homedir = /home/%D/%U template shell = /bin/bash winbind use default domain = no
对该档保存退出。然后还要修改一个关键的配置文件 /etc/nsswitch.conf,将原有的:
passwd: files shadow: files group: files
修改为:
passwd: files winbind shadow: files group: files winbind
表示该服务器在验证用户登录的时候,如果用户不在本地用户数据库中则会自动通过 winbind 来搜索 windows 活动目录内的用户数据库。/etc/nsswitch.conf 是 NSS 即 Name Service Switch 的配置文件。
保存之后可以重新启动 samba 和 winbind 服务,并使这两个服务在系统启动的时候自动启动。然后以 Windows 管理员 administrator 的身份执行 kinit 命令以从 W2K8E 上获得 Kerberos 的 TGT 票据。方法是执行命令:
# kinit administrator@JERRYWJL.COM
该命令执行成功没有任何提示,但即说明了已经正常获得了 TGT 票据。这里比较常见的错误是会出现诸如“Clock skew too great while getting initial credentials”这样的信息,最有可能的原因是当前系统和 KDC 服务器的时间差过大而导致获取 TGT 票据失败,因此需要检查一下两台主机的时钟。
如果上述命令执行无误,可以执行命令 net ads join 将 RHEL 加入到 Windows 域内。
# net ads join –U administrator
加入成功之后要确保在当前系统上执行 wbinfo –t 无错误信息提示:
# wbinfo –t
命令 wbinfo 的功能是从 winbind daemon 中查询所获得的信息。而 -t 选项用于验证当前的 Linux 服务器加入到 Windows 域内之后是否在域内建立了可信任的服务器账号。如果有报错信息的话,可能需要重启一下 winbind 服务。
在正常完成上述操作之后,就可以通过 wbinfo 和 getent 命令获得从 Windows 活动目录上获得的用户与组的信息。所有获得的域内用户信息都是以 Kerberos realm name + username/groupname 的格式出现。这就意味这以后在使用这些 Windows 帐户登录系统或者服务的时候也要使用该格式。而且在 W2K8E 的组件“active directory users and computers”的 computers 中可以看到刚加入域的该服务器的信息。
最后为当前服务器增加 Winbind 作为的获得域内资源和进行认证的方式之一。具体方法是在终端执行“setup”并选择“Authentication Configuration”并在“User info”和“Authentication”中都选择使用 Winbind,确认所有的信息之后进入下一步并点击“OK”即可,在完成之后 winbind 服务将会被自动重启。这样操作最终的结果是 Windows 中的管理员 administrator 可以 JERRYWJL+administrator 这个登录名在 RHEL 上登录成功。
pam_mkhomedir.so 模块
pam_mkhomedir.so 模块的主要作用是帮助用户在登录系统的时候自动创建家目录,并且随之生成该用户的 profile 文件。所以该模块在实现一些混合集中式认证的场景中会非常有用。因为当这些来自目录服务的用户登录成功之后,一般不会像本地用户登录那样可以自动创建自己的家目录。
所以来自目录服务的用户登录之后所做的一切操作和配置都无法永久保存,除非管理员手动地给这些登录用户创建家目录。不过目录服务中的用户的数量一般都非常大,手工操作的工作量和准确率可想而知。所以在这种情况下就需要使用 pam_mkhomedir.so 模块,当用户登录系统认证成功的时候,该模块会自动为用户创建家目录以及生成相关的 profile 文件。
我们可以结合上面的 RHEL + Windows Server 实现混和集中式认证的案例来继续说明 pam_mkhomedir.so 模块的用法。在上例中,当 windows 系统上的用户 administrator 成功地在 RHEL 上登录之后,唯一的问题是没有自己的主目录。这个时候终于轮到 pam_mkhomedir.so 模块出场了!
在这个方案中我们只需要简单修改 PAM 和系统用户登录的相关配置文件 /etc/pam.d/system-auth 并增加一行 session 的控制信息如下:
session required pam_mkhomedir.so skel=/etc/skel umask=0022 silent
表示用户登录之后会利用 pam_mkhomedir.so 这个 pam 模块自动建立自己的主目录,并会从 /etc/skel 目录下拷贝用户原始配置文件到所建立的目录中,当然所有的操作都会在后台执行。这个更改是实时生效的,也就是说更改完成之后无需重启任何服务,只要使用域内用户重新登录 Linux 系统即可发现与这个用户同名的主目录就能够自动建立在 /home/JERRYWJL 目录下。这样通过 W2K8E 活动目录认证用户访问 RHEL 资源的基本架构就已经搭建完成。
另外进行这个实验的用户应该可以发现,在当执行 setup 并选择使用 winbind 结合活动目录进行认证的时候,当完成这一步骤时系统会自动修改 /etc/pam.d/system-auth 文件,并在其中添加一个新的配置项——即使用 pam_winbind.so 进行用户验证用户,此模块专用于结合活动目录进行用户认证,并将获取的信息转换成 Linux 系统所能兼容的用户信息格式,所以整个的配置文件将变成:
#%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. auth required /lib/security/$ISA/pam_env.so auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok auth sufficient /lib/security/$ISA/pam_winbind.so use_first_pass auth required /lib/security/$ISA/pam_deny.so account required /lib/security/$ISA/pam_unix.so broken_shadow account [default=bad success=ok user_unknown=ignore] /lib/security/$ISA/pam_winbind.so account required /lib/security/$ISA/pam_permit.so password required /lib/security/$ISA/pam_cracklib.so retry=3 type= password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow password sufficient /lib/security/$ISA/pam_winbind.so use_authtok password required /lib/security/$ISA/pam_deny.so session required /lib/security/$ISA/pam_limits.so session required /lib/security/$ISA/pam_unix.so session required pam_mkhomedir.so skel=/etc/skel umask=0022 silent
此时当用 administrator 登录 Linux 系统的时候会发现其主目录会自动建立。
pam_ldap.so 模块
其实结合 RHEL + Windows Server 进行集中式认证的实现方法不仅仅只有 winbind 一种手段。
使用 Winbind 的方法由于涉及到 AD,Kerberos,Samba,Winbind 这几方面内容,因而在有些用户看来配置过程似乎有些复杂。所以在今天的内容中,我们将完全放弃使用 Samba 和 Winbind 而将 RHEL 系统配置为一个具有更出色兼容性的 LDAP 客户端来实现类似的功能。
这种方案的原理实际上包括下面几个内容:
首先我们将 Windows AD 作为网络中的 IDM 系统,所有的用户信息,包括用户名,UID,口令,登录 shell、有效期等等按理说都会存储在 AD 当中。
然后 Linux 系统会通过自身的应用程序编程接口和 LDAP 查询工具集来和 AD 服务器通讯并访问 AD 中的这些用户信息。
这种访问方式实际上应用到了 Linux 系统中的一个 PAM 模块——pam_ldap。pam_ldap 这个模块类似于常见的 pam_unix.so。一般来说如果 Linux 本地用户登录系统时会使用的 pam_unix.so,该模块可以将用户登录时输入的用户名和密码与系统本地用户数据库 /etc/passwd 和 /etc/shadow 中所记录的信息进行核对,如果验证通过则允许登录;而 pam_ldap 模块的基本功能则是会以 AD 上某个固定用户的身份和口令连接到 Windows DC 上查询 AD 数据库(之所以要以一个固定用户身份执行这个操作时因为默认情况下,Windows AD 是不允许以匿名方式查询和访问的,所以这个固定用户在 AD 上不但要确实存在,而且要具备足够的权限),另外 pam_ldap.so 在查询到 AD 中用户信息的同时也能对 AD 中加密的用户口令进行正确转换以实现身份认证,认证成功之后才允许用户登录或进行后续访问。
除了 pam_ldap.so 模块之外,Linux 系统还提供了一个 Open LDAP 的工具集,其中最关键的工具和命令是 ldapsearch,管理员通过手动执行该命令能够从 AD 上获得目录内的信息。这对于在配置的过程中进行调试和排错将相当有用。
当然在这个认证过程中为了保证密码之类的敏感信息在网络中传递的安全性,Linux 客户端要和基于 Windows 操作系统的 Kerberos KDC 进行安全通讯,这样则必须要启用另外一个 PAM 模块——pam_krb5.so,它能够使 Linux 客户端以正确的实例从 Kerberos KDC 上获取 TGT(票据授权票据),并通过一个完整的 Kerberos 认证过程来实现用户信息的安全传递。因为在默认情况下 Windows 的域控制器和 Kerberos 的 KDC 是集成于一体的。
另外,当使用 pam_ldap 查询到用户信息时,还有一个非常关键的问题需要解决,这就是 Windows AD 中存储的用户信息和 Linux Open LDAP 所存储的用户信息格式和名称是不统一的。如果大家曾经看过我以前介绍 Open LDAP 的文章则很容易建立这样的概念:所有的 LDAP 服务器实际上基本上都在使用 LDAP(轻量级目录访问协议),这个协议规定了 LDAP 中的所有信息都必须有一个命名方式,而命名方式归根结底是由架构档,即 schema 所决定。由于历史方面的问题,我们实在无法保证不同的目录服务产品都是用统一的架构档,这就意味着很有可能在 Windows AD 的目录服务器上添加的用户的一些属性虽然能够被 Linux 系统的 LDAP 查询工具和应用程序编程接口获得,但无法通过 NSS 名字转换服务转换成用户登录或者其它服务所需要的属性。
举一个简单的例子:假如我们在 Linux 系统中添加一个本地用户或者在 Linux 的 Open LDAP 中添加一个用户,这个用户如果要能够登录到 Linux 系统则必须包括用户名、用户 ID(UID)、用户家目录、默认登录 Shell 以及用户口令等基本信息。这样当用户登录的时候,Linux 系统的名称服务(NSS)会将用户转换成 UID 来验证用户身份,验证成功方可登录。但是在 Windows 系统中,显然我们不能指望所添加的用户具有和 Linux 系统上一样的用户属性和信息,无法获得这些信息将意味着无法登录 Linux 系统。
所以这个时候我们不但要使用 pam_ldap,还要使用一个叫做 nss_ldap 的应用程序扩展库来实现将 Windows AD 用户的架构所定义的一些属性和 Linux Open LDAP 架构所定义的,用户登录必须的属性进行一一映像。(实际上 pam_ldap 和 nss_ldap 分别是 RHEL 系统中一个叫做 nss_ldap 的安装包提供的 pam 模块扩展和应用链接库扩展,所以在 RHEL 系统中必须确保已经安装了 nss_ldap 包。)而映射的方法也很简单,因为 nss_ldap 提供了一个配置文件 /etc/ldap.conf,该档可以根据需求更改。我们只需要按照其规定的格式指定两种目录产品的用户属性对应关系即可。
那么这种对应包括:
将一些 Windows AD 的 schema 所定义的用户属性名称映像为 Linux Open LDAP schema 所拥有的用户属性。例如在 Linux 的 Open LDAP 中 UID 对应 Windows AD 中的 sAMAccountName,当然类似这样的映射还有很多;
这也是比较大的问题:Linux Open LDAP 的架构中规定的一些用户属性实际上在 Windows AD 上是根本不存在的,针对这个问题相信诸位已经想到了方法,就是通过一些特殊的方式来扩展 Windows AD 上的用户属性。
所以在 Windows 系统上实际上已经提供了一个这样的工具,叫做 SFU(Service For Unix)。该工具在 W2K3E 的 R2 版本上已经被加入到标准安装光盘中。而在 W2K3E 的非 R2 版本上也可以通过手动安装来实现其功能。这是一个在 Windows 系统上专门对 Unix 系统访问提供支持的组件。通过 SFU 可以将某些 Windows 操作系统集成到现有的 UNIX 环境中。它提供的组件可以简化跨 UNIX 和 Windows 平台的网络管理和用户管理。
SFU 为 Interix 提供了一个完整的高性能的 UNIX 环境,这个环境包含诸如 csh 或 ksh 的 UNIX shell、数百款工具和实用程序,以及一整套完整的开发工具和库(通过它们可以在 Interix 子系统中连接并使用基于 UNIX 的应用程序)。而 SFU 具体功能包括:
与 Unix 相结合,可将 Unix 的执行和客户机环境应用到 Microsoft Windows 主机上,反之亦然;
可用于访问网络文件系统(NFS)的服务和命令。这样 UNIX 和 Windows 环境之间就可以共享档;
可访问 UNIX 和 Windows 系统上的帐户和密码服务(PCNFS、NIS 以及 LDAP)的用户映像服务;
用于 Windows 和 UNIX 环境的“一次性注册”功能,UNIX 和 Windows 操作系统之间可以对密码进行同步并映像认证证书;
在功能齐全的 UNIX 环境中的 Windows 计算机上执行 UNIX shell 脚本和应用程序的功能;
目前 SFU 比较成熟的版本是 3.5。在 W2K3E 的 AD 安装完成之后通过“添加 / 删除程序”可以方便地安装。所以有了 SFU,我们可以扩展 AD 目录信息的 schema,以方便和 Linux 系统的集成。
下面我们将要开始配置和实现该环境。按照我们的惯例,在开工之前需要完整说明一下当前的实验拓扑结构和操作目标:
我将在一台 W2K3E R2 的操作系统上部署 AD 的域控制器,并且安装和部署 SFU 作为 IDM 服务器。该服务器的 IP 地址是 192.168.10.10,全称域名(FQDN)为:winsrv.example.com。由于域控制器需要 DNS 服务支持,所以在该服务器升级为域控制器之前必须先安装和配置 Windows 的 DNS 管理器。另外有一台 RHEL 5.2 的操作系统,IP 地址是 192.168.10.20,该服务器将 DNS 指向 Windows 服务器,其 FQDN 为:linsrv.example.com,这样该服务器将获得 DNS 支持。
要实现的目标是管理员在域控制器上添加用户或组信息能够在 RHEL 系统上查询到。而且该用户能够在 RHEL 系统上登录。
首先是在 Windows 服务器上构建 DNS 服务器与域控制器。注意:我这里使用的是 W2K3E 的 R2 版本,该版本有两张安装光盘。在 Windows 系统上部署 DNS 和域控制器的方法这里不再赘述。
在 Windows 的 AD 部署完成之后需要安装 SFU,在 W2K3E 的 R2 版本上,SFU 是系统自带的组件。可以通过在 Windows 系统中点击“Start”->“Run”并运行“appwiz.cpl”来开启“Add/Remove Rrogram”,接着选取“Add/Remove Windows Components”,双击选取其中的“Active Directory Services”以及其子项“Identity Management for Unix”和该项中的所有子项,其中包括“Administration Components”,“Password Synchronization”和“Service for Unix”并最终选择“OK”和“Next”以执行安装,同时在安装的过程中按照提示插入第二张光盘即可,由于要安装的软件比较大,所以安装时间将比较长,在安装完成之后按要求重启域控制器。
在域控制器重启之后,需要验证 SFU 是否成功安装。点击“Start”->“Administrative Tools”->“Microsoft Identity Management for Unix”,此时应该能够成功开启 IDM 的接口以及看到 SFU,所以 SFU 实际上是 Windows 实现跨系统平台的 IDM 的组件之一。接着,需要开启“Active Directory Users and Computers”并选取其中任何一个 OU 中的用户或者组并右键点击“properties”,这时可以发现在它的属性中多出一个叫做“UNIX Attributes”的用户属性,并包含了“NIS Domain”、“UID”等只有 Linux 系统上才有的一些用户属性。这样即证明 SFU 已经安装成功。
实际上在 W2K3E R2 的版本上安装 SFU 最大的好处就是基本上不需要用户进行任何手动的配置,所有 SFU 配置采用默认即可。但是其实会有很多用户还在使用 W2K3E 的早期版本,在这个版本上 SFU 并没有作为一个默认的系统组件被加入,那么则需要从微软的官方网站去下载 SFU 的安装包执行手动安装和配置,这是一个 200 多 MB 的自解压安装程序,文件名是 SFU35SEL_EN.exe。双击运行之后会默认解压到系统的 c:\documents and settings\administrator\local settings\temp 目录中,进入该目录执行 setup.exe 文件将看到 SFU 的手动安装接口,点击“Next”之后在“Username”和“Organization”处输入执行安装的用户和组织,这里我用“administrator”和“example.com”,接受协议并点击“Next”,在新打开的接口上选择“Standard Installation”并进入下一步。在出现的对话框中选择“Enable suid behavior for Interix programs”和“Changing Default Behavior to Case Sensitivity”这两个选项。
其中“Enable suid behavior for Interix programs”表示根据 POSIX 标准,在系统执行某文件时,该档有权限包含用于设置 UID(setuid)和 GID(setgid)的位。如果某档中设置了任一个位或同时设置了这两个位,则执行该档时的进程可获得它的 UID 或 GID。如果使用得当,此机制允许非特权用户执行那些只允许具有更高权限的档管理器拥有者或组运行的程序。但如果使用不当,由于此行为允许非特权用户执行仅应由管理员来执行的操作,则因此可能带来安全隐患。所以默认情况下 Windows Services for UNIX 安装程序不启用对此机制的支持。但为了后续获得更好的兼容性,目前我们应该启用对 setuid 行为的支持。因此勾选该选项。
另外一个选项“Changing Default Behavior to Case Sensitivity”表示系统要求用户选择是否将对象名称(比如文件名)的默认行为更改为区分大小写。这个选择将影响到系统的安全性以及 Windows Services for UNIX 的作用原理。因为对于 Windows 系统大多数对象(比如文件和目录)的名称都是保留大小写、但不区分大小写的。所以在同一目录中不能同时存在名称为例如 sample.txt 和 Sample.txt 的两个档,原因是 Windows 在识别档时会将它们看作是同一档。但是 UNIX 操作系统是完全区分大小写的。所以对象名称之间只要存在对象名称字符大小写的差异时 UNIX 系统就可区分它们,这样像 sample.txt 和 Sample.txt 就可以出现在同一目录中并且 UNIX 系统对这些文件执行操作时可以区分它们。例如执行命令 rm S*.txt 可以删除 Sample.txt,但不会删除 sample.txt。为实现典型的 UNIX 行为,Server for NFS 和 Interix 子系统在处理名称时一般都是区分大小写的。
此行为可能会带来安全问题,特别是对于已习惯 Windows 中不区分大小写的用户。例如黑客可能将木马版本的 edit.exe 以 EDIT.EXE 的名称保存在与原始档所处的同一目录中。如果用户在 Windows 命令提示符下键入 edit,则可能不执行标准版本、而是执行木马版本的(EDIT.EXE)。在启用区分大小写功能之前,Windows 用户应意识到这类问题。
对于 Windows XP(专业版)和 Windows Server 2003 系列操作系统,除了 Win32 子系统以外,其它子系统的默认行为均保留大小写但不区分大小写。在先前版本的 Windows 中,这类子系统默认情况下是完全区分大小写的。为支持标准的 UNIX 行为,在安装(用于安装 Interix 子系统的)基本实用程序或 Server for NFS 时,Windows Services for UNIX 安装程序允许您更改 Windows XP 和 Windows Server 2003 系列操作系统的非 Win32 子系统的默认行为。如果您启用了区分大小写的功能,但随后又卸除了 Server for NFS 和基本实用程序,则 Windows Services for UNIX 安装程序将恢复非 Win32 子系统的默认行为,即不区分大小写。这里仍然是选择该选项。 之后的另一个接口是配置用户名称映像:
用户名称映像起单一 clearinghouse 的作用,它提供了集中的用户映像服务。用户名称映像允许在 Windows 与 UNIX 的用户和组帐户之间创建映射。
用户名称映像允许为整个企业维护单一的映像数据库。此特性大大方便了为多个运行 Windows Services for UNIX 的计算机配置验证的过程。除 Windows 与 UNIX 用户和组帐户之间一对一的映像之外,用户名称映像还允许创建一对多的映射,即可以将多个 Windows 账户与一个 UNIX 账户关联起来。此特性非常有用,举例来讲,它让管理员可以不必为个别用户维护多个分立的 UNIX 账户,而只使用少数几个账户提供不同类的访问权限即可。管理员可以使用简单映射,通过完全相同的名称将 Windows 与 UNIX 账户映射起来。当然管理员也可以创建高级映射,通过不同的名称将 Windows 与 UNIX 账户关联起来。可以将之与简单映射配合使用。
但在我们的实验中实际上和“Network Information Serivce(NIS)”没有任何关系。所以点击下一步之后不需要输入任何“NIS Domain”和“NIS Server Name”再次点击下一步之后完成 SFU 的安装。在 SFU 安装完成之后,同样可以像在 R2 系统那样通过“Administration Components”看到 SFU 的接口以及用户属性中的“UNIX Attributes”。然后重启系统以完成整个安装。最后在 Windows 的 cmd 接口中执行 services.msc 开启服务管理器,并确保其中的 Server for Nis 这个服务的“Start Type”为“Automatic”并且“Status”为“Started”。
下面开始进行 RHEL5 系统上的配置。
首先完成 RHEL5 基本环境的设置,包括配置 IP 地址,关闭和禁用防火墙以及 SELinux,在 /etc/resolv.conf 中将 DNS 服务器指向 Windows 服务器,并且调整系统时间尽量和 Windows 服务器一致。这里值得一提的是,因为后续要使用到 Kerberos 认证,所以时间精确度的要求实际上将非常高。
由于我在内网中没有一个标准的事件源,所以此采用一种简单的方法,即将 Windows 服务器作为 NTP 服务器,并且在 RHEL 系统上制定一个任务计划,使用 ntpdate 每隔一分钟和 Windows 系统对时一次即可。另外要确保在 RHEL 系统中安装以下软件包,尤其是 openldap-servers,nss-ldap 这两个包和一些 Kerberos 的相关包。所需要的包全部在安装光盘中提供,openldap-servers、openldap、nss_ldap、mozldap、php-ldap、openldap-clients、python-ldap、openldap-devel 以及 krb5-devel、krb5-libs、pam_krb5、krb5-auth-dialog、krb5-workstation,挂载光盘切换到 Server 目录下执行 rpm -ihv 进行安装即可。 完成上述的几个步骤,RHEL5 操作系统的基本环境配置即告一段落。
现在开始配置 RHEL5 作为 Windows 的 AD 和 Kerberos KDC 的客户端以及成员服务器,在终端执行命令“setup”并选择其中的“Authentication Configuration”并运行,然后选择“Use LDAP”,“Use Shadow Passwords”以及“Use Kerberos”并继续,在出现的“LDAP Setting”中填入 LDAP 方面的设置信息并执行下一步进入“Kerberos Setting”,分别如图设置 Kerberos 的“Realm”,“KDC”和“Admin Serer”。完成之后就可以退出该接口了。所有的设定实际上会写入到配置文件 /etc/krb5.conf 档中,该档内容如下:
[logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmind.log [libdefaults] default_realm = EXAMPLE.COM dns_lookup_realm = false dns_lookup_kdc = false ticket_lifetime = 24h forwardable = yes [realms] EXAMPLE.COM = { kdc = 192.168.10.10:88 admin_server = 192.168.10.10:749 default_domain = example.com } [domain_realm] .example.com = EXAMPLE.COM example.com = EXAMPLE.COM [appdefaults] pam = { debug = false ticket_lifetime = 36000 renew_lifetime = 36000 forwardable = true krb4_convert = false }
在完成了 Kerberos 客户端配置之后,执行 kinit 命令来从 Windows 的 KDC 上初始化 TGT(票据授权票据)。Kerberos 是一个非常复杂的安全协议,关于 Kerberos 的原理和工作流程,请参照上例,这里就不再赘述。命令为:
# kinit administrator@EXAMPLE.COM
如果能够初始化 TGT 成功则不会有任何提示,当然前提是两台系统的时间必须要保证准确。同时要修改 /etc/pam.d/system-auth,配置 RHEL5 系统使用 pam_ldap 接口从 Windows 的域控制器上查询用户信息,下面是我修改之后的信息:
#%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. auth required pam_env.so auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid >= 500 quiet auth sufficient pam_ldap.so use_first_pass auth sufficient pam_krb5.so use_first_pass auth required pam_deny.so account required pam_unix.so broken_shadow account sufficient pam_ldap.so account sufficient pam_succeed_if.so uid < 500 quiet account [default=bad success=ok user_unknown=ignore] pam_krb5.so account required pam_permit.so password requisite pam_cracklib.so try_first_pass retry=3 password sufficient pam_ldap.so use_authok password sufficient pam_unix.so md5 shadow nullok try_first_pass use_authtok password sufficient pam_krb5.so use_authtok password required pam_deny.so session optional pam_keyinit.so revoke session required pam_limits.so session sufficient pam_mkhomedir.so skell=/etc/skell session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid session required pam_unix.so session optional pam_krb5.so
在这个档中实际上增加了下面的四行,这里所增加的内容表示只要在 LDAP 服务器中确定该用户合法身份以及验证密码无误之后则允许登录系统,并且允许登录时自动创建该用户的主目录。不难看出,实际上这步操作是在为用 Windows AD 用户直接登录 RHEL 系统做准备。
auth sufficient pam_ldap.so use_first_pass account sufficient pam_ldap.so password sufficient pam_ldap.so use_authok session sufficient pam_mkhomedir.so skell=/etc/skell
而且除了 pam_ldap.so 模块之外,我们还将发现通过 Kerberos 进行认证的部分实际上调用了另外一个 pam 模块 pam_krb5.so。Kerberos 进行票据验证的细节将主要通过该模块来进行。所以这个模块的被自动添加到 system-auth 文件中,从很大程度上屏蔽了认证实现的复杂度。
下面就到了最重要的一个步骤:如果要将 RHEL 作为 Windows 域控制器的成员服务器或者客户端并且要确保从 Windows AD 上获得的用户信息可以在 Linux 系统上登录,就必须要修改 /etc/ldap.conf,该档是由 nss_ldap 包所提供。该文件中首先会指定 LDAP 服务器的 ip 地址、主机名等基本信息,然后会指定将以 LDAP Server 中的哪个用户的身份和口令绑定到 LDAP 服务器上执行搜索和查询(Windows 域控制器默认情况下不允许执行匿名搜索),另外也指定了该用户在 LDAP 服务器上能够搜索和查询的范围,最后也是最关键的,就是在该档中将设置从 LDAP 服务器上获取的用户属性和 Linux 系统上用户属性的映像关系和映像图。
前面曾经讲到,由于两种目录服务的命名架构不同,Windows AD 上可登录的用户信息属性与类型和 Linux 上用于登录的用户信息属性与类型存在很大的不同,而且关键是 Linux 系统上用于登录的用户信息属性与类型在 Windows AD 上绝大部分是默认不存在的。那么之所以安装 SFU 是基于这需求扩展了 Windows AD 上的架构,实际上则增加了用户信息属性与类型,但是扩展之后属性与类型的名称和 Linux 系统上的仍然有所不同,这个时候就需要在该档中按照格式进行手工的映像了。
修改 /etc/ldap.conf 檔,像刚才解释的那样,首先确定使用 Windows AD 上的哪一个用户和密码登录 Windows 域进行搜索,所以在该文件中增加下面的信息:
base dc=example,dc=com binddn cn=administrator,cn=Users,dc=example,dc=com bindpw redhat
显而易见,这里我使用的是 Windows AD 上的系统管理员 administrator 和对应的密码 redhat,该用户毋庸置疑在 Windows 系统以及域环境中已经具备了足够的权限。而搜索的范围自然也是整个的 example.com 这个域。
之后定义该用户所在 LDAP 服务器,在这里当然是 Windows 的域控制器,添加:
uri ldap://192.168.10.10/
最后也是最关键的配置部分是手工定义我刚才提到的这些映射关系,添加下面的这些配置信息:
host winsrv.example.com nss_base_passwd cn=Users,dc=example,dc=com?one nss_base_shadow cn=Users,dc=example,dc=com?one nss_base_group cn=Group,dc=example,dc=com?one nss_map_objectclass posixAccount User nss_map_objectclass shadowAccount User nss_map_objectclass posixGroup Group nss_map_attribute uid sAMAccountName nss_map_attribute cn sAMAccountName nss_map_attribute homeDirectory unixHomeDirectory nss_map_attribute shadowLastChange pwdLastSet nss_map_attribute uniqueMember member nss_map_attribute gecos cn pam_login_attribute sAMAccountName pam_filter objectclass=User nss_base_passwd cn=Users,dc=winsrv,dc=example,dc=com pam_password ad
上面的信息实际上就是一组标准的 NSS 信息的映像关系。其中:
host winsrv.example.com 用于指定 LDAP 服务器的主机名或者 FQDN; nss_base_passwd cn=Users,dc=example,dc=com?one nss_base_shadow cn=Users,dc=example,dc=com?one nss_base_group cn=Group,dc=example,dc=com?one
表示客户端会根据 /etc/nsswitch.conf 文件中所定义的搜索顺序,到 cn=Users,dc=example,dc=com 这个范围中搜索相应的用户、组以及密码信息。这里的 dc=com?one 我认为应该是一个满足格式兼容所需要做的一个转换而已。而剩下的这一堆结构如“nss_map_objectclass A B”和“nss_map_attribute A B”这一类的信息相信大家已经能够猜到。实际上是 Windows AD 和 Linux LDAP 中的用户属性对应关系,其中 A 表示的是 Linux 系统中的用户属性名称,而 B 表示在 Windows 中的用户属性名称。例如在 Linux 的 LDAP 服务器上,每添加一个用户,它都需要有一个叫做“homeDirectory”的属性并且建立相应的主目录以满足登录需求,而如果在 Windows 的 AD 上,则可能通过安装 SFU 扩展出一个叫做 unixHomeDirectory 的属性,其作用和 Linux LDAP 的 homeDirectory 属性是大致一样的,只不过叫法不同而已。但名称不同则必须要在 /etc/ldap.conf 中明确指定,这样 Linux 系统上的名称服务才能够正确翻译来自 Windows AD 的用户属性。而只有正确翻译了这些相关的用户属性,Windows AD 上的用户才可以在 RHEL 上登录。剩下的如 pam_filter objectclass=Use,表示 PAM 模块只会对 user 这个对象类型执行相关操作,而 pam_password ad 表示如果 pam_ldap.so 模块对用户密码进行转换和识别,将使用 AD 的相关协议来进行。
为了更好地理解这个难点,我们完全可以使用另外一种方法来尝试直接从 Windows 的域控制器上获得 AD 中的用户信息,看看 Windows AD 域的用户都有哪些自己认为标准的属性和类型。这里将以 windows 上的 administrator 用户身份来直接搜索 Windows AD 目录,使用的就是上面提到的 ldapsearch 命令,这是 Open LDAP 工具集中的命令之一。
执行下面的命令:
# ldapsearch -x -b "dc=example,dc=com" -D "cn=administrator,cn=users,dc=example,dc=com" -w "redhat" -h 192.168.10.10 | grep Administrator
从输出的 Windows 用户属性和类型信息中,大家应该能够理解这种对应关系的作用以及我们刚才的做法了。
# Administrator, Users, example.com dn: CN=Administrator,CN=Users,DC=example,DC=com cn: Administrator distinguishedName: CN=Administrator,CN=Users,DC=example,DC=com memberOf: CN=Administrators,CN=Builtin,DC=example,DC=com name: Administrator sAMAccountName: Administrator uid: Administrator msSFU30Name: Administrator unixHomeDirectory: /home/Administrator
最后我们来看一下,如何在 Windows 的 AD 上添加用户并使该用户可以在 Linux 系统中看到和直接登录。
在执行这个操作前,还是首先使用 administrator 用户进行一个测试,即只为 Windows 中的 administrator 用户添加 Unix 属性。在 Windows 域控制器上选择“Start”->“Administrative Tools”->“Active Directory Users and Computers”,然后右键选择用户“Administrator”点击“Properties”并切换到“UNIX Attribute”,在该标签中定义“NIS Domain”,“UID”(可以自行指定),“Login Shell”,“Home Directory”,最后一定要指定一个“Primary Group Name”(往往和 UID 一致),并选择“Apply”。这样即定义了该 Windows 用户的 Unix 属性。
而此时在 RHEL 系统上,可以立刻执行命令 getent passwd 命令,如果一切顺利,如图所示我们将看到 Windows 系统上的用户 Administrator 用户,由于用户的信息只要满足登录需求就能被 getent 所显示出来,所以如果直接用该用户登录 RHEL 系统也能够成功!
既然这样,如果在 Windows 的“Active Directory Users and Computers”中选择“example.com”的“users”容器,并添加两个用户 tuser1 和 tuser2,并像刚才那样定义好“UNIX Attribute”之后,在 RHEL 上一样可以看到该用户信息并且甚至可以直接登录系统成功。
尽管实验到此算是实现了我们需要的结果,不过不知道各位读者是否看出一些问题?对了!相信大家已经发现,在 /etc/ldap.conf 所定义的所有映像关系中似乎并没有见到什么通过安装 SFU 所扩展出来的特殊属性。这个问题实际上是因为在 W2K3E 的 R2 版本中已经整合了 SFU,所以 SFU 的架构或者扩展属性已经加入到 Windows AD 的默认 LDAP 架构和属性中,故并不需要在 /etc/ldap.conf 中再进行额外的指定。但目前仍然有很多用户在使用 W2K3E 的非 R2 版本,并且要像我上面所提到的那样下载和完全手动安装 SFU,这样通过 SFU 获得的扩展架构和属性就不是 Windows AD 的默认架构和属性,于是这样就需要在 /etc/ldap.conf 中去手动定义这些属性和 Linux LDAP 的属性相对应。因此,如果各位在使用 W2K3E 的非 R2 版本,那么在 /etc/ldap.conf 文件的目录属性映像应该更改为下面的样子:
nss_base_passwd cn=Users,dc=example,dc=com?one nss_base_shadow cn=Users,dc=example,dc=com?one nss_base_group cn=Group,dc=example,dc=com?one nss_map_objectclass posixAccount User nss_map_objectclass shadowAccount User nss_map_objectclass posixGroup Group nss_map_attribute uid sAMAccountName nss_map_attribute uidNumber msSFU30uidNumber nss_map_attribute gidNumber msSFU30gidNumber nss_map_attribute cn sAMAccountName nss_map_attribute uniqueMember member nss_map_attribute homeDirectory msSFU30homeDirectory nss_map_attribute loginShell msSFU30LoginShell nss_map_attribute gecos cn pam_login_attribute sAMAccountName pam_filter objectclass=User nss_base_passwd cn=Users,dc=winsrv,dc=example,dc=com pam_password ad
这样在 W2K3E 的非 R2 版本中通过上述操作也一样可以在 Linux 中看到所有的 Windows 目录中的用户信息和组信息。
总结
通过以上几篇文章对 PAM 的基本概念,工作原理和十几个常用模块的在实际应用环境当中的举例讲解,相信大家对可插拔认证模块已经有了一定的了解和认识。 由于时间和篇幅的关系,本人不可能将所有模块的用法都一一举例,所以希望对此有兴趣的朋友通过充分的实验来充分掌握其原理与细节,并通过活学活用 PAM 来实现系统安全的有效增强。
作者简介
王基立, 现工作于红帽软件(北京)有限公司,具备多年的售前解决方案规划与售后技术支持经验,熟悉红帽所有平台类产品和解决方案。现常驻深圳任红帽软件华南区解决方案架构师一职,主要负责红帽解决方案在华为、中兴等大型电信企业用户环境中的设计、规划、应用以及相关售前工作。同时也为包括各高级分销商以及金融、政府、教育等各方面在内的管道和区域用户提供相关解决方案、技术咨询、技术培训、现场实施、技术支持等服务。
给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。
活动推荐:
2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。
评论