配置 OpenSSH 以首选公钥认证,然后恢复为空密码认证

配置 OpenSSH 以首选公钥认证,然后恢复为空密码认证

我想为服务帐户(我们称之为“serviceacct”)配置 OpenSSH 6.2p2,并使用空密码执行以下操作:

  1. 首先尝试公钥认证;如果成功,则运行authorized_keys文件中指定的强制命令。
  2. 回到空密码验证并运行在其他地方指定的强制命令。

本质上,这会为已知用户提供一种行为,为匿名用户提供一种行为。

在理想情况下,sshd_config 中的这些设置可以实现我想要的效果:

PubkeyAuthentication yes
PasswordAuthentication yes
Match User serviceacct
  PermitEmptyPasswords yes
  ForceCommand /my/program

但我遇到了几个问题:

  1. ForceCommand /my/program覆盖在authorized_keys文件中设置的强制命令。
  2. 使用空密码似乎比公钥认证更优先。

除了修改 OpenSSH 服务器之外,还有其他方法可以解决这两个问题吗?我能想到的一个明显的解决方法是只使用两个服务帐户 - 一个用于仅使用公钥身份验证的已知用户,另一个用于仅使用空密码身份验证的匿名用户。如果可能的话,我会尽量避免拥有两个用户帐户。

编辑-为什么我喜欢这种行为

我正在构建一个服务,用于托管各种类型的版本控制系统存储库(Subversion、Git 和 Mercurial)。可以考虑 GitHub 或 Bitbucket,但托管在本地(这是关键,因为我们的一些工作不能离开我们的网站)。可以说,这些版本控制系统中最简单的访问方法是 SSH。

每个存储库都有可配置的已知用户和匿名用户的访问规则。我希望能够支持已知用户和匿名用户使用同一 URL 访问任何版本控制系统。由于托管存储库的用户是 URL 的一部分(例如ssh://user@host/path),因此如果有两个不同的用户(一个是已知用户,一个是匿名用户),则需要两个不同的 URL。

我应该澄清一个技术细节:我实际上是在使用AuthorizedKeysCommandsshd_config 中的指令,它指示 sshd 使用外部程序的输出而不是读取 ~/.ssh/authorized_keys 文件。

答案1

IIUC 您希望对通过 ssh 密钥或无需任何密码登录的人使用相同的帐户,并且您希望区分这两种身份验证方法。

我认为这是可行的,像这样,第一个服务器部分:

$ sshd --help 2>&1 | sed -n '2p'
OpenSSH_7.9, LibreSSL 2.8.2
$ grep ^Expose /etc/ssh/sshd_config                                                                               
ExposeAuthInfo yes

$ man sshd_config | col -b | sed -n '/ExposeAuthInfo/,/^$/p'
     ExposeAuthInfo
             Writes a temporary file containing a list of authentication
             methods and public credentials (e.g. keys) used to authenticate
             the user.  The location of the file is exposed to the user
             session through the SSH_USER_AUTH environment variable.  The
             default is no.

您还需要调整 sshd_config 以实现无密码登录。我建议使用类似这样的方法,将其保存PermitEmptyPasswords no在配置文件的全局部分!

Match User specialuser
    PermitEmptyPasswords yes
    AuthenticationMethods publickey none
    ForceCommand /path/to/wrapper

让我们制作一个测试包装器(为了方便,我暂时将其放入~/.ssh/authorized_keys)...

$ grep ^command $HOME/.ssh/authorized_keys
command="$HOME/test.sh" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILleQxrJU7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ cat ~/test.sh
#!/bin/sh
set -x
printenv | egrep "^(SSH_ORIGINAL_COMMAND|SSH_USER_AUTH)"

if [[ -r ${SSH_USER_AUTH} ]]; then
    cat ${SSH_USER_AUTH}
    if grep -q ^publickey ${SSH_USER_AUTH} ; then
        echo "XXX I've logged with a public key!"
    else
        echo "XXX I've NOT logged with a public key!"
    fi
fi

if [[ -z "${SSH_ORIGINAL_COMMAND}" ]]; then
    exec ${SHELL}
else
    exec ${SHELL} -c "${SSH_ORIGINAL_COMMAND}"
fi

让我们尝试使用公钥进行 ssh。

$ ssh -l specialuser remote_server
+ printenv
+ egrep ^(SSH_ORIGINAL_COMMAND|SSH_USER_AUTH)
SSH_USER_AUTH=/tmp/sshauth.UTmBQYIadWVem97
+ cat /tmp/sshauth.UTmBQYIadWVem97
publickey ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILleQxrxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ grep -q ^publickey /tmp/sshauth.UTmBQYIadWVem97
+ echo XXX I've logged with a public key!
XXX I've logged with a public key!
+ exec /bin/ksh
$

我不会为您测试无密码登录,但我认为我们这里已经具备了所需的所有部分;)

答案2

难道不是那回事?

man /etc/ssh/sshd_config

  • AuthenticationMethods
    • 指定必须成功完成才能授予用户访问权限的身份验证方法。必须遵循此选项由一个或多个以逗号分隔的身份验证方法名称列表。成功的身份验证需要至少完成这些列表之一
    • 例如,的参数publickey,password publickey,keyboard-interactive将要求用户完成公钥身份验证,然后进行密码或键盘交互身份验证。每个阶段仅提供一个或多个列表中的下一个方法,因此对于此示例,在公钥之前无法尝试密码或键盘交互身份验证。

相关内容