我想为服务帐户(我们称之为“serviceacct”)配置 OpenSSH 6.2p2,并使用空密码执行以下操作:
- 首先尝试公钥认证;如果成功,则运行authorized_keys文件中指定的强制命令。
- 回到空密码验证并运行在其他地方指定的强制命令。
本质上,这会为已知用户提供一种行为,为匿名用户提供一种行为。
在理想情况下,sshd_config 中的这些设置可以实现我想要的效果:
PubkeyAuthentication yes
PasswordAuthentication yes
Match User serviceacct
PermitEmptyPasswords yes
ForceCommand /my/program
但我遇到了几个问题:
ForceCommand /my/program
覆盖在authorized_keys文件中设置的强制命令。- 使用空密码似乎比公钥认证更优先。
除了修改 OpenSSH 服务器之外,还有其他方法可以解决这两个问题吗?我能想到的一个明显的解决方法是只使用两个服务帐户 - 一个用于仅使用公钥身份验证的已知用户,另一个用于仅使用空密码身份验证的匿名用户。如果可能的话,我会尽量避免拥有两个用户帐户。
编辑-为什么我喜欢这种行为
我正在构建一个服务,用于托管各种类型的版本控制系统存储库(Subversion、Git 和 Mercurial)。可以考虑 GitHub 或 Bitbucket,但托管在本地(这是关键,因为我们的一些工作不能离开我们的网站)。可以说,这些版本控制系统中最简单的访问方法是 SSH。
每个存储库都有可配置的已知用户和匿名用户的访问规则。我希望能够支持已知用户和匿名用户使用同一 URL 访问任何版本控制系统。由于托管存储库的用户是 URL 的一部分(例如ssh://user@host/path
),因此如果有两个不同的用户(一个是已知用户,一个是匿名用户),则需要两个不同的 URL。
我应该澄清一个技术细节:我实际上是在使用AuthorizedKeysCommand
sshd_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
将要求用户完成公钥身份验证,然后进行密码或键盘交互身份验证。每个阶段仅提供一个或多个列表中的下一个方法,因此对于此示例,在公钥之前无法尝试密码或键盘交互身份验证。