正常的服务器都是使用 用户名+密码或者用户名+ssh key的方式登录,配合防火墙及合理的ssh配置,能达到很好的安全性。但是无论密码还是ssh key都是固定不变的,一旦被渗透等就会导致登录信息泄露,这时如果启用了多因子认证,就能防止黑客通过ssh登录。多因子认证是在原有的认证基础上,在加一个或多个基于时间不断变化的验证码、或生物指纹、面部识别的认证,只要这个信息不泄漏,即使原认证信息泄露也无法登录。

最常见的多因子验证,就是谷歌的两步验证。类linux的系统中,很多软件都是使用pam模块做认证的,谷歌开源了google-authenticator-libpam工具,理论上支持pam认证的软件都可以启用谷歌两步认证。下面就说一下ssh配置两步认证的过程和一些玩法。

一、编译

centos 的epel源中有现成的包,debian中也有,直接使用dnf就能安装,我这里使用编译的方式安装。

dnf install git autoconf automake  make  libtool gcc   

在命令行显示二维码用到 libqrencode ,

dnf install qrencode

两步认证用到了pam认证框架,需安装pam-devel

dnf install pam-devel

编译:

git clone https://github.com/google/google-authenticator-libpam.git
cd google-authenticator-libpam

./bootstrap.sh
./configure

make
sudo make install

主要用到以下两个文件

  1. 执行程序: /usr/local/bin/google-authenticator
  2. pam库文件:/usr/local/lib/security/pam_google_authenticator.so

二、设置时间同步

TOTP是基于时间的,在初始化两步验证之前,先对一下时间,如果有ntpdate命令,执行:

ntpdate time.cloudflare.com

把这这个命令加到定时任务中,一定要确保服务器时间准确。

如果系统是redhat8,系统中ntp已经被chrony替代,执行以下命令:

dnf install -y chrony

systemctl enable chronyd

systemctl start chronyd

查看时间同步时间源服务器:

chronyc sources 

查看同步状态:

chronyc tracking 

三、初始化两步验证

准备工作做完后,就可以初始化两步验证,首先需要手机或个人电脑中安装两步验证的客户端,例如:谷歌验证器、authy等。

3.1 手动初始化

在服务器上执行:

google-authenticator

google-authenticator 初始化步骤:

  第1个:是否想启用基于时间的令牌,选择y

  第2个:是否更新认证文件(root用户是/root/.google_authenticator),由于第一次设置文件不存在,选择y 

  第3个:是否禁止多个用户公用认证口令,有可能会产生中间人欺骗,即令牌用过一次即失效,禁止选择y

  第4个:默认1个口令的有效期是30s,为了防止主机时间和口令客户端时间不一致,最多允许客户端和服务器误差4分钟,服务器上已经设置时间同步,选择n

  第5个:是否启用防暴力破解,30s内不得超过3次登陆测试,选择y

这里需要用手机客户端扫描生成的二维码,初始化完成后会生成两步验证的配置文件,root用户在/root/.google_authenticator,普通用户在/home/user/.google_authenticator,文件的属主要和用户一致,不然会导致无法登录。

3.2 使用参数方式初始化

和手动初始化一样,只是使用参数的方式,不需要交互,方便进行自动化和脚本调用

google-authenticator -t -d -r 3 -R 30 -w 3 -s /root/.google_authenticator
-t: 基于时间的令牌
-d: 不允许令牌重用
-r 3: 限制错误次数为3次
-R 30: 限制验证时间窗口为 30s
-w 3:  验证窗口为3个,当前验证令牌的前一个和后一个均是生效的,也就是允许误差
-s : 保存位置,默认为~/.google_authenticator

四、配置ssh

配置sshd_config,编辑 /etc/ssh/sshd_config,添加:

ChallengeResponseAuthentication yes
UsePAM yes

重启sshd

systemctl restart sshd

五、配置pam

5.1 登录时先输入两步验证码,在输入ssh密码的配置方法

编辑 /etc/pam.d/sshd,在第一行添加:

auth  required  /usr/local/lib/security/pam_google_authenticator.so  [authtok_prompt='请先输入两步验证码:' ]  secret=/root/.google_authenticator  no_increment_hotp

no_increment_hotp :不统计失败的两步认证,防止有被暴力破解时锁定用户。

配置好后,可以用ssh或者xshell客户端登录一下,登录过程:

ssh root@172.16.29.100                                                 
'请先输入两步验证码:'
Password:
Last login: Wed Jan 20 17:09:39 2021 from 172.16.29.1
[root@nixops.me ~]#

5.2 先输入ssh密码,在输入两步验证码

编辑 /etc/pam.d/sshd,在最后一行添加:

   auth  required  /usr/local/lib/security/pam_google_authenticator.so nullok

通过以上的配置,ssh密码 + 谷歌两步验证的登录方式就配置完成了。

六、一些玩法

因为使用了pam框架,有一些基于pam的程序,都可以试着启用两步验证

6.1 普通用户使用su命令时,需要两步验证码

编辑/etc/pam.d/su,找到开头这里:

#%PAM-1.0
auth            required        pam_env.so
auth            sufficient      pam_rootok.so

在 pam_rootok.so这一行下面,加入

    auth required /usr/local/lib/security/pam_google_authenticator.so [authtok_prompt='请先输入两步验证码:' ] secret=/root/.google_authenticator no_increment_hotp

加入后,root切换至普通用户不需要两步验证,普通用户切换至root,或者普通用户之间切换需要先进行两步验证

6.2 sudo命令需要两步验证码

sudo 实际上是以root用户执行命令,在pam的规则中指定一下user即可,编辑/etc/pam.d/sudo,在第一行加入

    auth requisite /usr/local/lib/security/pam_google_authenticator.so [authtok_prompt='请先输入两步验证码:' ] secret=/root/.google_authenticator user=root

6.3 特定IP或者网段不进行两步验证

编辑/etc/pam.d/sshd,在顶部添加:

    auth [success=1 default=ignore] pam_access.so accessfile=/etc/totp_access.conf
    
    auth       required /usr/local/lib/security/pam_google_authenticator.so [authtok_prompt='请先输入两步验证码:' ] secret=/root/.google_authenticator  no_increment_hotp

规则文件/etc/totp_access.conf的内容为:

    + : ALL : 10.20.10.100
    + : ALL : 172.16.19.0/24
    + : ALL : LOCAL
    - : ALL : ALL

6.4 ssh三重认证

安全不在于登录过程中多几道认证,但是对于某些要求较高或者特殊的场景下,可能会有需要多重认证的情况,三重认证包括以下认证方式:

  1. publickey (SSH key)
  2. password publickey (SSH key 的密码)
  3. keyboard-interactive (两步验证码)

和ssh密码认证的方式类似,只是把密码认证改成了ssh publickey + publickey password而已,配置思路也是一样,只是需要sshd_config中多加两条配置,用来指定登录使用的认证方式:

PubkeyAuthentication yes
AuthenticationMethods publickey,password publickey,keyboard-interactive

6.5 多用户启用两步认证

如果服务器中不只有一个用户,pam配置中可以使用变量${USER}来配置多用户,不需要为每个用户写一条pam配置,例如:

auth       required     pam_google_authenticator.so secret=/home/${USER}/.ssh/google_authenticator nullok

如果想做自动化,可以定制一个.bash_profile文件,将这个.bash_profile文件放到/etc/skel/中,这样每次创建用户后就会复制到用户目录下,当用户第一次登录后,调用其中的脚本生成/home/${USER}/.google_authenticator,从而自动绑定两步认证,这里只提供思路,不做具体实现。

参考文章:
https://www.redhat.com/sysadmin/mfa-linux
https://wiki.archlinux.org/index.php/Google_Authenticator
https://www.digitalocean.com/community/tutorials/how-to-set-up-multi-factor-authentication-for-ssh-on-centos-8