Ansible 失败并显示 "Permission denied (keyboard-interactive)"

Ansible fails with "Permission denied (keyboard-interactive)"

我有两台不同的机器,我可以使用企业 VPN 和代理在 SSH 中连接。

为此,我的 ~/.ssh/config 有两个这样定义的主机:

Host foobar
  User alice
  HostName XXX.XXX.XXX.XXX
  ProxyCommand nc -x proxy-socks.foobar.com:4242 %h %p

两个主机的 ProxyCommand 相同,只有 HostNameUser 不同。每个主机都有我的 public 密钥,我只需输入 ssh foobar 即可连接到每个主机,不需要密码。

现在,我尝试在这些机器上使用ansible。我有一个类似 inventory.cfg 的列表,其中列出了我的 ~/.ssh/config:

中定义的两台机器的名称
[vpn]
foobar
barfoo

我尝试了这个简单的命令:

ansible -i inventory.cfg vpn -m ping

这适用于其中一台机器,但不适用于另一台机器。这是编辑后的输出:

foobar | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}
barfoo | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: Welcome on barfoo [...] Permission denied (keyboard-interactive).",
    "unreachable": true
}

由于我在输出中收到了来自主机的“欢迎”消息,这意味着我确实到达了主机(因此代理配置应该没问题)。 但我无法理解错误“权限被拒绝(键盘交互)”。我可以通过 SSH 连接到这台机器而无需密码(事实上,管理员甚至禁用了密码验证,我不得不通过电子邮件将我的 public 密钥发送给他们)。

我试图通过添加 --private-key $HOME/.ssh/id_rsa 来明确指定我的 SSH 密钥,但错误消息完全相同。

出于好奇,我尝试使用 Python 的包 fabric,但这对两台机器都很好:

import fabric
fabric.Connection('barfoo').run('hostname')

所以在 ansible 和这台机器配置之间似乎发生了一些奇怪的事情。有什么线索吗?


编辑

根据@GeralexGR 的建议,我在 ansible 命令中添加了 -vvvv 以获得更多输出。

在输出中,我可以看到 ansible 正在调用 SSH :

ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o 'ControlPath="/home/alice/.ansible/cp/dbd7338475"' barfoo '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''

通过反复试验,我可以将这个命令简化为这个命令:

ssh -vvv -o PreferredAuthentications=publickey barfoo 'hostname'

此命令在一台机器上失败,但在另一台机器上失败。但是,如果我删除 PreferredAuthentications 选项,它在两台机器上都能正常工作。

当它失败时,它输出类似的东西:

debug1: Next authentication method: publickey
debug1: Offering public key: [...]
[...]
debug1: Server accepts key: [...]
[...]
Authenticated with partial success.
debug1: Authentications that can continue: keyboard-interactive
debug3: start over, passed a different list keyboard-interactive
debug3: preferred publickey
debug1: No more authentication methods to try.

如果我删除此选项并执行简单的 ssh -vvvv,我将在输出中得到以下内容:

debug1: Next authentication method: publickey
debug1: Offering public key: [...]
[...]
debug1: Server accepts key: [...]
[...]
Authenticated with partial success.
debug1: Authentications that can continue: keyboard-interactive
[...]
debug1: Next authentication method: keyboard-interactive
debug2: userauth_kbdint
[...]
debug1: Authentication succeeded (keyboard-interactive).

所以,我的猜测是这台机器需要 keyboard-interactive。事实上,如果我把 publickeykeyboard-interactive 都放在选项中,这有效:

ssh -vvv -o preferredauthentications=publickey,keyboard-interactive barfoo 'hostname'

所以,回到ansible,我试过这个:

ansible -vvvv --ssh-extra-args='-o preferredauthentications=publickey,keyboard-interactive' -i inventory.cfg -m ping vpn

但还是失败了,我猜这个认证机制在ansible中是不可能的?我不确定这里是否需要 why/how keyboard-interactive,因为我从来没有被提示输入密码。我去问机器的管理员

解决方案由@Zeitounator 在评论中友情提供。

我在 inventory.cfg 文件中添加了这两行(使用虚拟密码):

[vpn:vars]
ansible_ssh_pass=foo

现在初始 ansible 命令运行良好。

或者,在命令行中使用 --ask-pass 选项也可以:

ansible --ask-pass -i inventory.cfg -m ping vpn

对于上下文,我向机器的管理员询问了更多信息。这台机器不要求我输入密码或任何东西,但是,它要求一些外部用户(不是我)接受一些条款和条件。这就是为什么需要 keyboard-interactive 机制。