我正在尝试使用 libpam-google-authenticator 通过 ssh 启用 2FA。并非所有用户都需要启用身份验证器。每个人都使用 ssh 公钥,没有人有密码。我正在运行 Debian buster,我也尝试过 bullseye 的 libpam-google-authenticator。
我的问题是,无论我在 PAM 配置中输入什么,未启用身份验证器的用户永远不会直接登录,但总是要求输入密码。
我已经安装了 libpam-google-authenticator 并使用以下命令配置了 /etc/ssh/sshd_config:
PasswordAuthentication no
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
PasswordAuthentication no
PermitEmptyPasswords no
我无法制定正确的 PAM 配置,以便没有 .google_authenticator 文件的用户仍可登录。根据我使用的方式,要么提示用户输入密码(他们没有密码),要么根本不允许登录。
在 /etc/pam.d/sshd 中我尝试过(像这样尝试在 Ubuntu 14.04.1 上使用公钥(无密码)+ Google 身份验证器进行 SSH):
#@include common-auth
auth required pam_google_authenticator.so debug nullok
在这种情况下,未设置身份验证器的用户将被拒绝,并出现以下调试;
Aug 05 15:11:18 <host> sshd(pam_google_authenticator)[746624]: debug: start of google_authenticator for "<user>"
Aug 05 15:11:18 <host> sshd(pam_google_authenticator)[746624]: debug: end of google_authenticator for "<user>" Result: The return value should be ignored by PAM dispatch
Aug 05 15:11:18 <host> sshd[746620]: error: PAM: Permission denied for <user> from <IP>
是否pam_permit
需要设置后备案例?
我也尝试过前后的各种组合auth required
,auth sufficient
但@include common-auth
它们都导致没有身份验证器的用户被要求输入密码,有时也要求有身份验证器的用户输入密码。
有人有办法实现这个效果吗?
答案1
这是我的工作配置。有些用户启用了身份验证器,有些则没有,并且只允许使用公钥进行 SSH 登录,而不允许使用密码。
在 /etc/ssh/sshd_config 中,
UsePAM yes
PasswordAuthentication no
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
PermitEmptyPasswords no
在 /etc/pam.d/sshd 中,
# Standard Un*x authentication.
#@include common-auth
# Require authenticator, if not configured then allow
auth required pam_google_authenticator.so debug nullok
auth required pam_permit.so
@include comon-auth
必须禁用,因为它包含 pam_unix,我不想使用它。然后您需要pam_permit
让没有身份验证器的用户身份验证成功(pam_google_authenticator
返回 ignore 而不是 pass)。
这仍然不允许 root 使用 ssh 密钥登录;sshd 日志
sshd[1244501]: fatal: Internal error: PAM auth succeeded when it should have failed
讨论SSH 上的 Google Authenticator PAM 阻止没有 2FA 的 root 登录。
按照上述方法操作后,我认为使用 SSH 配置对某些组强制实施 2FA 实际上更好,正如 @zoredache 所建议的那样。这让您可以轻松地将某些 IP 列入白名单,使其不需要 2FA。在这种情况下,sshd_config 例如说
UsePAM yes
PasswordAuthentication no
ChallengeResponseAuthentication yes
#AuthenticationMethods any # default
PermitEmptyPasswords no
Match Group adm Address *,!172.16.1.0/24
AuthenticationMethods publickey,keyboard-interactive
并且 /etc/pam.d/ssh 说
Standard Un*x authentication.
#@include common-auth
# Require authenticator; SSH should not allow any user in who doesn't have it
auth sufficient pam_google_authenticator.so debug nullok
auth requisite pam_deny.so
答案2
我认为您不需要或不想注释掉@include common-auth
。或者至少我没有这样做,而且它似乎可以正常工作。但我仍在测试这一点。
有人有办法实现这个效果吗?
没有时间为您将其翻译成 shell 脚本,但这是 ansible playbook 的摘录,似乎对我有用。我想即使您不使用 ansible,您也应该能够理解它正在做什么。
- hosts: linux_systems
tasks:
- name: Add group 'totp'
group:
name: totp
state: present
system: yes
- name: Create directory for totp secrets
file:
state: directory
path: /var/lib/google-authenticator
owner: "0"
group: "0"
mode: "0700"
- name: install libpam-google-authenticator
apt:
update_cache: yes
cache_valid_time: '{{ apt_cache_valid_time | default(7200) }}'
state: present
name:
- libpam-google-authenticator
- name: Create secret for 'example-user'
args:
creates: /var/lib/google-authenticator/example-user
shell: |
TOTP_USER=example-user; \
google-authenticator \
--force --quiet \
--emergency-codes=10 \
--time-based \
--qr-mode=none \
--allow-reuse \
--window-size=3 \
--rate-limit=4 --rate-time=30 \
--secret=/var/lib/google-authenticator/${TOTP_USER}
- name: update pam
lineinfile:
insertafter: '^@include common-password'
path: /etc/pam.d/login
line: 'auth required pam_google_authenticator.so nullok user=root secret=/var/lib/google-authenticator/${USER}'
- name: update pam
lineinfile:
insertafter: '^@include common-password'
path: /etc/pam.d/sshd
line: 'auth required pam_google_authenticator.so nullok user=root secret=/var/lib/google-authenticator/${USER}'
- name: update sshd ChallengeResponseAuthentication
notify: Restart sshd
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^ChallengeResponseAuthentication .*'
line: 'ChallengeResponseAuthentication yes'
handlers:
- name: Restart sshd
service:
name: sshd
state: restarted