FreeBSD 中文社区 2025 第二季度问卷调查
FreeBSD 中文社区(CFC)
VitePress 镜像站QQ 群 787969044视频教程Ⅰ视频教程Ⅱ
  • FreeBSD 从入门到追忆
  • 中文期刊
  • 状态报告
  • 发行说明
  • 手册
  • 网络文章集锦
  • 笔记本支持报告
  • Port 开发者手册
  • 架构手册
  • 开发者手册
  • 中文 man 手册
  • 文章
  • 书籍
  • FreeBSD 中文期刊
  • 编辑日志
  • 2025-123 下游项目
    • FreeBSD 发布工程:新主管上任
    • GhostBSD:从易用到挣扎与重生
    • BSD Now 与将来
    • 字符设备驱动教程(第三部分)
    • 学会走路——连接 GPIO 系统
    • FreeBSD 中对 SYN 段的处理
    • FreeBSD 2024 年秋季峰会
  • 2024-1112 虚拟化
    • 字符设备驱动程序教程(第二部分)
    • 面向 Linux 和 Windows 用户的 bhyve
    • Xen 与 FreeBSD
    • Wifibox:一种嵌入式虚拟化无线路由器
    • 嵌入式 FreeBSD:Fabric——起步阶段
    • DGP:一种新的数据包控制方法
    • 会议报告:我在都柏林的 EuroBSDCon 体验
  • 2024-0910 内核开发
    • 字符设备驱动程序教程
    • VPP 移植到了 FreeBSD:基础用法
    • 利用 Kyua 的 Jail 功能提升 FreeBSD 测试套件的并行效率
    • FreeBSD 上的 Valgrind
    • 嵌入式 FreeBSD:探索 bhyve
    • TCP/IP 历险记:FreeBSD TCP 协议栈中的 Pacing
    • 实用软件:实现无纸化(Paperless)
  • 2024-0708 存储与文件系统
    • FreeBSD 中的 NVMe-oF
    • FreeBSD iSCSI 入门
    • 使用 ZFS 原生加密保护数据
    • 嵌入式 FreeBSD:打造自己的镜像
    • TCP LRO 简介
    • 基于 Samba 的时间机器备份
  • 2024-0506 配置管理对决
    • 基本系统中的 mfsBSD
    • rdist
    • Hashicorp Vault
    • 在 GitHub 上向 FreeBSD 提交 PR
    • 悼念 Mike Karels
    • 2024 年 5-6 月来信
    • 嵌入式 FreeBSD 面包板
    • TCP/IP 历险记:TCP BBLog
    • 实用软件:开发定制 Ansible 模块
  • 2024-0304 开发工作流与集成
    • FreeBSD 内核开发工作流程
    • FreeBSD 与 KDE 持续集成(CI)
    • 更现代的内核调试工具
    • 从零开始的 ZFS 镜像及 makefs -t zfs
    • 提升 Git 使用体验
  • 2024-0102 网络(十周年)
    • FreeBSD 中的 RACK 栈和替代 TCP 栈
    • FreeBSD 14 中有关 TCP 的更新
    • if_ovpn 还是 OpenVPN
    • SR-IOV 已成为 FreeBSD 的重要功能
    • FreeBSD 接口 API(IfAPI)
    • BATMAN:更优的可移动热点网络方式
    • 配置自己的 VPN——基于 FreeBSD、Wireguard、IPv6 和广告拦截
    • 实用软件:使用 Zabbix 监控主机
  • 2023-1112 FreeBSD 14.0
    • LinuxBoot:从 Linux 启动 FreeBSD
    • FreeBSD 容器镜像
    • 现在用 Webhook 触发我
    • 新的 Ports 提交者:oel Bodenmann (jbo@freebsd.org)
  • 2023-0910 Port 与软件包
    • 回忆录:与 Warner Losh(@imp)的访谈
    • 在你自己的仓库中定制 Poudriere 源
    • Wazuh 和 MITRE Caldera 在 FreeBSD Jail 中的使用
    • PEP 517
    • CCCamp 2023 旅行报告
  • 2023-0708 容器与云
    • 在 Firecracker 上的 FreeBSD
    • 使用 pot 和 nomad 管理 Jail
    • 会议报告:C 与 BSD 正如拉丁语与我们——一位神学家的旅程
    • 抒怀之旅:与 Doug Rabson 的访谈
    • 基于 Jail 的广告拦截教程
    • 我们收到的来信
  • 2023-0506 FreeBSD 三十周年纪念特刊
    • CheriBSD 近十多年的历程
    • AArch64:成为 FreeBSD 新的一级架构
    • 岁月如梭:我个人的时间线
    • 安装 FreeBSD 1.0:回顾 30 年前
    • ZFS 是如何进入 FreeBSD 的呢?
    • 我不是来自约克郡的,我保证!
    • 回忆录:采访 David Greenman Lawrence
    • FreeBSD 和早期的 Unix 社区
    • 早期的 FreeBSD 移植
    • FreeBSD 30 周年:成功的秘诀
    • FreeBSD 在日本:回忆之旅与今日之实
  • 2023-0304 嵌入式
    • CheriBSD port 和软件包
    • 让我们来试试 ChatGPT
    • GPU 直通
  • 2023-0102 构建 FreEBSD Web 服务器
    • ZFS 的原子 I/O 与 PostgreSQL
    • 虚拟实验室——BSD 编程研讨会
    • ZFS 简介
    • 会议报告:落基山庆祝女性计算机科学家
    • 进行中的工作/征求反馈:数据包批处理
    • 基金会与 FreeBSD 桌面
  • 2022-1112 可观测性和衡量标准
    • 在 FreeBSD 的 DDB 内核调试器中编写自定义命令
    • DTrace:老式跟踪系统的新扩展
    • 基于证书的 Icinga 监控
    • 活动监控脚本(activitymonitor.sh)
    • 实用 IPv6(第四部分)
    • EuroBSDCon 会议报道
    • 实用 Port:Prometheus 的安装与配置
    • 书评:《用火解决问题:管理老化的计算机系统(并为现代系统保驾护航)》Kill It with Fire: Manage Aging Computer Systems (and Future Proof Modern Ones)
  • 2022-0910 安全性
    • CARP 简介
    • 重构内核加密服务框架
    • PAM 小窍门
    • SSH 小窍门
    • 实用 IPv6(第三部分)
    • 书评:Understanding Software Dynamics(深入理解软件性能——一种动态视角)—— Richard L. Sites 著
    • 访谈:保障 FreeBSD 安全性
    • MCH 2022 会议报告
  • 2022-0708 科研、系统与 FreeBSD
    • 在 FreeBSD 上构建 Loom 框架
    • 教授本科生 Unix 课程
    • FreeBSD 入门研讨会
    • 实用 IPv6(第二部分)
    • 在 2022 年及以后推广 FreeBSD
    • 进行中的工作/征求反馈:Socket 缓冲区
    • FreeBSD 开发者峰会报告
    • 支持 Electromagnetic Field 2022
  • 2022-0506 灾难恢复
    • 使用 FreeBSD 构建高弹性的私有云
    • LLDB 14 —— FreeBSD 新调试器
    • 实用 IPv6(第一部分)
    • 利用 netdump(4) 进行事后内核调试
    • 进行中的工作/征求反馈:FreeBSD 启动性能
    • 实用 Port:在 OpenZFS 上设置 NFSv4 文件服务器
  • 2022-0304 ARM64 是一级架构
    • FreeBSD/ARM64 上的数据科学
    • Pinebook Pro 上的 FreeBSD
    • 嵌入式控制器的 ACPI 支持
    • 进行中的工作/征求反馈:Lumina 桌面征集开发人员
    • 实用 Port:如何设置 Apple 时间机器
  • 2022-0102 软件与系统管理
    • 为 FreeBSD Ports 做贡献
    • 使用 Git 贡献到 FreeBSD Ports
    • CBSD:第一部分——生产环境
    • 将 OpenBSD 的 pf syncookie 代码移植到 FreeBSD 的 pf
    • 进行中的工作/征求反馈:mkjail
    • 《编程智慧:编程鬼才的经验和思考》(The Kollected Kode Vicious)书评
    • 会议报告:EuroBSDCon 2021 我的第一次 EuroBSDCon:一位新组织者的视角
  • 2021-1112 存储
    • 开放通道 SSD
    • 构建 FreeBSD 社区
    • 与完美操作系统同行 27 年
    • 进行中的工作/征求反馈:OccamBSD
    • 通过 iSCSI 导入 ZFS ZIL——不要在工作中这样做——就像我做的那样
  • 2021-0910 FreeBSD 开发
    • FreeBSD 代码审查与 git-arc
    • 如何为 FreeBSD 实现简单的 USB 驱动程序
    • 内核开发技巧
    • 程序员编程杂谈
  • 2021-0708 桌面/无线网
    • 通往 FreeBSD 桌面的直线路径
    • FreeBSD 13 中的人机接口设备 (HID) 支持
    • Panfrost 驱动程序
    • 用 Git 更新 FreeBSD
    • FreeBSD 的新面孔
    • 想给你的桌面加点佐料?
  • 2021-0506 安全
    • 七种提升新安装 FreeBSD 安全性的方法
    • copyinout 框架
    • 使用 TLS 改善 NFS 安全性
    • Capsicum 案例研究:Got
    • 对 Jail 进行安全扫描
  • 2021-0304 FreeBSD 13.0
    • 展望未来
    • FreeBSD 13.0 工具链
    • FreeBSD 13.0 中有新加载器吗?
    • TCP Cubic 准备起飞
    • OpenZFS 中的 Zstandard 压缩
    • 会议报告:FreeBSD 供应商峰会
    • Git 不够吗?
  • 2021-0102 案例研究
    • Tarsnap 的 FreeBSD 集群
    • BALLY WULFF
    • Netflix Open Connect
    • FreeBSD 的新面孔
    • 写作学者的 FreeBSD
    • 在世界之巅
  • 2020-1112 工作流/持续集成(CI)
    • FreeBSD Git 快速入门
    • 使用 syzkaller 进行内核 Fuzzing
    • Mastering Vim Quickly 书评
    • 线上会议实用技巧
    • 在控制台上进行网络监控
  • 2020-0910 贡献与入门
    • 采访:Warner Losh,第 2 部分
    • 代码审查
    • 撰写良好的提交消息
    • 如何在不是程序员的情况下做出贡献——成为 FreeBSD 译者
    • 如何成为文档提交者
    • 谷歌编程之夏
    • 为 FreeBSD 期刊撰写文章
    • 你为什么使用 FreeBSD
    • FreeBSD 的新面孔
  • 2020-0708 基准测试/调优
    • FreeBSD Friday
    • 采访:Warner Losh,第 1 部分
    • 构建和运行开源社区
    • 在 FreeBSD 上轻松搭建我的世界(Minecraft)服务器
    • FreeBSD 的新面孔
  • 2020-0506 网络性能
    • 内核中的 TLS 卸载
    • 访谈:Michael W Lucas
    • FreeBSD 桌面发行版
    • 使用 Poudriere 进行 Port 批量管理
    • FreeBSD 的新面孔
由 GitBook 提供支持
LogoLogo

FreeBSD 中文社区(CFC) 2025

在本页
  • 什么是 PAM?
  • PAM 配置
  • 规则类型
  • 控制
  • 模块和参数
  • 阅读策略
  • 添加认证方法
  • PAM 调试
在GitHub上编辑
导出为 PDF
  1. 2022-0910 安全性

PAM 小窍门

上一页重构内核加密服务框架下一页SSH 小窍门

最后更新于1个月前

  • 原文链接:

  • 作者:MICHAEL W LUCAS

可插拔身份验证模块(PAM)也许是 FreeBSD 中最不被理解、但部署最广泛的部分。每个 FreeBSD 系统都通过 OpenPAM 套件使用 PAM。大多数系统管理员都不会去修改它;如果他们不得不更改,只能按照那些看起来模糊合理的网上贴子来操作。PAM 看起来比实际要简单,但这种简单性可能会让你无意中制造出复杂性。使用 PAM 的关键就在于避免这种情况发生。

在本文中,我们将探讨 PAM 的组成部分和配置,帮助你避免一些常见错误,并找出调试错误的方法。

什么是 PAM?

大家都认同,用户名和密码并不是一个理想的认证系统,但对于替代方案却众说纷纭。不同的环境有不同的需求,也许你需要 Kerberos、LDAP 或 SSH 证书;也许你用硬件 DNA 扫描仪,或者用为个人牙齿模型定制的咬合护具来认证系统管理员。每种认证方法都需要自己独立的代码。你可以尝试编译每个程序以支持所有可能的认证方法,但这会导致代码量无限膨胀;或者你可以为每种认证方法构建一个兼容的共享库,仅在需要使用该方法时加载对应的库。这就是“可插拔”的意义所在。每个库就是一个“认证模块”,简称“模块”。

FreeBSD 的 OpenPAM,就像原始 Solaris 的 PAM 一样,只处理认证和与认证相关的任务。如果你曾经使用 Linux,就会发现 Linux-PAM 的开发者认为标准 PAM 过于简单,于是将其他功能挤进了他们的认证栈。而 OpenPAM 中的功能和工具适用于大多数 PAM 栈。

PAM 配置

在 /etc/pam.d 中为 FreeBSD 基本系统配置 PAM,而在 /usr/local/etc/pam.d 中为各个软件包配置 PAM。每个守护进程都有自己的配置文件,其文件名与程序名称相同,用于定义 PAM 策略。比如,你可以去看看 sshd(8) 的配置文件 /etc/pam.d/sshd,你会看到很多类似这样的行。

auth sufficient pam_opie.so no_warn no_fake_prompts
auth requisite pam_opieaccess.so no_warn allow_local
auth required pam_unix.so no_warn try_first_pass
…

每一行对应一条 PAM 规则。每条规则包含四个组成部分:类型、控制、模块以及模块参数。

第一个示例中,规则的类型为 auth,控制为 sufficient,模块为 pam_opie.so,模块参数则为 no_warn 和 no_fake_prompts。

规则类型

认证不仅仅是用户凭据的问题。系统还必须检查是否允许访问、为用户提供资源,并允许对认证系统本身进行管理。这就是类型声明发挥作用的地方。

  • auth 类型:验证用户的认证信息并设置资源限制。如果你错误地输入了密码或提供了一个不存在的用户名,auth 规则会拒绝你。auth 规则还用于设定限制,例如最大进程数或内存使用量。上面已经提到了 auth 规则。

  • account 类型:基于除用户认证之外的限制来控制访问。如果用户尝试在非工作时间登录,account 规则会阻止该访问。

  • session 类型:处理服务器端的设置。一个命令行用户需要一个虚拟终端、一个主目录,并且可能需要一条记录表明他们已经登录。而匿名 FTP 用户则不应获得虚拟终端,并且只能访问特定的目录。session 规则处理所有这些。

  • password 类型:处理认证更新。强制密码更改就是由 password 规则完成的。

控制

你可能在防火墙和服务器配置中见过访问控制列表。PAM 规则类似于访问控制列表。每个模块可以拒绝、失败或者对认证请求“持中立态度”。控制语句告诉 PAM 如何处理每个模块的决策。PAM 有四种常用的控制语句:required、requisite、optional 和 sufficient。

  • required 控制:表示该模块必须返回成功才能允许访问。如果该模块成功,用户将获得访问权限,除非后续的规则阻止访问。即使一个 required 模块失败,PAM 也会继续处理后续规则。

  • requisite 控制:与 required 控制类似,但如果认证模块失败,则规则处理立即停止。这可能会泄露认证失败的原因。

  • optional 控制:用于支持附加功能,比如 SSH 代理或 Kerberos。只有在没有其他模块拒绝或接受该会话的情况下,它们才能决定允许或拒绝访问。你可以用 optional 控制来实现例如在认证失败后增加下次尝试之间的等待时间等功能。

  • sufficient 控制:表示如果该模块成功且之前没有任何 required 控制失败,则用户立即获得访问权限,规则处理随即停止。如果该模块失败,PAM 不会因此拒绝访问。

模块和参数

PAM 模块是实现特定认证功能的共享库。密码处理是一种模块;LDAP 验证是一种模块;与 SSH 代理交互也是一种模块。要理解 PAM 策略,你需要知道每个模块的具体作用。每个 OpenPAM 模块,以及大多数附加模块,都有对应的手册页。当你第一次解析一个 PAM 策略时,会阅读大量的手册页。

每个模块还可以带有参数。虽然每个模块都可以有自己特定的参数以满足其需求,但大多数模块也接受一些通用参数。

  • debug 标志会记录额外的信息,以期帮助你弄清楚为何认证没有按预期工作。

  • no_warn 标志会抑制任何关于认证请求被拒绝原因的用户反馈。

  • 对于密码处理模块,有两个特殊参数:try_first_pass 和 use_first_pass。

    • try_first_pass 选项会重用用户之前输入的密码,但如果不行,该模块可以再次提示用户输入密码。

    • use_first_pass 选项则要求模块使用用户之前输入的密码,如果不成功,则直接拒绝该请求。

阅读策略

让我们再来看一下 sshd(8) 的示例规则。这些都是 auth 规则,因此涉及接受或拒绝登录凭据。先来看第一条规则……

auth sufficient pam_opie.so no_warn no_fake_prompts

这条规则是 sufficient 类型的规则。如果该模块成功,认证请求就被允许,并且规则处理会立即停止。

该模块是 pam_opie.so。根据手册页 pam_opie(8),我们知道它支持 OPIE。你可能需要做一些进一步的研究,以了解 OPIE 是指“一切中的一次性密码”。这条规则声明,如果有人使用 OPIE 进行认证,他们会立即获得访问权限。

auth requisite pam_opieaccess.so no_warn allow_local

这条规则是 requisite 类型的规则。如果它失败,规则处理会立即停止。这看起来……相当严格?

这条规则针对的是另一个 OPIE 模块,pam_opieaccess。既然在前一条规则中使用 OPIE 认证的用户会立即获得访问权限,那么为什么还要有另一条 OPIE 规则呢?查阅 pam_opieaccess(8) 手册可以发现,该模块用于检查用户是否配置为必须使用 OPIE。如果一个用户被配置为必须使用 OPIE,而他们正确地输入了 OPIE 信息,就绝不应该触发这条规则;相反,他们应该被拒之门外。

现在请看第三条规则。

auth required pam_unix.so no_warn try_first_pass

这是一条 required 规则。进入到这一层的用户必须通过该模块,否则将被拒绝访问。 pam_unix(8) 模块检查密码文件,实现标准的用户名和密码认证。因此,该策略可以总结如下:

  • 如果用户通过 OPIE 认证,则立即允许访问;否则继续往下检测。

  • 如果用户被配置为必须使用 OPIE,则拒绝他们。正确输入密码的 OPIE 用户永远不会走到这里。

  • 如果用户输入了正确的用户名和密码,则允许访问。

大多数账户不要求使用 OPIE,因此认证过程会直接转到密码文件的验证。这部分显得非常简略。那么,对于使用无效 shell 或设置为 nologin(8) 的用户呢?或者那些当前不允许登录的用户呢?这些情况属于 account 规则,而不是 auth 规则。如果你查看 /etc/pam.d/sshd,会看到专门检查用户访问权限的 account 规则部分。

添加认证方法

人们通常是在组织开始要求两因素认证时才接触到 PAM。可能是 Google Authenticator、Yubikey 或 Cisco 的 Duo。也许你还有专用的认证硬件,可以读取声纹、指纹或嗅觉特征。接下来,我们将使用后面三种构建一些不太常见的认证规则。下面是一个相当简单的例子。由于我还没看过这些不存在模块的文档,所以我将忽略那些选项。

auth required pam_voice.so
auth required pam_finger.so
auth required pam_aroma.so

这三个策略都是必需的。用户必须提交正确的声纹和指纹,而且还得气味合适,才能完成认证。

auth required pam_voice.so
auth requisite pam_finger.so
auth required pam_aroma.so

中间的策略(针对 pam_finger.so)是 requisite 类型的规则。如果该规则失败,认证检查会立即停止,并且应用程序会收到失败通知。进行气味分析开销很大,我们不希望浪费资源。

也许你希望允许用户选择使用哪种认证方法。

auth sufficient pam_voice.so
auth sufficient pam_finger.so
auth required pam_aroma.so

在这里,我们的前两种认证方法都是 sufficient 类型的。用户可以选择使用声纹或者指纹进行认证。如果这两种方法都失败了,用户就必须提供他们的“臭味”。我也可以将最后一条规则设为 sufficient,但如果策略在此结束,我会希望添加另一条规则,调用 pam_deny.so 来明确拒绝认证。

PAM 调试

你的精心调校的策略不起作用?那就糟糕了。PAM 提供的显式调试非常有限,你只有三个选择:debug 参数、pam_echo 和 pam_exec。

许多模块支持 debug 参数。这可能会将调试信息传递给用户,也可能会将调试信息输出到日志文件,或者什么也不做。模块会忽略不支持的参数,因此在策略中到处添加 debug 参数不会让 PAM 变得更糟。

pam_echo(8) 模块接受一个文本字符串作为参数,这个字符串会传回给用户。这些规则总是设为 optional 类型。让我们在其中一个实验性策略中添加一些 echo 调试信息。

auth optional pam_echo.so “auth policy starting, trying voice”
auth sufficient pam_voice.so
auth optional pam_echo.so “voice failed, trying finger”
auth sufficient pam_finger.so
auth optional pam_echo.so “finger failed, taking a whiff”
auth required pam_aroma.so
auth optional pam_echo.so “how did we get here?”

如果你觉得这看起来就像在代码中到处散布 printf() 调用,那你说对了。对于 1990 年代的 Sun 来说这已经足够用了,对你来说也同样适用。

如果程序将输出反馈给用户,他们将在终端上看到调试语句。如果 debug 参数没有提供有用的信息,而且程序也不会将调试输出回显给用户,那么你就可以使用 pam_exec(8) 来进行更复杂的调试。

pam_exec 模块可以为你执行任意命令。是的,这意味着你可以编写 Perl 脚本,通过网络从 Microsoft Excel 表格中验证用户凭据,但我希望你不会因此而自讨苦吃。大多数情况下,pam_exec 只是让入侵者有机会干扰你的认证过程,不过它非常适合用来调用一个小型的 shell 脚本。比如这样:

auth optional pam_exec.so /usr/sbin/pamdebug.sh pam_voice
auth sufficient pam_voice.so
auth optional pam_exec.so /usr/sbin/pamdebug.sh pam_finger
auth sufficient pam_finger.so
auth optional pam_exec.so /usr/sbin/pamdebug.sh pam_aroma
auth required pam_aroma.so
auth optional pam_exec.so /usr/sbin/pamdebug.sh impossible_end_of_pam_rule

脚本本身非常简单。

#!/bin/sh
logger “process $PPID calling $1”

这会记录进程 ID 以及你当前处于认证的哪个阶段。你肯定不会希望在一个忙碌的生产环境中运行它——那里的用户不断登录和注销——但在测试系统上调试时,这会使工作变得简单。

PAM 拥有的功能和选项远比我在这篇短文中能介绍的要多,但希望你已经大致了解了如何修改规则并微调认证,以达到你期望的方式来“惹恼”用户。

祝你好运。


MICHAEL W LUCAS 是《Absolute FreeBSD》、《FreeBSD Mastery: Jails》以及其他四十八本书的作者,其中一本便是(请鼓掌)《PAM Mastery》。了解更多信息,请访问 。

PAMTricks and Tips
https://mwl.io