虽然Linux-PAM从原始的Solaris PAM复制了一大堆想法,但它是在过去的二十年里发展起来的。开发人员添加了新功能,将功能分离到不同的模块中,并为他们可以戴上手套的每一个新硬件设备添加了支持。
本章讨论了Linux-PAM独有的几个模块,这些模块在Debian或CentOS中广泛使用。
为什么要专门用一章来介绍Linux PAM模块,而不对OpenPAM模块一视同仁?
Linux-PAM实现的许多功能在典型的(BSD)OpenPAM系统上是不需要的。BSD系统在PAM甚至Linux创建之前几年就具有用户资源限制等功能,因此不要在PAM中实现这些功能。BSD系统不需要systemd,所以也不需要pam_systemd。
大多数基于OpenPAM的系统都附带了默认Linux-PAM设置中没有的模块,如pam_ssh。然而,这些模块可以作为Linux-PAM的附加组件使用。我们在本书的后半部分分别介绍了其中的许多内容。
PAM允许系统在环境真正存在之前操纵用户的环境。在读取用户自己的shell文件之前,您可以使用 pam_env
在用户环境中分配变量。您可以在auth或session语句中使用 pam_env
。
pam_env
模块从 pam_env特定的配置文件、系统环境文件和用户的环境文件中提取其设置。
主 pam_env
配置文件 /etc/security/pam_env.conf 允许您设置根据用户连接方式而变化的环境变量。您提供一个默认值,然后可能提供一个条件替代值,或者根据需要进行覆盖。规则具有这种通用格式。
variable default override
如果语句没有覆盖,pam_env将为用户设置环境变量。在这里,我们无条件地设置EDITOR变量。
xxxxxxxxxx
EDITOR pico
用户可以用通常的shell配置覆盖此设置,但这允许您设置合理的默认值。
如果这就是pam_env让你做的,那就太蹩脚了。但是pam_env也允许系统根据pam环境做出决策。PAM设置自己的变量,连接的用户可能会带来他们自己环境的一部分。请看以下示例。
xxxxxxxxxx
REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST}
$REMOTEHOST的默认值是 localhost。如果没有其他情况,则假设用户从本地计算机连接。不过,可以使用覆盖。如果PAM项PAM_RHOST存在,我们将$REMOTEHOST设置为该值。@{}语法表示pam_env应检查pam项。
您可能希望依赖用户环境变量,例如$SSH_CLIENT或$DISPLAY。使用${}检查用户环境变量。
xxxxxxxxxx
DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
在 pam_env.conf 的前面,我们为用户分配了一个$REMOTEHOST环境变量。在这里,我们使用它来帮助为$DISPLAY分配一个合理的值。但是,如果用户带了他们自己的$DISPLAY,让他们保留它。
您可以使用 conffile 选项设置另一个PAM配置文件。这使您可以为不同的服务设置不同的环境。您可能需要为FTP用户提供一个特殊的环境,可以在 /etc/pam.d/ftpd 中进行设置。
xxxxxxxxxx
session required pam_env.so conffile=/etc/security/pam_env_ftpd.conf
默认的 pam_env.conf 没有未注释的条目。
您可以使用系统环境文件/etc/environment无条件地将变量锤入用户环境。与 /etc/bash.basshrc 等特定于shell的文件不同,/etc/environment 会影响所有用户,而不管他们的shell是什么。
与 pam_env.conf 不同,/etc/environment 根本不被解释。如果您想要插值和决策,请使用 pam_env.conf 。每行包含一个变量名、一个等号和值,如下所示:
xxxxxxxxxx
IRCSERVER=irc.mwl.io
其他条目不能引用$IRCSERVER的值。下面这样的条目将变量$BABBLE设置为文字字符串$IRCSERVER,而不是irc.mwl.io。
xxxxxxxxxx
BABBLE=$IRCSERVER
用户的shell解释这些值,并可以覆盖它们。
Pam_env使用标志 readenv 来控制读取 /etc/environment 。默认情况下,pam_env读取并使用环境文件。将readenv设置为0以禁用读取环境。
xxxxxxxxxx
session required pam_env.so readenv=0
您还可以使用 envfile 标志、等号(=)和环境文件的完整路径设置其他环境文件。这使您可以为不同的服务设置不同的环境。
用户可以拥有自己的环境文件,您可以在启动时让pam_env读取并强加这些环境文件。这很少是个好主意,但有时这是唯一的想法。userenv pam_env标志允许您设置包含所需环境变量的文件。此文件与用户的主目录相关。将 user_readenv 标志设置为1以启用此功能。
仅当必须在登录过程的早期设置特定用户的环境,并且不能为所有用户设置该环境时,才使用userenv。
用户环境文件的工作方式与系统环境文件完全相同。
PAM模块可以使用用户的环境和PAM项来做出决策。通过调用pam_env,您可以将新变量输入到pam身份验证或会话策略中。pam_env设置的环境变量可能会改变pam决策的结果。
如果允许使用用户环境文件,风险就会增加。虽然PAM模块通常经过精心编程,但我非常不愿意声明用户环境文件不能破坏身份验证过程。用户很聪明。如果您允许用户环境文件,请密切关注您的系统安全和行为。
虽然pam_env手册页声明pam_env应在任何策略中最后出现,以尽量减少影响身份验证或会话配置的环境污染风险,但此建议导致了CVE-2010-4708和CVE-2011-3149等安全漏洞。CentOS和Debian都将pam_env放在策略的首位,以尽量减少风险。
我建议尽可能避免使用pam_env。
Linux-PAM的 pam_succeed_if 模块允许您根据用户帐户设置、要检查的服务和连接执行各种检查。您可以将这些特征中的任何一个与您选择的值进行比较。 在用户级别,pam_succeed_if允许您检查用户名(user)、UID(uid)、GID(gid)、shell和主目录(home)。如果PAM设置了ruser或rhost项目,您可以检查这些项目。最后,您可以检查终端(tty)或服务。
您可以将这些作为数字、字符串和列表成员进行比较。此外,您可以进行基本的用户组成员资格比较,就像pam_wheel一样。如果比较结果匹配,则模块成功。如果比较不匹配,则模块失败。
你几乎可以将任何东西作为字符串进行比较。偶数也可以是字符串,但除了精确匹配外,这是相当有限的。pam_succeed_if允许您使用等号(=)进行精确的字符串比较。您可以通过 != 查看项目是否与字符串不匹配操作员。
此外,您还可以使用globs或shell样式的正则表达式。如果一个项与glob匹配,则 =~ 运算符成功,并且 !~ 如果项目与glob不匹配,则成功。
这是一个Debian配置,用于禁止root用户使用GDM登录。
xxxxxxxxxx
auth required pam_succeed_if.so user != root quiet_success
如果用户不等于字符串 root ,pam_succeed_If 将返回成功。
您可以将UID和GID与数字进行比较。这些对于具有恒定用户和组ID号的已定义应用程序帐户最有用,如www和tcpdump等。使用标准数学运算符表示小于(<)、小于或等于(<=)、大于(>)、大于或等于(>=)。pam_success_if 使用等号和 != 字符串比较中的符号;相反,使用eq表示等于,使用ne表示不等于。
CentOS在系统范围的默认值 /etc/pam.d/system-auth 中使用pam_succeed_if,以防止UID小于1000的用户帐户进行身份验证。
xxxxxxxxxx
auth requisite pam_succeed_if.so uid >= 1000 quiet_success
CentOS为应用程序帐户保留1000及以下的UID。用户帐户以UID 1000开头。UID低于1000的帐户不应进行身份验证。虽然这些帐户中的大多数都通过使用 /sbin/nologin 作为shell来阻止交互式使用,但PAM增加了另一层保护。
xxxxxxxxxx
auth requisite pam_succeed_if.so uid >= 1000 quiet_success
CentOS为应用程序帐户保留1000及以下的UID。用户帐户以UID 1000开头。UID低于1000的帐户不应进行身份验证。虽然这些帐户中的大多数都通过使用 /sbin/nologin 作为shell来阻止交互式使用,但PAM增加了另一层保护。
此处的 quiet_success 选项告诉pam_succeed_if不要吹嘘通过了此测试。
为了将项目与列表进行比较,pam_succeed_if 提供了 in 和 notin 运算符。在运算符后给出比较列表,用冒号分隔,就像这样:
xxxxxxxxxx
thing notin item1:item2:item3
您可以使用这样的列表禁止用户对服务进行身份验证。
xxxxxxxxxx
auth required pam_succeed_if user notin mwl:jkh:des
只要用户不是 mwl 、jkh 或 des,模块就会成功。
Debian使用扩展权限在每个服务的基础上控制PAM。我们将在第10章中看到一个例子。
您可以使用pam_succeed_if检查用户是否是组的成员。如果用户在组中,则 ingroup 运算符返回成功,而如果用户不在组中则 notinggroup 成功。在这里,我们查看用户是否属于组customers。
xxxxxxxxxx
auth sufficient pam_succeed_if.so user ingroup customers
同样,innetgr 运算符检查NIS网络组成员资格,而如果用户不在网络组中,notinnetgr 则返回成功。
LinuxPAM允许您跳过PAM策略中的语句,如第4章所述。这主要用于pam_succeed_if,创建pam规则,如“如果这是真的,跳过策略中的下一个规则”。CentOS通过这样的语句大量使用了此功能配置。
xxxxxxxxxx
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so
我们在这里使用Linux PAM扩展控件来说明,如果PAM_succeed_if返回PAM_SUCCESS S,则跳过一条规则。对于任何其他结果,忽略此模块。如果服务是crond,Pam_succeed_if将返回成功。如果服务是crond,我们跳过一行。
对于crond以外的任何服务,PAM策略都需要PAM_unix模块。
除了标准调试之外,pam_succeed_if还有几个特殊选项。
use_uid 选项告诉PAM使用请求用户的信息而不是目标用户的信息来检查条件。它将模块从使用PAM_USER切换到PAM_RUSER。
quiet 选项告诉模块不要将成功或失败记录到syslog。你可以通过 quiet_success 和 quiet_fail 有选择地只沉默成功或失败。
最后,每当有人检查不存在的用户时,都会进行 audit 日志记录。
在具有分布式用户管理的组织中,使用本地系统帐户识别用户可能是身份验证系统的一个有用部分。仅当系统密码文件中存在帐户时,pam_localuser 模块才会返回成功。
请注意,pam_localuser实际上并不检查用户的本地密码;它只确定帐户是否存在。我见过pam_localuser在本地帐户仅在LDAP完全失败时使用的环境中使用。然而,仅仅存在一个本地帐户就意味着允许用户使用 su(1)
或 sudo(1)
。
您可以使用pam_localuser的替代密码文件。使用 file 选项、等号和文件路径。
Linux-PAM可以对用户施加系统资源限制。系统资源不再像以前那样稀缺,但即使现在,用户也可能启动一个消耗整个CPU或填满主机内存的进程。资源限制有助于防止这些问题。您可以使用 pam_limits 设置资源限制。
运行bash的用户可以使用ulimit查看他们的限制,而基于csh的shell使用limit。
较旧的Linux版本在 /etc/limits.conf 中设置了这些限制。OpenPAM系统通常通过登录类处理此问题,而不是身份验证。
限制属于会话PAM类型。
pam_limits系统有两个组件,pam模块本身和限制文件。虽然您可以将pam_limits指向任何您喜欢的文件,但默认配置文件是 /etc/security/limits.conf 。其他限制文件位于 /etc/security/limes.conf 目录中。limits.conf 中的每一行都有四个字段:域、类型、项和值,如下所示:
xxxxxxxxxx
ftp hard nproc 0
domain 标识此限制适用于哪些用户。您可以按用户、组、通配符以及UID和GID的范围设置限制。在我们的示例中,域是用户 ftp 。
type 指示这是硬限制还是软限制。用户可以覆盖软限制,而硬限制则不受侵犯。我们的例子是一个严格的限制。
item 关键字定义了要限制的资源。Pam_limits包含许多资源关键字,我们稍后将讨论。该示例使用项 nproc
,关键字表示最大进程数。
最后一个字段给出了该资源的最大值。
上面的示例将用户 ftp 限制为最多零个进程。希望这是一个用于FTP服务的帐户;否则,用户Frederic Thomas Powell会相当恼火。
您可以通过用户名、组、UID、GID或通配符来识别受限制的用户。
对于适用于单个用户名的限制,请将用户名用作域。
要使用系统组,请在组名前添加@符号,例如@wheel、@staff或@customers。
星号(*)表示此限制适用于所有用户。“所有用户”不包括root,因为全能的root帐户不受凡人链的约束。如果你想对root应用限制,你必须明确地将root列为域。
Pam_limits使用%作为特殊通配符,专门为 maxlogins 和 maxsyslogins 限制保留。单独使用时,它设置了此主机上非root登录的最大数量。在它后面加一个组名,以设置该组的最大登录次数。
指定一个带有前导冒号的UID,如下所示:
xxxxxxxxxx
:1000
对于一系列UID,给出最低和最高匹配的UID,用冒号分隔。在这里,我们对UID为1000到2000的所有用户设置了限制:
xxxxxxxxxx
1000:2000
如果不设置最大匹配UID,则该限制适用于等于或大于所列UID的所有UID。在这里,我们对所有UID 1000及以上应用限制:
xxxxxxxxxx
1000:
组ID的工作原理与UID非常相似,除了它们前面有一个@符号。用冒号指定范围。如果您正在匹配一系列UID,PAM会将用户的主要组与该范围进行比较。然而,如果你匹配一个特定的组,PAM会查看用户所属的所有组。在这里,如果用户的GID为10000,即使它不是用户的主要组,我们也会施加一个限制:
xxxxxxxxxx
@:10000
将%maxlogins-only通配符与group@通配符组合,以限制组中所有用户的登录总数。在这里,如果你在组10000中,即使这不是你的主要组,你也在限制登录组中:
xxxxxxxxxx
%@:10000
现在决定这是什么样的限制。
Linux-PAM支持两种限制,硬限制和软限制。
软限制是用户可以提高的限制。这是操作系统说“嘿,你真的想使用超过你份额的资源吗?”用户可以通过ulimit或limit等shell内置来提高这个限制。
硬限制是由内核强制执行的绝对上限。用户无法规避此限制。
你应该使用哪一种?大多数用户不知道如何规避软限制,因此它实际上是一个硬限制。如果你有受过教育的用户,可以使用软限制和硬限制。我通常使用限制来限制服务帐户,以防止web服务器和数据库失控。在这种情况下,硬限制是最好的——如果我的网络服务器提高了自己的限制,我就会遇到一系列新的问题…
Linux-PAM可以对文件、内存、进程和登录设置限制。我们不会完全涵盖所有这些限制的含义,因为解释堆栈大小、锁定内存等问题需要另一整本书。
大多数极限值都是数值。一个用户可以打开100个文件,或使用1GB的RAM,等等。但“无限”这个词除外,它消除了对该用户的任何限制。
要设置用户核心文件的最大大小,请使用 core 限制。设置核心可以防止amok进程在最终尖叫并死亡时写入数GB的核心文件。要设置用户可以创建的文件的最大大小,请使用 fsize 限制。core和fsize都以千字节为单位取值。在这里,我们允许customers 的主要组的用户创建1 MB的核心文件:
xxxxxxxxxx
@customers hard core 1024
您还可以使用 nofile 限制用户可以同时打开的文件数量。要限制用户可以锁定的文件数量,请使用锁。下面,customers 组中的用户只能同时打开4096个文件:
xxxxxxxxxx
@customers hard nofile 4096
四个主要的内存限制是数据(data)、内存锁(memlock)、堆栈(stack)和as。所有这些都以千字节为单位设置。data 限制限制了用户在内存中可以拥有的数据量。memlock 值是用户可以锁定到内存中的最大内存量。stack 限制设置了最大堆栈大小,而您可以使用 as 设置地址空间(address space)限制。
您可以使用 msgqueue 限制来限制用户可以为POSIX消息队列申请的最大内存量。与其他内存限制不同,msgqueue以字节为单位。
限制处理器资源的主要方法是通过并发进程的数量和CPU时间的总量。nproc 项允许您设置同时处理的最大数量,而cpu允许您设置以分钟为单位的最大cpu时间。以下是CentOS如何让所有系统用户同时拥有4096个进程,但明确删除了root的任何限制:
xxxxxxxxxx
* soft nproc 4096
root soft nproc unlimited
限制处理器资源的另一种方法是控制操作系统调度用户进程的积极程度。priority 项允许您按照 nice(1)
设置用户进程的默认nicess。值越高,优先级越低。同样,nice 项目允许您设置用户可用的最大nicness。使用优先级是一种很好的(无意双关)方式,可以让用户在资源可用时拥有资源,但在系统加载时将它们分流到一边。在这里,我们告诉用户 mwl 他的任务无关紧要:
xxxxxxxxxx
mwl hard maxlogins 2
记住,当按组成员身份限制登录次数时,您需要使用上面“限制域”中讨论的特殊%通配符。
最后,chroot 限制允许您定义一个目录来 chroot(8)
用户。在大多数情况下,您不会使用pam_limits来chroot用户,而是依赖于 sshd(8)
等服务器软件。
身份验证与 systemd(8)
有什么关系?
Systemd不会对用户进行身份验证。PAM需要在每个用户登录时通知systemd。pam_systemd处理该通信。由于systemd还不是大多数Linux系统的必备组件,pam_systemd通常是一个可选模块。它在会议结束时发布。
pam_systemd的主要功能是管理systemd作用域和XDG基目录。很少有人需要调整其中任何一个,但你应该知道这是可能的。如果你是少数不幸的人之一,请参阅 systemd(8)
手册页了解详细信息。
这将带您了解最常用的Linux-PAM模块。现在让我们来谈谈一些通用的PAM调试。