Rocky Linux 9.6 SSH双因素认证实战:Google Authenticator配置指南

📅 2026/7/5 21:56:11
Rocky Linux 9.6 SSH双因素认证实战:Google Authenticator配置指南
1. 项目概述与核心价值最近在给几台生产环境的Rocky Linux 9.6服务器做安全加固SSH密码登录虽然方便但总感觉像把大门钥匙放在门垫下面心里不踏实。尤其是在当前环境下多一层防护总是好的。于是我决定给这些服务器的SSH登录加上第二道锁——双因素认证。Google Authenticator谷歌身份验证器就成了我的首选方案它不依赖网络离线也能生成动态验证码对于服务器这种关键基础设施来说可靠性是第一位的。这个项目说白了就是在Rocky 9.6系统上让SSH登录过程从“输入密码”变成“输入密码输入手机App上实时变化的6位数字”。即使你的密码不幸泄露攻击者没有你手机上的那个动态码依然无法登录。这对于保护那些暴露在公网、存放着重要数据和服务的服务器来说意义重大。无论你是运维工程师、开发者还是自己折腾家庭服务器的爱好者只要你关心服务器的访问安全这个配置都值得你花上半小时深入研究并部署。整个过程不复杂但里面的细节和坑我踩过不少今天就把最完整、最稳妥的配置路径分享给你。2. 环境准备与依赖安装2.1 系统环境确认与更新动手之前第一件事是确认你的系统环境。我用的是一台全新的Rocky Linux 9.6 Minimal安装确保环境干净。你可以通过cat /etc/redhat-release命令来查看系统版本。确认是Rocky Linux 9.x系列就没问题9.3、9.4、9.5、9.6甚至9.7核心步骤都是相通的。接下来我强烈建议你先更新系统到最新状态。这不是走形式因为后续安装的PAM模块和开发工具包其版本与系统内核和基础库的版本紧密相关更新能避免很多因版本不匹配导致的诡异问题。sudo dnf update -y更新完成后通常需要重启系统以确保所有更新生效特别是内核更新。你可以使用sudo reboot重启。重启后再次登录我们继续。2.2 安装核心依赖包Google Authenticator的PAM模块在默认仓库里没有我们需要通过EPELExtra Packages for Enterprise Linux仓库来获取。EPEL是社区维护的为RHEL及其衍生版如Rocky、CentOS提供大量高质量附加软件包。首先安装EPEL仓库sudo dnf install epel-release -y安装成功后我们就可以安装本次配置的核心软件包了sudo dnf install google-authenticator qrencode -y这里解释一下这两个包google-authenticator 这是主角。它包含了生成密钥、管理用户令牌的命令行工具以及最重要的——与系统PAM可插拔认证模块集成的库文件。PAM是Linux系统身份验证的框架我们就是通过配置PAM让SSH在验证密码后再去调用Google Authenticator进行二次验证。qrencode 这是一个非常实用的辅助工具用于生成二维码。在为用户初始化认证器时手动输入一长串密钥既麻烦又容易出错。用这个工具生成二维码用户用手机App一扫即可绑定体验好得多。除了这两个我们还需要确保系统安装了必要的开发工具和PAM开发库因为从源码编译或某些底层交互可能会用到虽然dnf安装的二进制包通常不需要但有备无患sudo dnf groupinstall Development Tools -y sudo dnf install pam-devel -y安装完成后可以验证一下google-authenticator命令是否可用which google-authenticator如果返回/usr/bin/google-authenticator这样的路径说明安装成功。注意 如果你在安装过程中遇到类似“无法找到 google-authenticator 包”的错误请先确认EPEL仓库是否成功启用。可以运行sudo dnf repolist | grep epel查看。如果没列出可能需要手动下载对应版本的EPEL RPM包进行安装。3. 为用户配置Google Authenticator令牌软件装好了接下来要为需要启用双因素认证的每个用户单独生成一个“种子密钥”。这个密钥是独一无二的会保存在用户的家目录下并需要被录入到用户的手机Authenticator App中比如Google Authenticator, Microsoft Authenticator, Authy等。3.1 生成初始配置切换到你要配置的用户。非常重要一定要在目标用户的登录会话下执行以下命令而不是在root下直接运行。因为生成的配置文件.google_authenticator会保存在当前用户的家目录下并且文件权限是600仅用户自己可读。如果以root身份为其他用户生成权限和归属可能会出问题。# 假设要为用户 ‘alice’ 配置 sudo su - alice # 执行初始化命令 google-authenticator执行命令后会进入一个交互式的配置向导。你会看到几个问题我的选择和理由如下Do you want authentication tokens to be time-based (y/n)输入y。这是默认和推荐的方式基于时间TOTP。另一种是基于计数器HOTP每次登录后计数器递增但需要服务器和客户端同步状态对于SSH场景基于时间的更简单可靠。接着会显示一个大大的二维码如果你的终端支持以及你的“密钥”secret key、验证码verification code和紧急备用码emergency scratch codes。请立即、妥善保存这些信息尤其是备用码万一手机丢失可以用它来登录。你可以用手机App扫描二维码或者手动输入密钥来添加账户。Do you want me to update your “/home/alice/.google_authenticator” file? (y/n)输入y。这会将配置写入家目录下的隐藏文件。Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks. (y/n)输入y。禁止重复使用同一个令牌。这能有效防止重放攻击。虽然意味着30秒内不能连续用同一个码登录两次但对安全性的提升是值得的。By default, tokens are good for 30 seconds. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (for example). Do you want to do so? (y/n)输入n。默认的“时间容差窗口”是前后各一个码共3个有效码。如果你的服务器和手机时间同步良好通过NTP保持默认即可。扩大窗口会降低安全性。只有在你确认时间不同步且无法解决时才考虑选y。If the computer that you are logging into isn’t hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting? (y/n)输入y。启用速率限制。这是非常重要的安全措施可以防止攻击者暴力尝试验证码。默认每30秒最多3次尝试足够你正常登录又能极大增加攻击成本。配置完成后退出当前用户回到有sudo权限的账户exit3.2 关键文件解读与备份现在查看一下用户alice的家目录会发现一个名为.google_authenticator的隐藏文件。sudo cat /home/alice/.google_authenticator你会看到类似以下内容密钥是打乱的示例JBSWY3DPEHPK3PXP RATE_LIMIT 3 30 WINDOW_SIZE 3 DISALLOW_REUSE TOTP_AUTH 12345678 23456789 34567890 45678901 56789012我来逐行解释第一行JBSWY3DPEHPK3PXP这就是核心的“种子密钥”Secret Key。它被编码为Base32字符串。手机App和服务器都拥有这个相同的密钥结合当前时间各自独立计算出相同的6位数字。这个密钥必须绝对保密以开头的行 这些是配置选项对应我们刚才交互式设置的选择。RATE_LIMIT,WINDOW_SIZE,DISALLOW_REUSE,TOTP_AUTH。最后的5行数字 这些就是“紧急备用码”。每个码只能用一次。用掉一个这个文件里对应的行会被删除。请务必将这些备用码抄写在安全的地方比如密码管理器或离线记事本。实操心得 在为生产环境多个用户配置时我习惯在初始化后立即将这个.google_authenticator文件进行加密备份。同时将二维码图片和备用码单独保存。这样即使服务器硬盘损坏或用户家目录误删也能快速恢复用户的2FA配置避免用户被锁死在系统外。备份命令示例sudo tar -czf /secure_backup/2fa_backup_alice.tar.gz -C /home/alice .google_authenticator记得将备份文件放到安全的位置并设置严格权限。4. 配置SSH服务使用PAM认证这是最关键的一步我们要修改两个配置文件PAM的SSH配置和SSH服务本身的配置。在修改前请务必为当前SSH会话开一个“逃生窗口”4.1 保持一个活动的SSH连接不要关闭在你进行以下配置并测试成功之前请确保至少有另一个已经通过密码或密钥登录的SSH会话保持连接。这样万一配置出错导致所有新登录被阻断你还可以通过这个“逃生窗口”回滚配置而不用去机房接显示器键盘。4.2 配置PAM/etc/pam.d/sshdPAM配置文件定义了SSH登录时的认证栈authentication stack。我们需要在密码认证之后追加Google Authenticator验证。编辑PAM配置文件sudo vi /etc/pam.d/sshd找到与auth相关的行。通常你会看到类似auth substack password-auth这样的行。我们需要在这一类认证行的末尾添加Google Authenticator的配置。一个安全且常见的添加位置是在auth required pam_sepermit.so之后auth substack password-auth之前或之后。为了清晰我选择在password-auth这一行之后添加。修改后的相关段落看起来像这样#%PAM-1.0 auth required pam_sepermit.so auth substack password-auth auth required pam_google_authenticator.so nullok关键解释auth 表示这是一个认证类模块。required 表示此模块必须认证成功但如果失败整个认证栈不会立即终止会等所有模块执行完再返回失败。这比requisite失败立即终止更友好便于调试。pam_google_authenticator.so 这就是我们安装的PAM模块。nullok这个参数至关重要它的意思是“如果用户没有配置.google_authenticator文件则跳过此模块视为成功”。这允许你为部分用户启用2FA而其他用户仍仅用密码登录。在初次部署时务必加上nullok并先为一个测试用户配置。等所有用户都配置好后可以考虑移除nullok以强制所有用户必须使用2FA。4.3 配置SSH服务/etc/ssh/sshd_config接下来我们需要告诉SSH服务在认证时要使用PAM。编辑SSH服务配置文件sudo vi /etc/ssh/sshd_config找到并确保以下两个参数被设置ChallengeResponseAuthentication yes UsePAM yesChallengeResponseAuthentication yes 启用质询-应答认证。Google Authenticator的动态码就是通过这种方式交互的。UsePAM yes 启用PAM模块。这通常是默认开启的但检查一下总没错。另一个重要设置确认PasswordAuthentication的设置符合你的预期。如果你希望只允许“公钥2FA”而完全禁用密码登录最安全那么保持PasswordAuthentication no。这样首次认证是公钥第二次认证如果配置了是PAM即Google Authenticator。如果你希望允许“密码2FA”则设置PasswordAuthentication yes。这样首次认证是密码第二次是Google Authenticator。我个人在生产环境推荐“公钥2FA”的组合因为它避免了密码在网络上传输且公钥认证本身就更强。但“密码2FA”对于不习惯管理密钥的用户来说更容易上手。修改完成后保存文件。在重启SSH服务前先检查配置语法是否正确这是一个好习惯sudo sshd -t如果没有任何输出表示语法正确。如果有错误它会提示你哪一行有问题请根据提示修正。现在可以安全地重启SSH服务了sudo systemctl restart sshd重启后千万不要立即关闭你当前的“逃生窗口”SSH会话你需要用一个新的SSH连接来测试配置是否生效。5. 登录测试与故障排查5.1 测试新的登录流程打开一个新的终端窗口尝试用你配置了2FA的用户如alice登录ssh aliceyour_server_ip登录过程会发生变化首先会提示你输入密码如果PasswordAuthentication是yes或者进行公钥认证。认证通过后你会看到一个新的提示Verification code:这时打开你手机上的Google Authenticator App找到对应你服务器或你设置的名字的账户输入当前显示的6位数字。输入正确的验证码回车。如果一切顺利你就会成功登录。恭喜双因素认证已经成功启用。5.2 常见问题与排查技巧实录在实际部署中你可能会遇到一些问题。下面是我踩过坑后总结的排查清单问题1登录时没有出现Verification code:提示直接进去了。可能原因A PAM配置未生效。检查/etc/pam.d/sshd文件确认pam_google_authenticator.so行已添加且拼写正确。确保文件末尾没有空格等异常字符。可能原因B SSH配置未生效。检查/etc/ssh/sshd_config中的ChallengeResponseAuthentication和UsePAM是否都为yes。修改后必须重启sshd服务。可能原因C 当前测试用户的家目录下没有.google_authenticator文件。用sudo ls -la /home/username/检查。如果没有需要以该用户身份运行google-authenticator命令生成。排查命令# 检查PAM配置 sudo grep google-authenticator /etc/pam.d/sshd # 检查SSH配置 sudo grep -E “^(ChallengeResponseAuthentication|UsePAM)” /etc/ssh/sshd_config # 检查用户配置文件 sudo ls -la /home/alice/.google_authenticator问题2提示Permission denied或Invalid verification code。可能原因A 服务器与手机时间不同步。这是最常见的原因。动态码基于精确的30秒时间片计算时间差超过30秒默认窗口就会失败。解决 确保服务器时间同步。安装并启用NTP服务sudo dnf install chrony -y sudo systemctl enable --now chronyd sudo chronyc sources # 查看时间源状态同时检查手机时间是否设置为“自动从网络获取时间”。可能原因B 在Authenticator App中添加账户时密钥输入错误或二维码扫描不完整。解决 删除App中的旧账户重新用google-authenticator命令生成新的二维码和密钥进行绑定。注意重新生成会作废旧的备用码。可能原因C 速率限制触发。如果你在短时间内连续输错多次验证码会被临时阻止。解决 等待30秒再试。可能原因D.google_authenticator文件权限不对。该文件必须仅对所属用户可读权限600。解决sudo chmod 600 /home/alice/.google_authenticator问题3为root用户配置后通过su或sudo切换用户时也要求验证码。原因 如果你在/etc/pam.d/su或/etc/pam.d/sudo文件中也添加了pam_google_authenticator.so模块那么这些操作也会触发2FA。应对 这取决于你的安全策略。如果你希望本地切换用户也需要2FA那就保留。如果觉得麻烦可以不要修改这些文件仅让远程SSH登录需要2FA。问题4紧急情况下备用码也用完了如何登录这是最危险的情况意味着你被完全锁在服务器外。预防优于补救 务必妥善保管备用码并考虑为至少一个管理账号如root保留一个未启用2FA的SSH密钥对将该私钥加密存储在极度安全的地方仅用于紧急救援。最后的物理手段 如果服务器有物理控制台KVM或本地终端你可以从控制台登录然后修改相应用户的PAM配置或删除其.google_authenticator文件以暂时禁用2FA。这就是为什么“逃生窗口”和备份如此重要。6. 生产环境进阶配置与优化基础功能跑通后我们可以考虑一些更贴合生产环境的优化措施。6.1 为不同用户组设置不同策略你可能不想为所有用户强制2FA比如一些用于自动化任务的系统账户。利用PAM的灵活性和nullok参数我们可以实现精细控制。一种方法是使用pam_succeed_if模块。例如我们想让除了deploy用户外的所有用户都使用2FA可以这样修改/etc/pam.d/sshdauth [success1 defaultignore] pam_succeed_if.so user deploy auth required pam_google_authenticator.so nullok这段配置的意思是如果用户是deploy则跳过下一行success1对于其他所有用户则执行pam_google_authenticator.so检查。6.2 与SSH公钥认证结合的最佳实践最安全的组合是SSH公钥认证 Google Authenticator。这样第一次认证公钥解决了“你有什么”私钥的问题第二次认证动态码解决了“你知道什么”随时间变化的码的问题。配置如下/etc/ssh/sshd_config:PasswordAuthentication no # 完全禁用密码登录 PubkeyAuthentication yes ChallengeResponseAuthentication yes UsePAM yes AuthenticationMethods publickey,keyboard-interactive:pamAuthenticationMethods publickey,keyboard-interactive:pam这一行是关键。它指定了认证方法顺序先公钥后键盘交互式即PAM/Google Authenticator。两者都必须成功。用户侧 用户需要先将自己的SSH公钥上传到服务器的~/.ssh/authorized_keys文件中。登录流程 用户连接时首先自动使用私钥认证。成功后系统会弹出Verification code:提示要求输入Google Authenticator的动态码。这种模式下即使私钥泄露没有动态码依然无法登录反之亦然。安全性极高。6.3 日志记录与监控启用2FA后监控认证日志很重要。日志位于/var/log/secureRocky Linux 9。你可以看到成功的2FA登录和失败的尝试。sudo tail -f /var/log/secure | grep google-authenticator失败日志会显示“Invalid verification code”或“Failed to read “/home/user/.google_authenticator”等信息。定期检查这些日志可以帮助你发现暴力破解尝试或配置问题。6.4 批量部署与自动化如果需要为大量用户配置手动运行google-authenticator命令不现实。你可以编写一个脚本自动化这个过程。核心思路是为每个用户生成一个随机密钥可以用openssl rand -base64 20生成然后转换为Base32。用qrencode生成二维码图片。按照固定格式创建.google_authenticator文件。将密钥、二维码和备用码通过安全渠道分发给相应用户。但请注意自动化生成密钥并分发本身引入了密钥管理的新风险。务必确保脚本运行环境的安全以及分发过程的安全如使用加密邮件、内部安全通讯工具等。对于超大规模或合规要求严格的环境可能需要考虑更专业的集中式双因素认证解决方案如FreeRADIUS Google Authenticator模块或商业产品而非这种基于本地文件的分散式管理。