Verified Production Fix
[docker/cli] Use native golang ssh when creating SSH docker client
GH-docker/cli#6572 • Mar 07, 2026
### ROOT CAUSE
The Docker CLI's Go client is currently using the system's `ssh` binary to establish SSH connections, which introduces potential security risks and complicates FIPS compliance. The Go standard library provides a robust native SSH client that supports FIPS algorithms without relying on external tools, making it a more secure and reliable choice.
### CODE FIX
To fix this issue, we will replace the system `ssh` binary usage with Go's native SSH client library (`golang.org/x/crypto/ssh`). This change will ensure that the Docker CLI uses a FIPS-compliant SSH implementation directly from the Go standard library.
Here's how to modify the code:
1. **Replace the SSH command execution with Go's SSH client**:
- Remove the code that executes the `ssh` command.
- Use Go's `ssh` package to create an SSH client connection directly.
2. **Update Imports**:
Add the following import to the top of the file:
import (
"golang.org/x/crypto/ssh"
"net"
"os"
"syscall"
)
3. **Modify the SSH Connection Handling**:
Replace the existing SSH connection code in `connhelper.go` with the following implementation:
// Create an SSH client using Go's native library
func createSSHClient(addr, user, keyPath string) (*ssh.Client, error) {
// Read the private key
key, err := os.ReadFile(keyPath)
if err != nil {
return nil, fmt.Errorf("failed to read private key: %v", err)
}
// Create a dialer to connect to the SSH server
dialer := net.Dialer{}
conn, err := dialer.Dial("tcp", addr)
if err != nil {
return nil, fmt.Errorf("failed to dial SSH server: %v", err)
}
// Create an SSH client from the connection
sshClient, err := ssh.NewClientConn(conn, &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.PublicKeyCallback(func() (string, error) {
return string(key), nil
}),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
})
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to create SSH client: %v", err)
}
return sshClient, nil
}
4. **Replace SSH Command Execution**:
Update the code that previously executed the `ssh` command with the new `createSSHClient` function.
For example, replace:
exec.Command("ssh", "-o", "StrictHostKeyChecking=no", ...)
With:
client, err := createSSHClient(addr, user, keyPath)
if err != nil {
// Handle error
}
defer client.Close()
5. **Test the New Implementation**:
Add test cases to verify that the new SSH client works as expected.
func TestCreateSSHClient(t *testing.T) {
// Setup test server
server := &Server{...}
server.Start()
defer server.Stop()
// Test client creation
client, err := createSSHClient(server.Addr, "user", "path/to/key")
if err != nil {
t.Fatalf("Failed to create SSH client: %v", err)
}
defer client.Close()
// Test SSH connection
// ...
}
By making these changes, the Docker CLI will use Go's native SSH client, ensuring better security, FIPS compliance, and reducing dependency on external tools.
Deploy with DigitalOcean
Use this fix in production instantly. Claim your $200 developer credit.
Get Started →
digital