Skip to content

Commit

Permalink
ssh: Add retries when to setupProxy
Browse files Browse the repository at this point in the history
When using podman-machine with applehv, sometimes gvproxy would die
shortly after being started.
The following happens:
- podman starts gvproxy with --listen-vfkit
- gvproxy starts and waits for vfkit to create a network connection
- podman starts vfkit
- vfkit creates the VM and connects to gvproxy
- gvproxy resumes its execution, and tries to create the ssh forwards
  podman asked for on the command line
- gvproxy fails to create the ssh forward and exits

This happens because setupProxy fails in (*Bastion).reconnect with
"ssh: handshake failed: EOF". This is related to
https://www.man7.org/linux/man-pages/man8/systemd-user-sessions.8.html
even if it's possible to create a TCP connection to the ssh port,
sshd/pam won't necessarily allow you to connect at the ssh level.

This commit fixes this bug by adding a retry to the calls to
CreateBastion() to complement the retries already present in
initialConnection().
  • Loading branch information
cfergeau committed Jan 11, 2024
1 parent 6ae64dd commit 15db5b1
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 7 deletions.
8 changes: 4 additions & 4 deletions pkg/sshclient/bastion.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ func HostKey(host string) ssh.PublicKey {
return nil
}

func CreateBastion(_url *url.URL, passPhrase string, identity string, initial net.Conn, connect ConnectCallback) (Bastion, error) {
func CreateBastion(_url *url.URL, passPhrase string, identity string, initial net.Conn, connect ConnectCallback) (*Bastion, error) {
var authMethods []ssh.AuthMethod

if len(identity) > 0 {
s, err := PublicKey(identity, []byte(passPhrase))
if err != nil {
return Bastion{}, errors.Wrapf(err, "failed to parse identity %q", identity)
return nil, errors.Wrapf(err, "failed to parse identity %q", identity)
}
authMethods = append(authMethods, ssh.PublicKeys(s))
}
Expand All @@ -100,7 +100,7 @@ func CreateBastion(_url *url.URL, passPhrase string, identity string, initial ne
}

if len(authMethods) == 0 {
return Bastion{}, errors.New("No available auth methods")
return nil, errors.New("No available auth methods")
}

port := _url.Port()
Expand Down Expand Up @@ -149,7 +149,7 @@ func CreateBastion(_url *url.URL, passPhrase string, identity string, initial ne
}

bastion := Bastion{nil, config, _url.Hostname(), port, _url.Path, connect}
return bastion, bastion.reconnect(context.Background(), initial)
return &bastion, bastion.reconnect(context.Background(), initial)
}

func (bastion *Bastion) Reconnect(ctx context.Context) error {
Expand Down
9 changes: 6 additions & 3 deletions pkg/sshclient/ssh_forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,17 @@ func setupProxy(ctx context.Context, socketURI *url.URL, dest *url.URL, identity
return &SSHForward{}, err
}

bastion, err := CreateBastion(dest, passphrase, identity, conn, connectFunc)
createBastion := func() (*Bastion, error) {
return CreateBastion(dest, passphrase, identity, conn, connectFunc)
}
bastion, err := retry(ctx, createBastion, "Waiting for sshd")
if err != nil {
return &SSHForward{}, err
return &SSHForward{}, fmt.Errorf("setupProxy failed: %w", err)
}

logrus.Debugf("Socket forward established: %s -> %s\n", socketURI.Path, dest.Path)

return &SSHForward{listener, &bastion, socketURI}, nil
return &SSHForward{listener, bastion, socketURI}, nil
}

const maxRetries = 60
Expand Down

0 comments on commit 15db5b1

Please sign in to comment.