You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/cmd/commands/connect/ssh.go

94 lines
2.7 KiB

package connect
import (
"errors"
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/posener/complete"
)
const (
sshSynopsis = "Authorize a session against a target and invoke an SSH client to connect"
)
func sshOptions(c *Command, set *base.FlagSets) {
f := set.NewFlagSet("SSH Options")
f.StringVar(&base.StringVar{
Name: "style",
Target: &c.flagSshStyle,
EnvVar: "BOUNDARY_CONNECT_SSH_STYLE",
Completion: complete.PredictSet("ssh", "putty", "sshpass"),
Default: "ssh",
Usage: `Specifies how the CLI will attempt to invoke an SSH client. This will also set a suitable default for -exec if a value was not specified. Currently-understood values are "ssh" and "putty".`,
})
f.StringVar(&base.StringVar{
Name: "username",
Target: &c.flagUsername,
EnvVar: "BOUNDARY_CONNECT_USERNAME",
Completion: complete.PredictNothing,
Usage: `Specifies the username to pass through to the client`,
})
}
type sshFlags struct {
flagSshStyle string
}
func (s *sshFlags) defaultExec() string {
return strings.ToLower(s.flagSshStyle)
}
func (s *sshFlags) buildArgs(c *Command, port, ip, addr string) (args, envs []string, retErr error) {
var cred usernamePasswordCredentials
if c.sessionAuthz != nil {
creds, err := parseCredentials(c.sessionAuthz.Credentials)
if err != nil {
return nil, nil, fmt.Errorf("Error interpreting secret: %w", err)
}
if len(creds) > 0 {
// Just use first credentials returned
cred = creds[0]
}
}
switch strings.ToLower(s.flagSshStyle) {
case "ssh":
// Might want -t for ssh or -tt but seems fine without it for now...
args = append(args, "-p", port, ip)
// SSH detects a host key change when localhost proxy port changes, disable localhost
// host key verification to avoid 'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED...'
args = append(args, "-o", "NoHostAuthenticationForLocalhost=yes")
case "sshpass":
if cred.Password == "" {
return nil, nil, errors.New("Password is required when using sshpass")
}
// sshpass requires that the password is passed as env-var "SSHPASS"
// when the using env-vars.
envs = append(envs, fmt.Sprintf("SSHPASS=%s", cred.Password))
args = append(args, "-e", "ssh")
args = append(args, "-p", port, ip)
// sshpass cannot handle host key checking, disable localhost key verification
// to avoid error: 'SSHPASS detected host authentication prompt. Exiting.'
args = append(args, "-o", "NoHostAuthenticationForLocalhost=yes")
case "putty":
args = append(args, "-P", port, ip)
}
switch {
case cred.Username != "":
args = append(args, "-l", cred.Username)
case c.flagUsername != "":
args = append(args, "-l", c.flagUsername)
}
return args, envs, nil
}