Missing sudo password when using agent-based authentication for sudo

I can ssh and sudo to a give machine manually

ssh mymachine
sudo ls 

This machine is setup with agent-based authentication for sudo (in my case is PKCS11 PIV authentication using a YubiKey) . It’s passwordless, I enter the PIN for the Yubikey once and the ssh-agent on my laptop remembers it.

But it seems this is ignored when connecting via ansible. I can see the “regular ssh” part as user xxxx works, that also uses SSH PIV authentication via the ssh-agent. But when I use become: true then I get the Missing sudo password thing.

Is it possible to use the yubikey PIV authentication for sudo in ansible?

Ansilbe detects the prompt from sudo/su/whatever become system is used and expects to have a password to give to it. No other interactive authentication systems are supported with those become plugins. That said, it ‘might’ work if you feed your Yubikey output as a ‘password’ to Ansible, but depending on the implementation (specially if time based vs list based), it might not work at all. A custom become and connection plugins might be required to handle this, if it is even possible.

but nor ssh nor sudo does not ask for a password at all with this setup .

To be clear

 ssh-add -s /usr/local/lib/libykcs11.dylib # I do this once a day 
Enter passphrase for PKCS#11: 
Card added: /usr/local/lib/libykcs11.dylib

ssh user1@mymachine # this won't ask for password it authenticates using the ssh-agent with the yubikey, it does not ask for yubikey pin either

sudo ls # this won't ask for password nor pin

At the end I tracked down to SSH_AUTH_SOCK environment not being preserved when ansible does the sudo.

I have in my /etc/sudoers a Defaults env_keep += "SSH_AUTH_SOCK" which seems to work fine when I ssh/sudo manually (not via ansible).

But when I do it via ansible I need to use become_flags=--preserve-env=SSH_AUTH_SOCK. Then I don’t get the missing sudo password. How is ansible connection different from the regular ssh?

ansible haproxy -b -m command -a id # with default become_flags
uipath-haproxy-paas | FAILED | rc=-1 >>
Missing sudo password

ansible haproxy -b -m command -a id    # with become_flags=--preserve-env=SSH_AUTH_SOCK  
[WARNING]: Platform linux on host uipath-haproxy-paas is using the discovered Python interpreter at /usr/bin/python3.9, but future installation of another Python interpreter could change the meaning of that
path. See https://docs.ansible.com/ansible-core/2.17/reference_appendices/interpreter_discovery.html for more information.
uipath-haproxy-paas | CHANGED | rc=0 >>
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

^ Ansible detects this prompt waiting AFTER ssh login, it was expecting it to be the sudo prompt and has no password to supply, hence the error.

Ansible handles several interactive prompts via connection/become plugin, that is a expected in an automated system and that is a major difference from executing ssh directly.

But there is no prompt for Enter passphrase for PKCS#11 when doing ssh or sudo. That already happened when I added it to the ssh-agent with ssh-add. The ssh will not trigger any interactive prompt , sudo won’t trigger it either.

It seems the culprit is that SSH_AUTH_SOCK environment is not preserved, when I add become_flags=--preserve-env=SSH_AUTH_SOCK then it works (no password/pin required, no missing sudo password either) .

But I’m still confusedwhy become_flags=--preserve-env=SSH_AUTH_SOCK is required when ansible does the sudo, but not when I do ssh/sudo. The /etc/sudoers have a line to preserve SSH_AUTH_SOCK that seems to work when I interactively ssh/sudo (I never have to enter the password/pin) since it’s already on the ssh-agent.

This is more of a sudo problem than an Ansible one.

When you ssh to a server, you create an interactive tty session with that remote host. When you run Ansible against your inventory, Ansible creates non-interactive tty sessions with the remote hosts.

Sudo has special rules for environment variables, when they are preserved, and when they are not. If you become root, should root use the non-root user’s ENV or load its own? Should it reset the ENV and load defaults? It has rules defined for various scenarios, but has arguments to work around those when exceptions arrise.

In your case, your SSH_AUTH_SOCK environment variable is preserved in your interactive session, but not in Ansible’s non-interactive session. Passing become_flags=--preserve-env=SSH_AUTH_SOCK to become_method=sudo then instructs sudo that it needs to preserve this ENV for the session, when it normally wouldn’t by default.

1 Like