Skip to content

Conversation

dfaerch
Copy link
Contributor

@dfaerch dfaerch commented Oct 18, 2025

Background

Due to a long-standing Paramiko bug, SSH login can fail when multiple keys are loaded in your SSH agent, depending on how strict the SSH server is.

If the first key Paramiko tries is invalid, it transmits an extra SERVICE_REQUEST before the second key. Since this is incorrect behavior (according to Damien Miller from OpenSSH (golang/go#75268 (comment)), citing the RFC), some SSH servers will reject it. This results in Paramiko raising a “No existing session” error on the second key attempt.

I use ssh2lxd (https://github.com/dfaerch/ssh2lxd) to allow pyinfra to SSH into Incus containers trough a single ssh-daemon running on the host. It’s written in Go and uses the official Go SSH library, which, unfortunately for me, follows the RFC. Damien Miller’s comment above was written in an issue on said library only a month ago, and he additionally notes:

OpenSSH is likely to match x/crypto/ssh's behaviour as it is more correct.

So we might eventually see an OpenSSH release that triggers the same Paramiko bug, suddenly affecting many more users.

Both remain open as of Oct 2025.

At that speed, I don’t know if we can expect a quick response even if OpenSSH tightens this, so I propose a fallback that fixes the issue right now for the few affected and buys time between any OpenSSH change and a Paramiko fix.

My proposed solution

I’ve implemented a fallback that triggers when SSHException is raised during connect and the message is “No existing session.” In that case, pyinfra gathers the agent keys and, in a loop, opens a fresh connection and tries to authenticate with each remaining key.

Opening a new connection per key is slower and not especially elegant, but it avoids having to patch Paramiko. And if you don't hit the bug, everything works as before.


  • Pull request is based on the default branch (3.x at this time)
  • Pull request includes tests for any new/updated operations/facts
  • Pull request includes documentation for any new/updated operations/facts
  • Tests pass (see scripts/dev-test.sh)
  • Type checking & code style passes (see scripts/dev-lint.sh)

Copy link
Member

@Fizzadar Fizzadar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat workaround, very nice - thank you @dfaerch!

@Fizzadar Fizzadar merged commit 6677c61 into pyinfra-dev:3.x Oct 21, 2025
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants