如何在 CentOS 8 上为 SSH 设置多因素身份验证

作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分接受捐款。

介绍

SSH 默认情况下使用密码进行身份验证,并且 大多数 SSH 硬化指令建议使用 SSH 密钥而不是 SSH 密钥。 然而,SSH 密钥仍然只是一个因素,虽然是一个更安全的因素。 通道是您的计算机上的终端,通过加密隧道将数据发送到远程机器。

在本教程中,我们将设置多因素身份验证来对抗这一点。 多因素身份验证(MFA)或 双因素身份验证(2FA)需要超过一个因素来身份验证或登录。

1、你所知道的东西,如密码或安全问题 2.你所拥有的东西,如身份验证应用程序或安全代币 3.你所拥有的东西,如你的指纹或声音

一个常见的因素是OATH-TOTP应用程序,如Google Authenticator。OATH-TOTP(开放身份验证基于时间的一次密码)是一个开放的协议,可以生成一次性密码,通常是每30秒回收六位数的密码。

本文将介绍如何使用 OATH-TOTP 应用程序除了 SSH 密钥外启用 SSH 身份验证。通过 SSH 登录您的服务器将需要两种因素,从而使其比单独使用密码或 SSH 密钥更安全。

如果您正在寻找有关安全 SSH 连接的进一步指导,请查看以下 关于硬化 OpenSSH 的教程硬化 OpenSSH 客户端

前提条件

要遵循本教程,您将需要:

  • 一台 CentOS 8 服务器具有 sudo 非 root 用户和 SSH 密钥,您可以通过以下 初始服务器设置教程来设置。
  • 安装了 OATH-TOTP 应用的智能手机或平板电脑,如 Google Authenticator (iOS, Android)。
  • 另外,您也可以使用名为 'oathtool' 的 Linux 命令行应用来生成 OATH-TOTP 代码。

步骤 1 – 安装 Google PAM

在此步骤中,我们将安装和配置谷歌的PAM。

PAM,即可插入身份验证模块,是Linux系统中用于验证用户的身份验证基础设施,因为谷歌创建了OATH-TOTP应用程序,所以他们还创建了一种PAM,可以生成TOTP,并且完全兼容任何OATH-TOTP应用程序,如Google Authenticator或Authy(https://www.authy.com/)。

首先,添加了EPEL(企业Linux的额外包)重复:

1sudo yum search epel

如果您的存储库具有 EPEL 安装包,您将看到以下输出:

1[secondary_label Output]
2===== Name Matched: epel =====
3epel-release.noarch : Extra Packages for Enterprise Linux repository configuration

现在安装epel-release包以启用EPEL存储库:

1sudo yum install epel-release

但是,如果您没有epel-release包,则可以手动安装存储信息:

1sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

接下来,安装 PAM. 如果这是第一次使用 repo,您可能会被要求接受 EPEL 密钥.一旦被接受,您将不会被要求再次接受该密钥:

1sudo yum install google-authenticator qrencode-libs

当 PAM 安装时,我们将使用附带 PAM 的助手应用来生成您想要添加第二个因素的用户的 TOTP 密钥. 此密钥是基于用户对用户的生成,而不是整个系统的生成。

运行这两个命令来初始化应用程序:

1google-authenticator -s ~/.ssh/google_authenticator

通常,你需要做的就是运行google-authenticator命令,没有参数,但SELinux不允许 ssh daemon 写入您的主文件夹中的.ssh目录之外的文件。

SELinux 是一个强大的工具,可以保护您的系统免受潜在的攻击,值得在执法模式下运行。因此,关闭 SELinux 并不被认为是最好的做法。

运行命令后,您将被问到几个问题,第一个问题是是否应该基于时间的身份验证令牌:

1[secondary_label Output]
2Do you want authentication tokens to be time-based (y/n) y

使用 sequential-based tokens 意味着代码在某个特定时刻开始,然后在每次使用后增加代码。使用 time-based tokens 意味着代码在某个特定时间框架后改变。

回答此问题后,大量的输出将滚动过去,包括一个大QR代码。 使用手机上的身份验证应用程序扫描QR代码或手动键入秘密密密钥。 如果QR代码太大了可以扫描,您可以使用QR代码上方的URL获取更小的版本。

<$>[注] :确保您在安全的地方记录秘密密钥、验证代码和紧急扫描代码,例如密码管理器。

剩下的问题告知PAM如何运作,我们将逐一审查它们:

1[secondary_label Output]
2Do you want me to update your "~/.google_authenticator" file (y/n) y

这将键和选项写入google_authenticator文件. 如果你说不,程序会停止,没有任何东西被写入,这意味着身份验证器不会起作用:

1[secondary_label Output]
2Do you want to disallow multiple uses of the same authentication
3token? This restricts you to one login about every 30s, but it increases
4your chances to notice or even prevent man-in-the-middle attacks (y/n) y

通过回答是的,您正在通过使每个代码在使用后立即过期来防止重播攻击,这将防止攻击者捕捉您刚刚使用的代码并使用它登录:

 1[secondary_label Output]
 2By default, a new token is generated every 30 seconds by the mobile app.
 3In order to compensate for possible time-skew between the client and the server,
 4we allow an extra token before and after the current time. This allows for a
 5time skew of up to 30 seconds between authentication server and client. If you
 6experience problems with poor time synchronization, you can increase the window
 7from its default size of 3 permitted codes (one previous code, the current
 8code, the next code) to 17 permitted codes (the 8 previous codes, the current
 9code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
10between client and server.
11Do you want to do so? (y/n) n

在移动四分钟窗口中回答允许最多17个有效代码。通过回答,您将其限制到1:30分钟滚动窗口中的3个有效代码。除非您在1:30分钟窗口中发现问题,否则回答是更安全的选择。

1[secondary_label Output]
2If the computer that you are logging into isn't hardened against brute-force
3login attempts, you can enable rate-limiting for the authentication module.
4By default, this limits attackers to no more than 3 login attempts every 30s.
5Do you want to enable rate-limiting (y/n) y

率限制意味着远程攻击者只能尝试一定数量的猜测,然后被迫等待一段时间才能再次尝试。

完成此设置后,如果您想要备份您的秘密密钥,您可以将~/.ssh/google-authenticator文件复制到可信的位置。从那里,您可以将其部署到额外的系统或在清洁安装后重新部署。请注意,通过在多个机器上使用相同的密钥,您将引入重播攻击的可能性,如果攻击者能够为一个服务器扫描代码,然后在有效窗口中使用它,针对不同的服务器。

美元(注)

** 注意:** 如果您正在使用一个加密的主文件夹,这是超出本文的范围,您可能需要将 ~./google-authenticator 文件存储在您的主文件夹以外的目录中。

美元

由于我们将配置文件存储在非标准位置,因此我们需要根据其新位置恢复 SELinux 背景。

使用以下命令来做到这一点:

1restorecon -Rv ~/.ssh/

有了这两个更改,我们现在安装并配置了Google Authenticator PAM,下一步是配置SSH以使用您的TOTP密钥,我们需要告诉SSH关于PAM,然后配置SSH以使用它。

步骤 2 — 配置 OpenSSH 以使用 MFA/2FA

因为我们将对 SSH 进行 SSH 更改,所以重要的是永远不要关闭您的初始 SSH 连接,而是打开第二个 SSH 会话来进行测试,以免在您的 SSH 配置中出现错误时将自己锁定在服务器上。一旦一切正常工作,您可以安全地关闭任何会话。 另一种安全预防措施是创建您正在编辑的系统文件的备份,以便在发生错误的情况下,您可以简单地返回瓦尼拉文件并使用清洁的配置重新开始。

首先,备份sshd配置文件,然后编辑它. 在这里,我们正在使用nano,默认情况下没有安装在CentOS上. 您可以使用sudo yum install nano安装它,或者使用您喜爱的替代文本编辑器。

备份文件,然后打开它:

1sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak
2sudo nano /etc/pam.d/sshd

将下列行添加到文件的末尾:

1[label /etc/pam.d/sshd]
2auth required pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator nullok
3auth required pam_permit.so

由于我们不得不将 google_authenticator config 文件放置在非标准位置,所以我们必须为 PAM 提供通往 config 文件的路径。

行末尾的nullok字告诉PAM这种身份验证方法是可选的,这允许没有OATH-TOTP代币的用户仍然使用他们的SSH密钥登录,一旦所有用户都有OATH-TOTP代币,您可以从这个行中删除nullok,使MFA成为强制性的。

使用「pam_permit.so」的第二行需要允许身份验证,如果我用户不使用MFA代码登录时。在登录时,每个方法都需要一个SUCCESS来允许身份验证。如果用户不使用MFA auth工具,则使用「nullok」选项返回一个IGNORE用于交互式键盘身份验证。因此,如果该行被忽视,那么下一行会触发「pam_permit.so」返回SUCCESS并允许进行身份验证。

保存并关闭文件。

接下来,我们将配置SSH以支持此类身份验证。

备份 SSH 配置文件,然后打开以进行编辑:

1sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
2sudo nano /etc/ssh/sshd_config

尋找開始於「ChallengeResponseAuthentication」的行,評論「不」的行,並不評論「是」的行。

你的檔案會看起來像這樣:

1[label /etc/ssh/sshd_config]
2. . .
3# Change to no to disable s/key passwords
4ChallengeResponseAuthentication yes
5#ChallengeResponseAuthentication no
6. . .

保存并关闭文件,然后重新启动SSH以重新加载配置文件.重新启动sshd服务不会关闭我们当前的开放连接,因此您不会冒险用此命令锁定自己:

1sudo systemctl restart sshd.service

要测试到目前为止的一切工作,打开终端窗口,并尝试通过SSH登录. 非常重要的是,你保持当前的SSH会话打开,并通过额外的会话测试,否则你会在某个时候锁定自己并需要使用Web控制台来重新登录。

<$>[注] 注: 如果您之前已经创建了SSH密钥并正在使用它,您将注意到您不必输入用户密码或MFA验证代码,这是因为SSH密钥默认地覆盖了所有其他身份验证选项。

接下来,要将 SSH 密钥作为一个因素和验证代码作为第二个因素,我们需要告诉 SSH 使用哪些因素,并防止 SSH 密钥超过所有其他类型。

步骤 3 – 让 SSH 意识到 MFA

重新打开sshd配置文件:

1sudo nano /etc/ssh/sshd_config

添加下列行到文件底部. 这告诉SSH哪些身份验证方法是必要的. 这个行告诉SSH我们需要一个SSH密钥和一个密码或验证代码(或三个):

1[label /etc/ssh/sshd_config]
2. . .
3AuthenticationMethods publickey,password publickey,keyboard-interactive

保存并关闭文件。

接下来,重新打开 PAM sshd 配置文件:

1sudo nano /etc/pam.d/sshd

查找auth substack password-auth线向文件的顶部。 通过添加一个#字符作为行上的第一个字符来评论它。

1[label /etc/pam.d/sshd]
2. . .
3#auth substack password-auth
4. . .

保存并关闭文件,然后重新启动 SSH:

1sudo systemctl restart sshd.service

现在尝试再次使用不同的终端会话/窗口登录服务器。与上次不同,SSH应该请求您的验证代码。输入后,您将被登录。即使您看不到您的SSH密钥被使用的任何迹象,您的登录尝试使用了两个因素。如果您想要验证,您可以在SSH命令后添加-v(for verbose):

 1[secondary_label Example SSH Output]
 2. . .
 3debug1: Authentications that can continue: publickey
 4debug1: Next authentication method: publickey
 5debug1: Offering RSA public key: /Users/sammy/.ssh/id_rsa
 6debug1: Server accepts key: pkalg ssh-rsa blen 279
 7Authenticated with partial success.
 8debug1: Authentications that can continue: keyboard-interactive
 9debug1: Next authentication method: keyboard-interactive
10Verification code:

在输出的末尾,你会看到SSH在哪里使用你的SSH密钥,然后要求验证代码。你现在可以使用SSH密钥和一次性密码登录SSH。

你现在已经成功地添加了第二个因素,当远程登录到你的服务器通过SSH. 如果这是你想要的 —使用你的SSH密钥和TOTP代币启用MFA为SSH(对于大多数人来说,这是最佳的配置) —那么你完成了。

以下是关于恢复、自动使用等的一些技巧和技巧。

步骤 4 — 添加第三个因素(可选)

在步骤3中,我们列出了在sshd_config文件中批准的身份验证类型:

  1. 公共密钥 (SSH 密钥)
  2. 密码公共密钥 (密码)
  3. 键盘交互式 (验证代码)

虽然我们列出了三个不同的因素,但我们迄今为止选择的选项只允许一个SSH密钥和验证代码,如果你想拥有所有三个因素(SSH密钥,密码和验证代码),一个快速的更改将允许所有三个。

打开 PAM sshd 配置文件:

1sudo nano /etc/pam.d/sshd

查找您之前评论的行, #auth 子堆密码-auth,并通过删除 `#' 字符删除该行评论。

1sudo systemctl restart sshd.service

通过启用auth substack 密码-auth选项,PAM 现在将向您索取密码,除了检查 SSH 密钥并要求验证代码,我们之前已经工作了。

步骤 5 – 恢复访问 Google MFA(可选)

就像你硬化和保护的任何系统一样,你会负责管理安全性,在这种情况下,这意味着不丢失你的SSH密钥或TOTP秘密密密钥,并确保你可以访问TOTP应用程序,但有时事情会发生,你可能会失去对你需要进入的密钥或应用程序的控制。

失去访问秘密钥匙

如果你失去了你的TOTP秘密密钥,恢复可以分成几个步骤。第一步是没有知道验证代码而返回,第二步是找到秘密密密钥或再生正常MFA登录。

失去DigitalOcean Droplet上的TOTP秘密密钥后,您可以从仪表板中使用虚拟控制台(https://andsky.com/tech/tutorials/how-to-use-the-digitalocean-console-to-access-your-droplet)登录,使用您的用户名和密码登录。

如果您正在使用非Droplet系统,那么您有两种恢复访问的选择:

  1. 控制台 (本地/非ssh) 访问系统(通常是物理或通过一些像 iDrac)
  2. 有不同的用户没有MFA启用

第二种选项是更不安全的选项,因为使用MFA的目的在于硬化所有ssh连接,但如果您失去访问MFA身份验证器应用程序,它是安全的。

一旦您登录,有两种方法可以获取TOTP秘密:

  1. 恢复现有密钥
  2. 生成新的密钥

在每个用户的主目录中,秘密密钥和Google Authenticator的设置都被保存在文件中: ~/.ssh/google-authenticator. 该文件的第一行是秘密密钥。 获取密钥的快速方法是执行以下命令,该命令显示了‘google-authenticator’文件的第一行(即秘密钥)。

1head -n 1 /home/sammy/.ssh/google_authenticator

一旦你恢复了现有密钥,你可以手动键入你的身份验证应用程序,然后你应该回到业务,或者你可以填写下面的URL中的相关细节,并让谷歌生成一个QR代码来扫描。

1https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/username@hostname%3Fsecret%3D16-char-secret%26issuer%3Dentry-name-in-auth-app

如果有理由不使用现有密钥(例如,无法轻松安全地与受影响的用户共享秘密密密钥),您可以直接删除 ~/.ssh/google-authenticator 文件,这将允许用户使用单个因素再次登录,假设您没有通过删除 '/etc/pam.d/sshd' 文件中的 'nullok' 选项来执行 MFA。

失去访问 TOTP 应用程序

如果您需要登录到您的服务器,但无法访问您的TOTP应用程序以获取验证代码,您仍然可以使用首次创建秘密密密钥时显示的恢复代码登录。 请注意,这些恢复代码是一次性使用的。 一旦使用来登录,它就不能再次作为验证代码使用。 希望您将其保存到一个可访问的地方,如果您没有TOTP应用程序,但仍然安全。

步骤 6 — 更改身份验证设置(可选)

如果您想在初始配置后更改 MFA 设置,而不是使用更新的设置生成新的配置,您可以简单地编辑 ~/.ssh/google-authenticator 文件。

1[label .google-authenticator layout]
2<secret key>
3<options>
4<recovery codes>

在此文件中设置的选项在选项部分有一个行;如果您在初始设置期间对某个选项回答,则相应的行将被排除在文件中。

以下是您可以对该文件进行的更改:

  • 要启用序列代码而不是基于时间的代码,请将代码到期窗口延长至 4 分钟,将行 " TOTP_AUTH 添加到 " HOTP_COUNTER 1
  • 若要启用单个代码的多个用途,请删除行 " DISALLOW_REUSE.
  • 若要延长代码到期限为 4 分钟,请添加行 " WINDOW_SIZE 17.
  • 若要禁用多个失败登录(率限制),请删除行 " RATE_LIMIT 3 30.
  • 若要更改率限制的门槛,请找到行 `" RATE_LIMIT

步骤 7 – 避免某些帐户的MFA(可选)

例如,某些使用 SSH 的应用程序,如某些 FTP 客户端,可能不支持 MFA. 如果应用程序没有方法请求验证代码,请求可能会停留,直到 SSH 连接时间结束。

只要/etc/pam.d/sshd中的几个选项设置正确,您可以控制用户对用户的基础上使用的因素。

若要允许某些帐户的 MFA 和其他帐户的 SSH 密钥,请确保 `/etc/pam.d/sshd 中的下列设置已启用:

 1[label /etc/pam.d/sshd]
 2#%PAM-1.0
 3auth required pam_sepermit.so
 4#auth substack password-auth
 5
 6. . .
 7
 8# Used with polkit to reauthorize users in remote sessions
 9-session optional pam_reauthorize.so prepare
10auth required pam_google_authenticator.so nullok

在这里,auth substack password-auth被评论,因为密码需要被禁用。如果某些帐户有意禁用MFA,则不能强制MFA,所以在最后一行留下nullok选项。

设置此配置后,只需像任何需要 MFA 的用户一样运行google-authenticator,而不要为只使用 SSH 密钥的用户运行。

步骤 8 — 通过配置管理自动设置(可选)

许多系统管理员使用 配置管理工具,如 Puppet, Chef 或 Ansible,以管理他们的系统. 如果您想要使用这样的系统在创建新用户帐户时安装一个秘密密钥,那么有一个方法可以做到这一点。

「google-authenticator」支持命令行交换,以便在单个非交互式命令中设置所有选项。 若要查看所有选项,您可以键入「google-authenticator --help」。

1google-authenticator -t -d -f -r 3 -R 30 -w 3 -s ~/.ssh/google_authenticator

上面提到的选项如下:

  • -t => 基于时间的计数器
  • -d => 禁用代码重用
  • -f => 强迫编写设置文件而不要求用户
  • -r => 多少次尝试输入正确的代码
  • -R => 几秒钟内用户可以尝试输入正确的代码
  • -w => 有多少代码可以同时有效(这些参考 1:30 分钟 - 4 分钟的有效代码窗口)
  • -s => 存储身份验证文件的路径

它回答了我们手动回答的所有问题,将其保存到一个文件中,然后输出秘密密密钥,QR代码和恢复代码(如果您添加旗帜 -q,那么将不会有任何输出)。

步骤 9 – 强制所有用户使用 MFA (可选)

如果你想强制所有用户的MFA,即使在第一次登录,或者如果你宁愿不依赖你的用户生成自己的密钥,有一个简单的方法来处理这一点。

要做到这一点,配置文件最初创建后,特权用户需要将该文件复制到每个主目录的.ssh 目录,并将其权限更改给相应的用户。

金钱(警告)

警告:这可能是一个安全风险,因为每个人都共享相同的第二个因素。

美元

强制创建用户的秘密密密钥的另一种方法是使用一个 Bash 脚本:

  1. 创建一个 TOTP 代币,
  2. 促使他们下载 Google Authenticator 应用程序并扫描将显示的 QR 代码,以及
  3. 在检查google-authenticator文件是否已经存在后,为他们运行google-authenticator应用程序。

要确保脚本在用户登录时运行,您可以将其命名为 .bash_login,并将其放置在其主目录的根部。

结论

在本教程中,您已将两个因素(SSH 密钥 + MFA 代币)在两个渠道(您的计算机 + 您的手机)中添加到您的服务器中。

记住,如果你正在寻找有关安全 SSH 连接的进一步指导,请查看这些 关于 OpenSSH 硬化的教程OpenSSH 客户端硬化

Published At
Categories with 技术
Tagged with
comments powered by Disqus