LinuxEye - Linux系统教程

LinuxEye - Linux系统教程

当前位置: 主页 > 安全 >

常用的Linux可插拔认证模块(PAM)应用举例

时间:2012-05-20 11:42来源:www.infoq.com 编辑:admin 点击:
linux pam认证模块示例:pam_access.so,pam_listfile.so,pam_limits.so,pam_rootok.so, pam_userdb.so,pam_securetty.so,pam_cracklib.so,pam_pwhistroy.so,pam_tally.so, pam_winbind.so,pam_mkhomedir.so
      上一篇文章《Linux可插拔认证模块(PAM)的配置文件、工作原理与流程》我们介绍了常用的Linux可插拔认证模块(PAM)的配置文件、工作原理和流程,下面我们将通过一些实际配置和例子来说明pam的各种常用模块的作用以及使用方法。

pam_access.so模块

pam_access.so模块主要的功能和作用是根据主机名(包括普通主机名或者FQDN)、IP地址和用户实现全面的访问控制。 pam_access.so模块的具体工作行为根据配置文件/etc/security/access.conf来决定。该配置文件的主体包含了三个字段 ——权限、用户和访问发起方。格式上是一个用“:”隔开的表。
第一个字段:权限(permission),使用“+”表示授予权限,用“-”表示禁止权限。
第二个字段:用户(user),定义了用户、组以及用“@”表示的在不同主机上的同名用户和同一主机上不同名用户。
第三个字段:访问发起方(origins),定义了发起访问的主机名称、域名称、终端名称。

而且该文件提供了很多范例供修改时参考,并且都给出了具体的说明,例如:

#禁止非root用户通过tty1访问相关服务
#-:ALL EXCEPT root:tty1

#禁止除了wheel、shutdown以及sync之外的所有用户访问相关服务
#-:ALL EXCEPT wheel shutdown sync:LOCAL

#禁止wheel用户通过.win.tue.nl之外的其它它终端访问相关服务
#-:wheel:ALL EXCEPT LOCAL .win.tue.nl

# 禁止下面的用户从任何主机登录。其它用户可以从任意地方访问相关服务
#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL

# root用户允许通过cron来使用tty1到tty6终端访问相关服务
#+ : root : cron crond :0 tty1 tty2 tty3 tty4 tty5 tty6

# 用户root允许从下面的地址访问相关服务
#+ : root : 192.168.200.1 192.168.200.4 192.168.200.9
#+ : root : 127.0.0.1

# 用户root可以从192.168.201.网段访问相关服务
#+ : root : 192.168.201.

# 用户root可以从.foo.bar.org中任何主机访问相关服务
#+ : root : .foo.bar.org

# 用户root不允许从任何主机访问相关服务
#- : root : ALL

# 用户@nis_group和foo可以从任何主机访问相关服务
#+ : @nis_group foo : ALL

# 用户john只能从127.0.0.0/24来对本机相关服务进行访问
#+ : john : 127.0.0.0/24

# 用户john可以通过ipv4和ipv6的地址对本机相关服务进行访问
#+ : john : ::ffff:127.0.0.0/127

# 用户john可以通过ipv6的地址访问本机相关服务
#+ : john : 2001:4ca0:0:101::1

# 用户john可以通过ipv6的主机IP地址来访问本机
#+ : john : 2001:4ca0:0:101:0:0:0:1

# 用户john可以通过ipv6的IP地址和掩码来访问相关服务
#+ : john : 2001:4ca0:0:101::/64

# 开放所有用户对本机所有相关服务的访问
#- : ALL : ALL

那么具体如何应用到实际环境中呢?我们来设计这样一个例子:

如果要在网络内架设一个FTP服务器,而且在该FTP服务器上需要强制地指定某个用户只能通过某个IP地址登录。这个时候pam_access.so模块就派上用场了。

假设我的FTP服务器是使用vsftp来构建的,那么具体方法是:

首先修改FTP服务器的/etc/pam.d/vsftpd文件,在调用account接口处插入:

"account    required     pam_access.so"
到第一行,那么整个文件的内容如下:
[root@localhost ~]# cat /etc/pam.d/vsftpd
#%PAM-1.0
session    optional     pam_keyinit.so    force revoke
auth       required     pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed
auth       required     pam_shells.so
auth       include      system-auth
account    required     pam_access.so
account    include      system-auth
session    include      system-auth
session    required     pam_loginuid.so

上述配置表示当针对FTP访问执行用户类接口的时候会增加pam_access.so的认证。保存退出之后修改/etc/security/access.conf配置文件,添加下面的两行:
- : admin1 : ALL EXCEPT 192.168.10.251
- : admin2 : ALL EXCEPT 192.168.10.252

前提是我在系统上事先已经建立了admin1和admin2两个用户。所以上面的配置表示:admin1用户不能从192.168.10.251之外的任何客户端访问FTP服务器;而admin2用户不能从192.168.10.252之外的任何客户端访问FTP服务器。

最后再修改/etc/vsftpd/vsftpd.conf文件,禁用匿名登录:

Anonymous_enable = NO

这样当重启vsftpd服务之后,用户admin1将只能从192.168.10.251访问ftp服务,而admin2将只能从192.168.10.252访问ftp服务。

所以当针对这种需求而且不想使用防火墙以及应用程序自带的认证机制的时候,通过pam_access.so可以实现所需的效果。

pam_listfile.so模块

pam_listfile.so模块的功能和pam_access.so模块类似,目标也是实现基于用户/组,主机名/IP,终端的访问控制。不过 它实现的方式和pam_access.so会稍微有些不同,因为它没有专门的默认配置文件。访问控制是靠pam配置文件中的控制选项和一个自定义的配置文 件来实现的。而且除了针对上述访问源的控制之外,还能够控制到ruser,rhost,所属用户组和登录shell。所以有些用户认为它的功能似乎比 pam_access.so更加灵活和强大一些。

对于pam_listfile.so的配置方法,我们可以参考vsftpd文件中对pam的调用方式。

熟悉vsftpd的人都知道,在vsftpd默认配置中,root用户是不允许通过ftp方式直接访问FTP服务器的。这个功能实际上是由/etc /vsftpd/vsftpd.conf,/etc/vsftpd/ftpusers和/etc/pam.d/vsftpd共同控制的。 因为在/etc/pam.d/vsftpd中有这样的一行配置:

auth       required pam_listfile.so item=user sense=deny file=/etc/vsftpd/ftpusers onerr=succeed

表示当用户试图登录FTP服务器的时候,会调用pam_listfile.so模块来验证用户是否可以登录,这里item=user表示访问控制是 基于user即用户实现的。那么哪些用户可以登录呢?就是除了file选项所定义的/etc/vsftpd/ftpusers文件之外的用户,这是由另外 一个选项sense=deny所决定的。

而在/etc/vsftpd/vsftpd.conf中明确指定了对用户的认证需要通过/etc/pam.d/vsftpd中的配置调用pam模块:

pam_service_name=vsftpd

而恰好root用户又在/etc/vsftpd/ftpusers文件中,所以这成为了制约root登录FTP服务器的一个必要条件(但不是唯一条件)。

所以针对这种情况,我们要开放和允许root用户登录FTP的权限,至少有三种改法:

  1. 修改/etc/pam.d/vsftpd文件,将sense=deny改成sense=allow。这样会正好将情况反转过来,FTP服务器只允许/etc/vsftpd/ftpusers文件内的用户登录;

  2. 修改/etc/pam.d/vsftpd文件,注释掉调用pam_listfile.so那行。这样FTP服务器在认证用户的时候将不再考虑pam_listfile.so模块的任何限制;

  3. 将root从/etc/vsftpd/ftpuser文件中注释掉;

不过需要注意的是,root用户比较特殊,因为它在vsftpd配置中的限制不仅仅来自于pam,vsftpd本身的配置中也对其做了限制。当我们看/etc/vsftpd/user_list文件的时候,还将会看到这样的配置说明:

# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.

表示当vsftpd.conf中userlist_deny=NO的时候,系统将只允许user_list中的用户登录FTP服务器;如果 userlist_deny=YES,情况将截然相反——此时user_list变成了黑名单,里面的用户将一概不允许登录FTP服务器。所以要彻底开放 root登录FTP的权限,我们还要在/etc/vsftpd/vsftpd.conf中增加userlist_deny=YES或者注释掉 user_list中的root。

不过不管怎么说,vsftpd中禁用root用户的直接登录是在绝大多数FTP服务器上默认的安全措施,所以开放root权限时应该慎重。

另外除了通过pam_listfile.so实现基于用户的访问控制之外,还可以实现基于其它条件的访问控制。我们具体看看pam_listfile.so模块的选项就会比较清楚:

使用pam_listfile.so模块配置的格式分为五个部分:分别是item、sense、file、onerr以及apply。 其中:

item=[tty|user|rhost|ruser|group|shell]:定义了对哪些列出的目标或者条件采用规则,显然,这里可以指定多种不同的条件。

onerr=succeed|fail:定义了当出现错误(比如无法打开配置文件)时的缺省返回值。

sense=allow|deny:定义了当在配置文件中找到符合条件的项目时的控制方式。如果没有找到符合条件的项目,则一般验证都会通过。

file=filename:用于指定配置文件的全路径名称。

apply=user|@group:定义规则适用的用户类型(用户或者组)。

而至于file文件的写法就简单了,每行一个用户或者组名称即可。

所以,当我们需要对其它服务进行类似的访问控制的时候,就可以照葫芦画瓢。例如现在需要在SSH服务器上对ssh客户端实现基于用户的访问控制,目的是不允许admin从通过ssh登录。

针对这种需求只需要更改/etc/pam.d/sshd文件,并在该文件中添加一行(添加到第一行):

auth required pam_listfile.so  item=user sense=deny file=/etc/pam.d/denyusers onerr=succeed

然后建立文件/etc/pam.d/denyusers,并在文件中写入用户信息——>就写admin即可。

表示用户以ssh登录必须要通过pam_listfile.so模块进行认证,认证的对象类型是用户,采用的动作是禁止,禁止的目标是/etc/pam.d/denyuser文件中所定义的用户。

这样在该条目添加到该文件之后,使用admin从其它主机远程ssh访问服务器会出现密码错误的提示。但是使用root或者其它用户则访问能够成功。

再次强调,要注意pam模块使用的顺序,刚才的规则一定要添加到auth的第一行之前,否则不会生效。

pam_listfile.so的另外一个案例是应用于诸如xinetd超级进程上的的非独立服务的应用。例如笔者曾接触过一个用户在对系统进行安 全加固的时候需要禁止gssftp的匿名用户登录功能。这里需要说明的是gssftp是RHEL系统上基于kerberos协议进行认证的一款轻量级的 FTP服务器。默认情况下,当修改了/etc/xinetd/gssftp配置文件并通过重启xinetd启动服务就可以开启该服务。当开启gssftp 服务之后,该ftp服务器也是允许匿名用户登录的。而且除了/etc/xinetd.d/gssftp之外没有其它的配置文件可以对该服务进行过多的定 制。这个时候实际上也可以借用pam_listfile.so模块来对其进行一些简单的控制。

参考如下的例子,如果要禁用匿名登录,则可以修改/etc/xinetd.d/gssftp文件如下:

[root@localhost ~]# cat /etc/xinetd.d/gssftp 
# default: off
# description: The kerberized FTP server accepts FTP connections \
#              that can be authenticated with Kerberos 5.
service ftp
{
        flags           = REUSE
        socket_type     = stream        
        wait            = no
        user            = root
        server          = /usr/kerberos/sbin/ftpd
#        server_args     = -l -a    
        log_on_failure  += USERID
        disable         = no
}

然后在/etc/pam.d/gssftp文件中增加对pam_listfile.so模块的调用:
auth    required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
并根据PAM配置文件内容建立相应配置文件/etc/ftpusers,内容为:
anonymous
ftp

这样修改之后的效果是,当没有改server_args时,那么启用/etc/ftpusers之后,所有用户都无法登录服务器;而如果保存了 server_args之后,只有pam_listfile.so指定在/etc/ftpusers文件中的用户不能登录FTP服务器,而且在输入用户名 之后会被直接拒绝掉。但root或者其它自建立的用户可以访问FTP服务器。

pam_limits.so模块:

pam_limits.so模块的主要功能是限制用户会话过程中对各种系统资源的使用情况。缺省情况下该模块的配置文件是/etc/security/limits.conf。而该配置文件的基本格式实际上是由4个字段组成的表,其中具体限制的内容包括:

Domain             type                       item                                                       value
用户名/组名      软/硬限制                                                                            具体值
                                core——core文件大小 (KB)
                                data——最大数据大小(KB)
                                fsize——最大文件大小(KB)
                                memlock——最大可用内存空间(KB)
                                nofile——最大可以打开的文件数量
                                rss——最大可驻留空间(KB)
                                stack——最大堆栈空间(KB)
                                cpu——最大CPU使用时间(MIN)
                                nproc——最大运行进程数
                                as——地址空间限制
                                maxlogins——用户可以登录到系统最多次数
                                locks——最大锁定文件数目

需要注意的是,如果没有任何限制可以使用”-”号,并且针对用户限制的优先级一般要比针对组限制的优先级更高。

使用pam_limits.so模块的最常见的场景是在运行Oracle数据库的RHEL服务器中,因为一般Oracle数据库在安装之前,按照其官方文档的说明需要先对某些用户(Oracle)使用系统资源的情况进行限制。

所以我们总是能够在Oracle数据库服务器的/etc/security/limits.conf文件中看到类似这样的配置:

oracle           soft    nproc   2047
oracle           hard    nproc   16384
oracle           soft    nofile  1024
oracle           hard    nofile  65536

结合上面的配置文件说明,可知Oracle数据库需要对Oracle用户使用资源的情况进行一些限制,包括: oracle用户最大能开启的进程数不超过16384,最大能打开的文件数不超过65536。

至于soft和hard的区别,不同于磁盘配额中的软限制和硬限制。普通用户可以调整自己的soft limit但最高不能超过hard limit,而且除了root以外的普通用户也不能够随意更改hard limit。该调整完成之后一般可以使用ulimit命令查看。

顺便提一下,针对nofile,这个只是基于用户层面的限制和调整方法。基于系统层面的限制和调整方法是修改/etc/sysctl.conf文件,直接改fs.file-max参数,调整之后sysctl –p生效。

另外一个例子,pam_limits.so模块也可以使用在对一般应用程序使用的资源限制方面。举例来说,如果需要在SSH服务器上对来自不同用户 的ssh访问进行限制,就可以调用该模块来实现相关功能。例如,当需要限制用户admin登录到SSH服务器时的最大连接数(防止同一个用户开启过多的登 录进程),就可以在/etc/pam.d/sshd文件中增加一行对pam_limits.so模块的调用:

session    required        pam_limit.so
然后在/etc/security/limits.conf文件中增加一行对admin用户产生的连接数进行限定:
admin      hard        maxlogins       2

完成之后重启服务器端的sshd服务。

之后我们可以看到,从客户端以admin身份登录SSH服务器时,在客户端上可以打开两个控制台登录。但当客户端开启第三个登录窗口的时候会被服务器拒绝,但其它用户不会受到限制。

pam_rootok.so模块

一般情况下,pam_rootok.so模块的主要作用是使uid为0的用户,即root用户能够直接通过认证而不用输入密码。

pam_rootok.so模块的一个典型应用是插入到一些应用程序的认证配置文件中,当root用户执行这些命令的时候可以不用输入口令而直接通过认证。

比如说“su”命令,为什么当以root用户执行“su”切换到普通用户身份的时候是不需要输入任何口令而可以直接切换过去?

当我们查看一下/etc/pam.d/su文件的内容就不会奇怪了。因为该文件的第一行就是:

auth       sufficient  pam_rootok.so

而如果将该行配置注释掉的情况下,就会发现即便以root用户切换普通用户的时候仍然要求输入口令。

另外一种方法,只需要将上述的“sufficient”改成“required”即可。因为这样,pam_rootok.so模块的验证通过就成为了必要条件之一。

pam_rootok.so模块的另外一个应用是在chfn命令中。Chfn命令用于改变/etc/passwd中的用户的说明字段。当以root 身份执行chfn命令修改用户信息的时候是不用输入密码的。但是以普通用户身份执行chfn则需要输入密码之后才能改变自己的用户说明。这实际上也是因为 在/etc/pam.d/chfn配置文件中的第一行调用了pam_rootok.so的结果。

不过这里即便将该配置中的第一行注释掉,root用户通过chfn修改自己信息的时候仍然不需要使用密码。所以恐怕效果不是很明显。究其原因主要是很多PAM模块对root用户是不会产生限制的。

pam_userdb.so模块

pam_userdb.so模块的主要作用是通过一个轻量级的Berkeley数据库来保存用户和口令信息。这样用户认证将通过该数据库进行,而不 是传统的/etc/passwd和/etc/shadow或者其它的一些基于LDAP或者NIS等类型的网络认证。所以存在于Berkeley数据库中的 用户也称为虚拟用户。

pam_userdb.so模块的一个典型用途就是结合vsftpd配置基于虚拟用户访问的FTP服务器。

相对于本地用户以及匿名用户来说,虚拟用户只是相对于FTP服务器而言才有用的用户,这些用户被严格地限定在pam_userdb数据库当中。所以 虚拟用户只能访问FTP服务器所提供的资源,因而可以大大提高系统安全性。另外相对于匿名用户而言,虚拟用户必须通过用户名和密码才能够访问FTP的资 源。这样也提高了对FTP用户下载的可管理性。

基于虚拟用户实现的vsftpd的原理基本上是这样一个过程:

先定义一些专门针对FTP的虚拟用户,然后将用户信息加入到系统自带的数据库中(但不是passwd)从而生成一个访问FTP的虚拟用户列表,这里 使用的数据库是db4也就是Berkeley DB。然后可以通过使用pam_userdb.so模块来调用该数据库存储用户信息以及实现FTP用户认证。当然同时也可以在系统中通过对配置文件的定义 和划分来实现对不同虚拟用户不同类型的访问控制。

下面我将详细介绍一下基于虚拟用户的FTP服务器配置方法,其中也包含了对pam_userdb.so模块的使用。

我的实验环境很简单:

FTP服务器的IP地址是:10.66.0.136,使用的操作系统是RHEL 5.4,FTP服务是vsftpd。

操作步骤:

1.备份配置文件:

[root@dhcp-0-136 ~]# cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak
2.建立虚拟用户数据库文件login.txt:
[root@dhcp-0-136 vsftpd]# pwd
/etc/vsftpd
[root@dhcp-0-136 vsftpd]# cat login.txt 
ftpuser1
123
ftpuser2
123
ftpuser3
123

该文件单数行为用户名称,双数行为用户访问FTP服务器时的口令。

完成之后根据该文件内容创建登录用户数据库文件:

[root@dhcp-0-136 vsftpd]# db_load -T -t hash -f /etc/vsftpd/login.txt /etc/vsftpd/vsftpd_login.db

之后需要确认系统上已经安装Berkeley DB,即db4软件包。

完成之后,在/etc/vsftpd/vsftpd.conf目录下会产生vsftpd_login.db文件。

设置该文件的访问权限为仅root可读写:

[root@dhcp-0-136 vsftpd]# chmod 600 vsftpd_login.db

3.使用PAM来实现对登录FTP用户的限制:

现在需要创建一个使用数据库的pam配置文件,在这里该文件命名为vsftpd.pam,在/etc/pam.d目录下。

[root@dhcp-0-136 ~]# touch /etc/pam.d/vsftpd.pam
[root@dhcp-0-136 ~]# vi /etc/pam.d/vsftpd.pam
在该文件中写入下面的两行:
[root@dhcp-0-136 ~]# cat /etc/pam.d/vsftpd.pam
auth required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_login
account required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_login
假如说以后添加了新的用户,那么修改login.txt,然后再次执行命令:
db_load -T -t hash -f /etc/vsftpd/login.txt /etc/vsftpd/vsftpd_login.db

生成新的数据库即可。

4.建立一个本地用户,其主目录作为虚拟用户对FTP服务器的访问时的服务目录:

[root@dhcp-0-136 ~]# useradd –d /home/ftpsite virtual

通过上面的步骤建立一个名为virtual的本地用户,并且该用户的主目录是/home/virtual

5.现在通过对/etc/vsftpd/vsftpd.conf主配置文件的定义来使虚拟用户可以访问FTP服务:

[root@dhcp-0-136 ~]# vi /etc/vsftpd/vsftpd.conf
既然该服务器要求使用虚拟用户访问,那么需要先关闭匿名用户访问功能:
anonymous_enable=NO
local_enable=YES
另外出于安全考虑,此处添加的所有用户都只赋予对FTP服务器只读权限:
write_enable=NO
anon_upload_enable=NO
anon_mkdir_write_enable=NO
anon_other_write_enable=NO
确保用户在登录的时候使用刚才定义的PAM配置文件来进行身份验证,因此更改此行为:
pam_service_name=/etc/pam.d/vsftpd.pam
6.激活虚拟用户功能,并将所有虚拟用户对FTP服务器的访问映射为刚才所添加的virtual用户对FTP服务器的访问。
guest_enable=YES
guest_username=virtual

这个 guest_enable非常重要,该选项用来激活虚拟用户! 而guest_username 是将所有虚拟用户映射成先前所建立的真实用户"virtual"。这也决定了虚拟用户在整个文件系统中的位置,也就是"virtual"的主目录 /home/ftpsite。

如果系统中还有本地用户需要访问FTP服务器,可以再次对本地用户访问FTP服务时的根目录进行指定:

local_root=/home/ftpsite
当然在这里将local_root改为其它用户也没有任何问题。 再增加一行:
listen=YES
表示FTP服务器将会以standalone的模式启动。即不通过xinetd以及/etc/init.d下的脚本启动,而可以直接执行vsftpd的启动。最后启动FTP服务:
[root@dhcp-0-136 ~]# service vsftpd restart

在服务启动之后可在客户端上进行测试: 我们可以使用刚才在自定义数据库中建立的用户ftpuser1、ftpuser2、ftpuser3分别登录FTP服务器进行访问测试,如果都能够在 ftp的命令行中正常登录则证明整个实验成功! 但是如果访问失败,比如说如果出现 “failed to open directory",则有可能是因为目录/home/ftpsite不是全局只读属性(如果想更改,可以通过设置 anon_world_readable_only=NO来实现,这个默认是YES,它是用来设置匿名用户只能下载全局可读的文件)。

7.在FTP服务器的虚拟用户建立之后,可以考虑针对不同的虚拟用户设置不同的访问权限:

整个功能只有在使用虚拟帐号的情况下才能借助虚拟帐号的per-user功能来实现。
为了测试需要,现在添加另外三个新的用户,分别是ftpuser4,ftpuser5和ftpuser6:

[root@dhcp-0-136 vsftpd]# cat login.txt 
ftpuser1
123
ftpuser2
123
ftpuser3
123
ftpuser4
123
ftpuser5
123
ftpuser6
123
然后将该文件所有信息再次导入数据库中:
[root@dhcp-0-136 vsftpd]# db_load -T -t hash -f /etc/vsftpd/login.txt /etc/vsftpd/vsftpd_login.db

假如在该场景中需要设置ftpuser4和ftpuser5用户具有对主目录的读取权限,而ftpuser6具有对主目录的写入权限。
那么可以针对这三个用户分别建立配置文件来进行限制。

首先创建并且定义一个容纳每个用户配置文件的目录:

[root@dhcp-0-136 vsftpd]# mkdir /etc/vsftpd_user_conf
然后在主配置文件中进行定义,定义的是不同用户配置文件所存储的路径,就在刚才建立的目录下:
user_config_dir=/etc/vsftpd_user_conf
进入该目录创建不同用户的配置文件:
[root@dhcp-0-136 vsftpd]# cd /etc/vsftpd_user_conf
创建的ftpuser4配置文件的内容如下:
[root@dhcp-0-136 vsftpd]# ls /etc/vsftpd_user_conf
    ftpuser4
    [root@dhcp-0-136 vsftpd]# cat /etc/vsftpd_user_conf/ftpuser4
    anon_world_readalbe_only=NO
通过上面的定义,ftpuser4用户可以读取的同时也能够下载文件。但是如果写成YES则意味着无法列出文件和目录。
然后赋予ftpuser5用户相同的权限,由于权限与ftpuser4一致,所以只需要拷贝配置文件即可:
[root@dhcp-0-136 vsftpd]#cp /etc/vsftpd_user_conf/ftpuser4 /etc/vsftpd_user_conf/ftpuser5
最后是定义ftpuser6的权限,该用户可以向服务器目录写入和上传,那么配置文件内容为:
[root@dhcp-0-136 vsftpd]# vi /etc/vsftpd_user_conf/ftpuser6
anon_world_readable_only=NO     不仅仅是只读,还可以下载
write_enable=YES                    可以写入
anon_upload_enable=YES           可以上传
anon_mkdir_write_enable=YES     可以建立目录
如果ftpuser5已经提升为管理员,现在需要针对管理员定义一个更高的权限,可以将ftpuser5的配置文件增加一行:
anon_other_write_enable=YES        增加管理员用户的删除/重命名的权限

完成之后保存退出,并重启服务:

分别测试ftpuser4、ftpuser5以及ftpuser6的权限会发现:

ftpuser4只有登录浏览权限;
ftpuser5除了登录浏览之外还可以删除文件以及重命名文件
ftpuser6可以登录浏览并上传和下载,但是对于已有的文件没有写入权限。

实验到此基本成功!

在实际操作中,这种方法能够更好解决对服务器访问用户细化地设置权限的问题。而且pam_userdb.so模块也不仅仅只是用于在FTP服务中创建和使用虚拟用户,类似的服务,例如postfix,web服务等,都可以使用该模块实现类似功能。

pam_securetty.so模块

pam_securetty.so模块用于控制用户登录系统的时候所使用的终端。为说明该模块的用法,我们可以例举一个简单的例子:
在RHEL操作系统上一旦开启telnet服务之后,默认情况下root用户是无法通过telnet登录的。如果要开启该功能的话,只需要修改/etc/pam.d/remote文件,将该文件中的:

auth       required     pam_securetty.so

这一行注释掉即可。

当通过这种方式telnet成功之后,再执行who命令查看用户登录情况的时候不难发现,刚才root用户telnet上来使用的终端是 pts/0,即网络终端。那么为什么root用户无法使用pts/0登录系统呢?实际上这是pam_securetty.so模块的配置文件/etc /securetty所定义的。默认情况下该文件中只定义了本地终端,所以另外一种改法是将pts/0,pts/1这类网络终端以及所需要添加的其它类型 终端加入到该文件中去。这样修改之后root用户一样可以登录。

不过当我们使用非root用户通过telnet登录的时候会发现登录成功的时候通过who显示出来用的也是pts/0终端,那么为什么非root用户不用修改securetty文件而root用户就需要?其实答案很简单,只要访问/usr/share/doc/pam-/txt/README.pam_securetty文件(该目录下也有其它PAM模块的帮助文档)就可以获知,实际上pam_securetty.so和其它的pam模块不同,它只针对root用户起作用。

所以pam_securetty模块和pam_limit.so模块在某种程度上是差不多的,即都可以针对系统资源使用做出明确的限制。

pam_cracklib.so模块

pam_cracklib.so是一个常用并且非常重要的PAM模块。该模块主要的作用是对用户密码的强健性进行检测。即检查和限制用户自定义密码的长度、复杂度和历史等。如不满足上述强度的密码将拒绝用户使用。

pam_cracklib.so比较重要和难于理解的是它的一些参数和计数方法,其常用参数包括:   

debug:将调试信息写入日志;

type=xxx:当添加/修改密码时,系统给出的缺省提示符是“New UNIX password:”以及“Retype UNIX

password:”,而使用该参数可以自定义输入密码的提示符,比如指定type=your own word;

retry=N:定义登录/修改密码失败时,可以重试的次数;

Difok=N:定义新密码中必须有几个字符要与旧密码不同。但是如果新密码中有1/2以上的字符与旧密码不同时,该新密码将被接受;

minlen=N:定义用户密码的最小长度;

dcredit=N:定义用户密码中必须包含多少个数字;

ucredit=N:定义用户密码中必须包含多少个大写字母;

lcredit=N:定义用户密码中必须包含多少个小些字母;

ocredit=N:定义用户密码中必须包含多少个特殊字符(除数字、字母之外);

下面是关于pam_cracklib.so的一个应用实例——在/etc/pam.d/system-auth中使用pam_cracklib.so来限制用户修改自己密码时必须满足一定的强健性要求。

[root@localhost ~]# 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        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     sufficient    /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet
account     required      /lib/security/$ISA/pam_permit.so
password    required      /lib/security/$ISA/pam_cracklib.so retry=3 minlen=9 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1
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

从上面使用pam_cracklib.so的策略看,要求用户修改密码时必须要满足9位,并且密码中至少要包含一个大写字母、小写字母、数字和特殊符号。

但是实际上像minlen和所有credit所对应的数值可以是非0之外的正负整数,那么这些数值到底表示什么意思呢?很多人将其简单地理解为某一类字符的位数,其实远远没有那么简单。

下面我们对这些数值和关系做一个简短的说明:

首先要明确整个环境中密码的长度要满足下面的计算公式:

计算公式:最小密码长度(minlen)应该小于或者等于 dcredit+ucredit+lcredit+ocredit+其它分值 (同时满足 * credit的条件),关于分值我们随后会讲解。 (参考file:///usr/share/doc/pam-0.99.6.2/html/sag-pam_cracklib.html理解)

(注)*credit=-1表示至少有一个的意思,*credit=N(N表示当满足条件的时候加N分,例如dcredit=2表示一个数字加2分,两个数字加4分),所以这里minlen其实更准确的表述应该是mincredit。

所以在下面的例子中,当pam_cracklib.so的参数按如下方式指定:

password    requisite     pam_cracklib.so try_first_pass retry=3 minlen=12 dcredit=2 ucredit=0 lcredit=0 ocredit=0
那么当用户执行命令修改密码的时候:
[test@dhcp-0-185 ~]$ passwd 
Changing password for user test.
Changing password for test
(current) UNIX password: 
New UNIX password:                   输入密码: 1\=poiuyt   不成功      1个数字再加2分
此时密码有一个数字,2分,其它的字符每个1分,总共10分,不满足minlen的位数需求,所以该密码不能通过。
BAD PASSWORD: is too simple
New UNIX password:                   输入密码: 12\=poiuyt   成功     2个数字再加2分
Retype new UNIX password: 
此时密码有两个数字,4分,其它的字符每个1分,总共12分,满足minlen的位数需求,所以密码可以通过。
New UNIX password:                   输入密码: 1\=poiuytre   成功     1个数字再加2分
Retype new UNIX password: 

此时密码有1个数字,2分,其它的字符每个1分,总共12分,满足minlen的位数需求,所以密码可以通过。

因此通过上述的配置基本可以得出这样的结论:

当某类credit为正数N的时候,表示密码中该类字符一个可以加N分;当某类credit为负数N的时候,表示密码中某类字符必须具备N个。时间关系我将不会一一演示。

所以当输入的密码所有的字符总分大于或者等于minlen,并且满足所有credit的要求,该密码通过; 即:输入的密码长度(每个输入值都算数)+*credit(加分)>=minlen

所以pam_cracklib.so模块在系统安全管理策略和管理中的用途是非常重要和广泛的。

pam_pwhistroy.so模块

pam_pwhistory.so模块也是一个常用模块,一般辅助pam_cracklib.so,pam_tally.so以及 pam_unix.so等模块来加强用户使用密码的安全度。不过pam_pwhistory.so模块起的是另一类的作用,即专门为用户建立一个密码历史 档案,防止用户在一定时间内使用已经用过的密码。

例如,当需要限定用户在90天之内不能重复使用以前曾经使用过的10个密码,那么具体操作方法是去修改/etc/pam.d/system-auth文件,在password接口处增加:

password     required       pam_cracklib.so    retry=3
    password     required       pam_pwhistory.so   enforce_for_root remember=10

此时用户使用过的密码将会记录到/etc/security/opasswd文件中。但是pam_pwhistory.so并没有什么选项可以限定 密码在多少天之内无法被重复使用,所以上述的90天是无法配置的。一个简单的解决方法就是当90天左右的时候,手动清空一次opasswd文件即可。

当然,如果要实现同样的功能除了pam_pwhistory.so模块之外还有其它的办法。比较常用的是pam_unix.so模块。具体方法是修 改/etc/pam.d/system-auth文件,给pam_unix.so模块里加上remember=10这个选项,修改之后的配置文件为:

password required pam_unix.so md5 remember=10 use_authtok

这样系统将同样记住10个已经使用的密码。

具体情况请参考: http://www.deer-run.com/~hal/sysadmin/pam_unix.html

不过此时/etc/security/opasswd文件因为记录了N个使用过的密码,所以安全性就十分关键了,所以要确保该文件只能被root用户读取和编辑:

# touch /etc/security/opasswd
# chown root:root /etc/security/opasswd
# chmod 600 /etc/security/opasswd

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来 实现系统安全的有效增强。

转载请保留固定链接: https://linuxeye.com/security/474.html

------分隔线----------------------------
标签:linux认证模块PAM
栏目列表
推荐内容