SSH Key of type ED25519-SK work with pyinfra==3.1 & paramiko==3.1 but not with newer versions of paramiko (3.2+)
Describe the bug
PyInfra cannot connect to host with ED25519-SK key and paramiko on 3.2+ version (works with 3.1) ED25519-SK is the ssh key type use with a yubikey FA
To Reproduce
- setup a host with ED25519-SK (https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html)
- put the host in inventory.py (test= "XX.XX.XX.XX" ...)
- pyinfra inventory.py exec --limit test -- hostname
Expected behavior
pyinfra should connect to host but give this error:
` File "/home/julien/.local/lib/python3.11/site-packages/paramiko/auth_handler.py", line 394, in _parse_service_accept key_type, bits = self._get_key_type_and_bits(self.private_key) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/julien/.local/lib/python3.11/site-packages/paramiko/auth_handler.py", line 218, in _get_key_type_and_bits if key.public_blob: ^^^^^^^^^^^^^^^ File "/home/julien/.local/lib/python3.11/site-packages/paramiko/agent.py", line 476, in getattr raise AttributeError(name) AttributeError: public_blob 2024-11-20T09:21:46Z <Greenlet at 0x7362bfc313a0: <bound method Host.connect of Host(X.X.X.X)>> failed with AttributeError
--> Disconnecting from hosts... --> An internal exception occurred: `
This seems to be a bug in Paramiko itself: https://github.com/paramiko/paramiko/issues/2462
There are PRs for this issue: https://github.com/paramiko/paramiko/pull/2465 / https://github.com/paramiko/paramiko/pull/2475
I have my own little wrapper script around pyinfra, so I was able to use this approach and it actually helped:
def apply_monkey_pathes():
import paramiko
# https://github.com/paramiko/paramiko/pull/2475
def _get_key_type_and_bits_patched(self, key):
if hasattr(key, "public_blob") and key.public_blob:
return key.public_blob.key_type, key.public_blob.key_blob
else:
return key.get_name(), key
paramiko.AuthHandler._get_key_type_and_bits = _get_key_type_and_bits_patched
apply_monkey_pathes()
I've verified it works on Linux, on Windows it throws "Invalid key", but it's better than nothing. I'll see if anything can be done to make it works on Windows too, but hopes are low, given how finicky yubikey based SSH auth on Windows already is
Other workarounds:
- Specifying a bespoke ssh config with
ssh_config_fileto use a different key for Pyinfra- Doesn't help, probably because Paramiko just consumes the entire ssh-agent and dies anyway if any scary keys are present
- Pass a
ssh_paramiko_connect_kwargs = {'key_filename': 'non-complicated-key'}- Would work, but only works if you have a simple private key available locally, no agent for you.
- Could construct a monkeypatched
paramiko.pkey.PKeyand pass that viassh_paramiko_connect_kwargs- This actually has a chance to work as it's used before Paramiko hurts itself in confusion
- A lot of work, but if someone does it we can all crib off of that.
- Move the hell away from Paramiko, it seems dangerously abandoned.
Move the hell away from Paramiko, it seems dangerously abandoned.
Very much agree with this sentiment