🔐 第08课:PAM认证

阶段二:用户与进程 第2/6课

📚 课程目标

一、PAM概述

1.1 什么是PAM

PAM (Pluggable Authentication Modules) 是Linux的认证框架,将认证逻辑从应用程序中解耦。应用程序只需调用PAM API,具体的认证方式由PAM配置决定。

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Application │────▶│   PAM API    │────▶│  PAM Modules │
│  (sshd/login) │     │  (libpam)    │     │  pam_*.so    │
└──────────────┘     └──────────────┘     └──────────────┘
                           │
                    ┌──────┴──────┐
                    │ PAM Config  │
                    │ /etc/pam.d/ │
                    └─────────────┘

1.2 PAM的优势

二、PAM配置文件

2.1 配置文件位置

$ ls /etc/pam.d/ | head -15
chfn
chpasswd
chsh
common-account
common-auth
common-password
common-session
common-session-noninteractive
cron
login
newusers
other
passwd
runuser
runuser-l

2.2 配置文件格式

# 格式:类型  控制标志  模块路径  [模块参数]
# 示例:
auth    required    pam_sepermit.so
auth    include     common-auth
account required    pam_nologin.so
password requisite  pam_pwquality.so retry=3
session optional    pam_motd.so

2.3 PAM四种类型

类型功能调用时机
auth身份认证验证用户身份(密码/密钥/令牌)
account账户验证检查账户是否有效(过期/锁定/时间限制)
password密码管理修改密码时的策略检查
session会话管理登录/注销时的操作(日志/资源限制/家目录)

2.4 控制标志

标志认证失败后续模块整体结果用途
required记录失败继续执行任一required失败则失败核心认证(必须通过)
requisite立即返回失败停止执行立即失败前置条件检查
sufficient忽略失败继续执行成功则整体成功替代认证方式
optional忽略继续执行仅当唯一模块时有效可选功能
includeN/A引用其他配置按引用内容判定配置复用
substackN/A类似include不影响外层sufficient嵌套配置
理解控制标志的关键:required是"必须通过但继续检查"(不泄露哪个模块失败),requisite是"立即失败"(安全但暴露信息),sufficient是"通过就够了"(快捷认证)。

三、常见PAM模块

3.1 认证模块

模块功能示例
pam_unix.so传统密码认证auth required pam_unix.so
pam_tally2.so登录失败计数与锁定auth required pam_tally2.so deny=5
pam_faillock.so失败锁定(新)auth required pam_faillock.so preauth deny=5
pam_google_authenticator双因素认证auth required pam_google_authenticator.so
pam_sepermit.soSELinux登录限制auth required pam_sepermit.so

3.2 账户模块

模块功能
pam_nologin.so检查/etc/nologin文件,存在时仅允许root登录
pam_time.so基于时间的访问控制
pam_access.so基于IP/用户的访问控制
pam_rootok.soroot免密(su命令使用)

3.3 密码模块

# 密码复杂度配置
# /etc/pam.d/common-password (Debian/Ubuntu)
password requisite pam_pwquality.so retry=3 minlen=8 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1

# 参数说明:
# retry=3        - 最多重试3次
# minlen=8       - 最小长度8
# difok=3        - 与旧密码至少3个字符不同
# ucredit=-1     - 至少1个大写字母
# lcredit=-1     - 至少1个小写字母
# dcredit=-1     - 至少1个数字
# ocredit=-1     - 至少1个特殊字符

3.4 会话模块

模块功能
pam_limits.so设置资源限制(ulimit)
pam_motd.so显示当日消息(Message of the Day)
pam_lastlog.so显示上次登录信息
pam_mkhomedir.so自动创建家目录(LDAP用户)
pam_env.so设置环境变量

四、SSH PAM配置(实机)

$ cat /etc/pam.d/sshd 2>/dev/null | grep -v '^#' | grep -v '^$' | head -15
@include common-auth
account    required     pam_nologin.so
@include common-account
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so close
session    required     pam_loginuid.so
session    optional     pam_keyinit.so force revoke
@include common-session
session    optional     pam_motd.so  motd=/run/motd.dynamic
session    optional     pam_motd.so noupdate
session    optional     pam_mail.so standard noenv # [1]
session    required     pam_limits.so
session    required     pam_env.so # [1]
session    required     pam_env.so user_readenv=1 envfile=/etc/default/locale
session [success=ok ignore=ignore module_unknown=ignore default=bad]        pam_selinux.so open
@include common-password

五、登录失败锁定

# 配置pam_faillock(CentOS 8+/Ubuntu 22.04+)
# 在/etc/pam.d/sshd或login中添加:
auth required pam_faillock.so preauth silent deny=5 unlock_time=900
auth include common-auth
auth [default=die] pam_faillock.so authfail deny=5 unlock_time=900
account required pam_faillock.so

# 查看失败记录
sudo faillock --user username

# 解锁用户
sudo faillock --user username --reset

六、资源限制 — limits.conf

$ cat /etc/security/limits.conf | grep -v '^#' | grep -v '^$' | head -10
N/A
# 格式:域  类型  项目  值
# 域:用户名/@组名/*(所有)/%(maxlogins)
# 类型:soft(软限制)/hard(硬限制)/-(both)
# 项目:core/fsize/nofile/nproc/memlock/等

# 示例配置
* soft nofile 65535        # 所有用户,软限制,最大打开文件数
* hard nofile 65535        # 所有用户,硬限制
@developers hard nproc 500 # developers组,最大进程数
username hard maxlogins 3  # 特定用户,最大登录数
* soft core unlimited      # 允许core dump

七、NSS — 名称服务切换

$ cat /etc/nsswitch.conf | grep -v '^#' | grep -v '^$'
passwd:         files systemd
group:          files systemd
shadow:         files systemd
gshadow:        files systemd
hosts:          files dns
networks:       files
protocols:      db files
services:       db files
ethers:         db files
rpc:            db files
netgroup:       nis

NSS决定系统如何查找用户、组、主机名等信息。配置中files表示本地文件,dns表示DNS查询,ldap表示LDAP目录。

八、故障排查

❌ 问题:PAM配置错误导致无法登录

预防措施:修改PAM配置前,保持一个root会话不退出!

# 1. 测试PAM配置
sudo pam_tally2 --user=username   # 查看失败次数

# 2. 恢复方法:从另一个root会话修正配置
# 3. 单用户模式修复
# 启动时在GRUB添加 init=/bin/bash

# 4. Live CD修复
# 挂载根分区后修改pam配置

九、练习

📝 练习1:配置密码策略

# 1. 查看当前密码策略
sudo pam-config --list 2>/dev/null || grep -v "^#" /etc/pam.d/common-password

# 2. 修改密码最小长度为12
# 编辑 /etc/security/pwquality.conf 或 /etc/pam.d/common-password

# 3. 测试密码策略
sudo passwd testuser   # 尝试设置弱密码,应被拒绝

📝 练习2:配置资源限制

# 设置用户的最大打开文件数
echo "* soft nofile 65535" | sudo tee -a /etc/security/limits.conf
echo "* hard nofile 65535" | sudo tee -a /etc/security/limits.conf

# 验证(需要重新登录生效)
ulimit -n
🏆

成就解锁:认证安全专家

✅ 理解PAM框架与4种控制标志

✅ 掌握常见PAM模块功能

✅ 学会配置密码策略与登录锁定

✅ 了解limits.conf资源限制

十、高级PAM配置

10.1 双因素认证(2FA)

# 安装Google Authenticator PAM模块
sudo apt install libpam-google-authenticator

# 用户初始化(每个用户执行)
google-authenticator

# 配置SSH使用2FA
# /etc/pam.d/sshd 添加:
auth required pam_google_authenticator.so

# /etc/ssh/sshd_config 修改:
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

sudo systemctl restart sshd

10.2 时间限制登录

# /etc/security/time.conf
# 格式:services;ttys;users;times
login;tty*;zhangsan;Wd0800-1800   # 工作日8-18点
sshd;*;!*;Wk0900-1700             # 工作时间

# 在PAM中启用
# /etc/pam.d/login 添加:
account required pam_time.so

10.3 LDAP认证集成

# 安装PAM LDAP模块
sudo apt install libpam-ldapd

# /etc/nslcd.conf 配置LDAP服务器
uri ldap://ldap.example.com
base dc=example,dc=com
ldap_version 3

# PAM自动创建家目录
# /etc/pam.d/common-session
session optional pam_mkhomedir.so skel=/etc/skel umask=077

十一、PAM安全审计

#!/bin/bash
# pam-audit.sh - PAM配置安全审计
echo "===== PAM安全审计 ====="

# 检查PAM配置文件权限
echo "--- 配置文件权限 ---"
ls -la /etc/pam.d/ | head -5

# 检查密码策略
echo "\n--- 密码策略 ---"
grep -v "^#" /etc/pam.d/common-password 2>/dev/null || grep -v "^#" /etc/pam.d/system-auth 2>/dev/null

# 检查是否有空密码账户
echo "\n--- 空密码检查 ---"
sudo awk -F: '($2 == "" || $2 == "!")' /etc/shadow

# 检查root直接登录
echo "\n--- root登录限制 ---"
grep -v "^#" /etc/securetty 2>/dev/null | head -5
grep "PermitRootLogin" /etc/ssh/sshd_config 2>/dev/null

# 检查limits配置
echo "\n--- 资源限制 ---"
grep -v "^#" /etc/security/limits.conf | grep -v "^$"