当前位置:首页 > 服务器 > Linux服务器 >  正文信息

Linux-PAM 的工作机制和配置方式

  2016-07-15 17:34:28  来源:运维帮  我来投稿  我要评论

 

 

作者介绍

李广慧是一位Linux系统管理员,现居上海,供职于德邦物流。微信:colinleefish,勿吝批评赐教。

 

正文

本系列讲解了 Linux-PAM 的工作机制和配置方式,还在 Linux-PAM 上做一些有趣的小实验。

 

本文的目标读者是期望了解 PAM 认证机制的 Linux 用户或者系统管理员。如果您是开发人员,希望编写一个使用 PAM 认证的应用程序或者 PAM 模块,本文的内容可能并不能满足您的需求,请参阅《Linux-PAM应用开发指南》(英文:http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_ADG.html)和《Linux-PAM 模块开发指南》(英文:http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_MWG.html)。

 

一、PAM 简介

 

PAM 的全称为“可插拔认证模块(Pluggable Authentication Modules)”。设计的初衷是将不同的底层认证机制集中到一个高层次的API中,从而省去开发人员自己去设计和实现各种繁杂的认证机制的麻烦。如果没有 PAM ,认证功能只能写在各个应用程序中,一旦要修改某个认证方法,开发人员可能不得不重写程序,然后重新编译程序并安装;有了 PAM ,认证的工作都交给 PAM ,程序主体便可以不再关注认证问题了:“ PAM 允许你进来,那你就进来吧。”

 

PAM 机制最初由 Sun 公司提出,并在其 Solaris 系统上实现。后来,各个版本的 UNIX 以及 Linux 也陆续增加了对它的支持。Linux-PAM 便是 PAM 在 Linux 上的实现,获得了几乎所有主流 Linux 发行版的支持。Linux-PAM 的目标同 PAM 一致,都是为了给程序的开发人员提供一套统一的认证接口。本系列中对 PAM 的介绍和实验,如无特别说明,一般都特指 Linux-PAM,实验的环境也均是 Linux。

 

我们先用一个例子来直观感受一下 PAM 。

su 是一个很常用的 Linux 命令,可以让我们从一个用户切换到另一个用户。我们都知道,当用户使用 root 账号登录时,su 到别的用户是不需要密码的,而从其他用户 su 到 root 则需要输入密码。在用 su 命令切换用户的过程中, su 做了两件事:认证(是否是 root、不是 root 的话是否有目标用户的密码)和启动相应的 Shell。

 

让我们来关注一下 su 的认证功能。按照正常的逻辑, su 的开发人员很可能会自己写出认证的功能:先判断是不是 root,是则判定认证通过;不是则要求用户输入目标账号的密码,匹配成功则认证通过,否则不通过。这套逻辑并不复杂,开发人员开发出来便是了。

 

过了几天,用户提出了这样的一个需求:运维团队都属于 wheel 组,能不能让 wheel 组的用户也能不输入密码而使用 su 切换?看起来也不是什么特别困难的需求,开发人员本可以满足就是了。但是如果再过几天,运维小张考虑到安全想要 su有短信验证码功能,而用户小王为了方便测试想要一个完全不用密码的 su。认证需求的差异化越来越明显,开发人员的工作也变得越来越困难。

 

这时,PAM 出现了。PAM 对开发人员说:“认证的事情交给我,你只要告诉我你想做用户认证就好,余下的事情由我来解决,能不能通过由我来说了算。”它又对运维人员说:“你们来我这里编写你们想要的针对 su 的认证策略吧,我将充分保证功能的灵活。”

 

这下好办了。su 的开发人员可以专注地为用户启动 Shell 服务,而不需要关心用户认证的细节了;用户或复杂、或简单的认证需求也都得到了满足。真是皆大欢喜。

 

Linux-PAM 工作的“类别”(type)

 

PAM 的具体工作主要有以下四种类别(type):account,auth,password 以及 session。这里,我们用非定义化的语言来简单解释一下这四种类别。

  • account:在用户能不能使用某服务上具有发言权,但不负责身份认证。比如,account 这个 type 可以检查用户能不能在一天的某个时间段登录系统、这个用户有没有过期、以及当前的登录用户数是否已经饱和等等。通常情况下,在登录系统时,如果你连 account 这个条件都没满足的话,即便有密码也还是进不去系统的。

  • auth:验证“你的确是你”的 type 。一般来说,询问你密码的就是这个 type。假如你的验证方式有很多,比如一次性密码、指纹、虹膜等等,都应该添加在 auth 下。auth 做的另外一件事情是权限授予,比如赋给用户某个组的组员身份等等。

  • password:主要负责和密码有关的工作。修改密码的时候有时会提示“密码不够长”、“密码是个常用单词”之类的,就是在这里设置的。在这里还设置了保存密码时使用了哪种加密方式(比如现在常用的 SHA-512)。请注意,这里的密码不局限于 /etc/shadow 中的密码,有关认证 token 的管理都应该在此设置:如果你使用指纹登录 Linux,在设置新指纹时,如果希望首先验证这是人的指纹而不是狗的指纹,也应该放在这里。

  • session:一个“忙前忙后”的 type,它要在某个服务提供给用户之前和之后做各种工作。比如用户登录之前要将用户家目录准备好,或者在用户登录之后输出 motd 等等。

 

请注意:PAM 不仅仅在用户登录时才发挥作用,sudo命令,su命令,passwd命令都会用到 PAM。前文中所有提及“登录”的地方都仅仅是举例,您完全可以用其他需要用户认证的服务(或者命令)去举例,从而更全面地理解 PAM。

 

二、Linux-PAM 的配置文件

 

PAM 的各个模块一般存放在 /lib/security/ 或 /lib64/security/ 中,以动态库文件的形式存在(可参阅 dlopen(3)),文件名格式一般为 pam_*.so。PAM 的配置文件可以是 /etc/pam.conf 这一个文件,也可以是 /etc/pam.d/ 文件夹内的多个文件。如果 /etc/pam.d/ 这个文件夹存在,Linux-PAM 将自动忽略 /etc/pam.conf。

 

/etc/pam.conf 类型的格式如下:

服务名称  工作类别  控制模式  模块路径  模块参数

/etc/pam.d/ 类型的配置文件通常以每一个使用 PAM 的程序的名称来命令。比如 /etc/pam.d/su,/etc/pam.d/login 等等。还有些配置文件比较通用,经常被别的配置文件引用,也放在这个文件夹下,比如 /etc/pam.d/system-auth。这些文件的格式都保持一致:

工作类别  控制模式  模块路径  模块参数

不难看出,文件夹形式的配置文件中只是没有了服务名称这一列:服务名称已经是文件名了。

 

由于很难在时下的发行版本中找到使用 /etc/pam.conf 这一独立文件作为 PAM 配置的例子,此处仅就 /etc/pam.d/ 格式举例。在笔者安装的 CentOS 7.2.1511 x64 中,/etc/pam.d/login 的内容如下:

 

#%PAM-1.0

auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so

auth       substack     system-auth

auth       include      postlogin

account    required     pam_nologin.so

account    include      system-auth

password   include      system-auth

# pam_selinux.so close should be the first session rule

session    required     pam_selinux.so close

session    required     pam_loginuid.so

session    optional     pam_console.so

# pam_selinux.so open should only be followed by sessions to be executed in the user context

session    required     pam_selinux.so open

session    required     pam_namespace.so

session    optional     pam_keyinit.so force revoke

session    include      system-auth

session    include      postlogin

-session   optional     pam_ck_connector.so

 

# 表示注释。

 

每一行代表一条规则。但也可以用 \ 来放在行末,来连接该行和下一行。

 

例子的最后一行开头有一个短横线 -,意思是如果找不到这个模块,导致无法被加载时,这一事件不会被记录在日志中。这个功能适用于那些认证时非必需的、安装时可能没被安装进系统的模块。

 

工作类别(type)、流程栈(stack)和控制模式(control)

我们在第一篇中接触了 Linux-PAM 的四种工作类别(type)。在上面的例子中,工作类别作为第一列出现。

 

讲到这里,我们有必要聊一聊 PAM 的流程栈(stack)概念:它是认证时执行步骤和规则的堆叠。在某个服务的配置文件中,它体现在了配置文件中的自上而下的执行顺序中。栈是可以被引用的,即在一个栈(或者流程)中嵌入另一个栈。我们之后和它会有更多的接触。

 

第二列为控制模式(control),用于定义各个认证模块在给出各种结果时 PAM 的行为,或者调用在别的配置文件中定义的认证流程栈。该列有两种形式,一种是比较常见的“关键字”模式,另一种则是用方括号([])包含的“返回值=行为”模式。

 

“关键字”模式下,有以下几种控制模式:

  • required:如果本条目没有被满足,那最终本次认证一定失败,但认证过程不因此打断。整个栈运行完毕之后才会返回(已经注定了的)“认证失败”信号。

  • requisite:如果本条目没有被满足,那本次认证一定失败,而且整个栈立即中止并返回错误信号。

  • sufficient:如果本条目的条件被满足,且本条目之前没有任何required条目失败,则立即返回“认证成功”信号;如果对本条目的验证失败,不对结果造成影响。

  • optional:该条目仅在整个栈中只有这一个条目时才有决定性作用,否则无论该条验证成功与否都和最终结果无关。

  • include:将其他配置文件中的流程栈包含在当前的位置,就好像将其他配置文件中的内容复制粘贴到这里一样。

  • substack:运行其他配置文件中的流程,并将整个运行结果作为该行的结果进行输出。该模式和 include 的不同点在于认证结果的作用域:如果某个流程栈 include 了一个带 requisite 的栈,这个 requisite 失败将直接导致认证失败,同时退出栈;而某个流程栈 substack 了同样的栈时,requisite 的失败只会导致这个子栈返回失败信号,母栈并不会在此退出。

 

“返回值=行为”模式则更为复杂,其格式如下:

[value1=action1 value2=action2 ...]

其中,valueN 的值是各个认证模块执行之后的返回值。有 success、user_unknown、new_authtok_reqd、default 等等数十种。其中,default 代表其他所有没有明确说明的返回值。返回值结果清单可以在 /usr/include/security/_pam_types.h 中找到,也可以查询 pam(3) 获取详细描述。

 

流程栈中很可能有多个验证规则,每条验证的返回值可能不尽相同,那么到底哪一个验证规则能作为最终的结果呢?这就需要 actionN 的值来决定了。actionN 的值有以下几种:

  • ignore:在一个栈中有多个认证条目的情况下,如果标记 ignore 的返回值被命中,那么这条返回值不会对最终的认证结果产生影响。

  • bad:标记 bad 的返回值被命中时,最终的认证结果注定会失败。此外,如果这条 bad 的返回值是整个栈的第一个失败项,那么整个栈的返回值一定是这个返回值,后面的认证无论结果怎样都改变不了现状了。

  • die:标记 die 的返回值被命中时,马上退出栈并宣告失败。整个返回值为这个 die 的返回值。

  • ok:在一个栈的运行过程中,如果 ok 前面没有返回值,或者前面的返回值为 PAM_SUCCESS,那么这个标记了 ok 的返回值将覆盖前面的返回值。但如果前面执行过的验证中有最终将导致失败的返回值,那 ok 标记的值将不会起作用。

  • done:在前面没有 bad 值被命中的情况下,done 值被命中之后将马上被返回,并退出整个栈。

  • N(一个自然数):功效和 ok 类似,并且会跳过接下来的 N 个验证步骤。如果 N = 0 则和 ok 完全相同。

  • reset:清空之前生效的返回值,并且从下面的验证起重新开始。

 

我们在前文中已经介绍了控制模式(contro)的“关键字”模式。实际上,“关键字”模式可以等效地用“返回值=行为”模式来表示。具体的对应如下:

  • required: 
    [success=ok new_authtok_reqd=ok ignore=ignore default=bad]

  • requisite: 
    [success=ok new_authtok_reqd=ok ignore=ignore default=die]

  • sufficient: 
    [success=done new_authtok_reqd=done default=ignore]

  • optional: 
    [success=ok new_authtok_reqd=ok default=ignore]

 
模块路径和模块参数

正如前文所述,模块一般保存在 /lib/security 或 /lib64/security 中(取决于操作系统位数)。Linux-PAM 配置文件中的模块位置可以是相对于上述文件夹的相对路径,也可以是文件的全路径。

 

模块参数用空格与模块路径相隔。该参数将只和特定模块相关,因此某个模块的文档中一定包含其参数的信息。如果需要在单个参数中使用空格,可以将整个参数用方括号([])包裹起来。

 

更多有关模块的信息,可参阅 Linux-PAM 的模块文档

 

三、参考文献

在本系列的写作中,笔者参考了如下文章:

关注创业、电商、站长,扫描中国站长网微信二维码,定期抽大奖

    点赞 投稿指南 专题页面 企业会员 责任编辑:运维帮
    作者:运维帮

    图文推荐

    1 2 3 4
     
     

    信息推荐

    文章推荐

    分类排行榜

    专栏文章

    更多>

    服务推荐

    扫一扫关注最新创业资讯