From fb6b4352392034f778e8b7f4a1573d1f0f0233eb Mon Sep 17 00:00:00 2001
From: Noah Stride <noah.stride@goteleport.com>
Date: Thu, 25 Jul 2024 23:26:52 +0100
Subject: [PATCH] Fix Paramiko and SSH multiplexer agent support (#44638)

---
 lib/tbot/service_ssh_multiplexer.go | 13 +++++++++++++
 lib/tbot/tbot_test.go               |  6 ++++++
 2 files changed, 19 insertions(+)

diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go
index fa39915614abe..ea5fab6adf266 100644
--- a/lib/tbot/service_ssh_multiplexer.go
+++ b/lib/tbot/service_ssh_multiplexer.go
@@ -358,6 +358,19 @@ func (s *SSHMultiplexerService) generateIdentity(ctx context.Context) (*identity
 	if err != nil {
 		return nil, trace.Wrap(err, "adding identity to agent")
 	}
+	// There's a bug with Paramiko and older versions of OpenSSH that requires
+	// that the bare key also be included in the agent or the key with the
+	// certificate will not be used.
+	// See the following: https://bugzilla.mindrot.org/show_bug.cgi?id=2550
+	err = newAgent.Add(agent.AddedKey{
+		PrivateKey:   id.PrivateKey,
+		Certificate:  nil,
+		LifetimeSecs: 0,
+	})
+	if err != nil {
+		return nil, trace.Wrap(err, "adding bare key to agent")
+	}
+
 	s.agentMu.Lock()
 	s.agent = newAgent.(agent.ExtendedAgent)
 	s.agentMu.Unlock()
diff --git a/lib/tbot/tbot_test.go b/lib/tbot/tbot_test.go
index ebe10213c5aa7..1b6faa4cb7972 100644
--- a/lib/tbot/tbot_test.go
+++ b/lib/tbot/tbot_test.go
@@ -1081,6 +1081,12 @@ func TestBotSSHMultiplexer(t *testing.T) {
 			out, err := sshSess.CombinedOutput("echo hello")
 			require.NoError(t, err)
 			require.Equal(t, "hello\n", string(out))
+
+			// Check that the agent presents a key with cert and a bare key
+			// for compat with Paramiko and older versions of OpenSSH.
+			keys, err := agentClient.List()
+			require.NoError(t, err)
+			require.Len(t, keys, 2)
 		})
 	}
 }