Add auto add-host and ssh-agent for docker-env

pull/15452/head
Товарищ программист 2023-07-02 02:52:41 +08:00
parent d1138d879d
commit 3d1b44055a
4 changed files with 92 additions and 88 deletions

View File

@ -48,6 +48,7 @@ import (
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/reason"
"k8s.io/minikube/pkg/minikube/shell"
"k8s.io/minikube/pkg/minikube/sshagent"
"k8s.io/minikube/pkg/minikube/sysinit"
pkgnetwork "k8s.io/minikube/pkg/network"
kconst "k8s.io/minikube/third_party/kubeadm/app/constants"
@ -296,6 +297,14 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
}
cname := ClusterFlagValue()
// start the ssh-agent
// this must be done before the cluster config is loaded
// otherwise we won't be able to get SSH_AUTH_SOCK and SSH_AGENT_PID from cluster config.
if err := sshagent.Start(cname); err != nil {
exit.Message(reason.SshAgentStart, err.Error())
}
co := mustload.Running(cname)
driverName := co.CP.Host.DriverName
@ -316,6 +325,7 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
// for the sake of docker-env command, start nerdctl and nerdctld
if cr == constants.Containerd {
out.WarningT("Using the docker-env command with the containerd runtime is a highly experimental feature, please provide feedback or contribute to make it better")
startNerdctld()
// docker-env on containerd depends on nerdctld (https://github.com/afbjorklund/nerdctld) as "docker" daeomn
@ -328,6 +338,10 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
out.WarningT("Please ensure you have executed 'ssh-agent bash' and 'minikube ssh-host --append-known' in this shell before using docker-env on containerd. Ignore this message if you have done it")
}
// set the ssh-agent envs for current process
os.Setenv("SSH_AUTH_SOCK", co.Config.SSHAuthSock)
os.Setenv("SSH_AGENT_PID", strconv.Itoa(co.Config.SSHAgentPID))
r := co.CP.Runner
if cr == constants.Docker {
@ -400,14 +414,18 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
if err != nil {
exit.Error(reason.IfSSHClient, "Error with ssh-add", err)
}
cmd := exec.Command(path, d.GetSSHKeyPath())
cmd.Stderr = os.Stderr
cmd.Env = append(cmd.Env, fmt.Sprintf("SSH_AUTH_SOCK=%s", co.Config.SSHAuthSock))
cmd.Env = append(cmd.Env, fmt.Sprintf("SSH_AGENT_PID=%d", co.Config.SSHAgentPID))
err = cmd.Run()
if err != nil {
exit.Error(reason.IfSSHClient, "Error with ssh-add", err)
}
}
// eventually, run something similar to ssh --append-known
appendKnownHelper(nodeName, true)
},
}
@ -558,6 +576,8 @@ func dockerEnvVars(ec DockerEnvConfig) map[string]string {
envSSH := map[string]string{
constants.DockerHostEnv: sshURL(ec.username, ec.hostname, ec.sshport),
constants.MinikubeActiveDockerdEnv: ec.profile,
constants.SSHAuthSock: ec.sshAuthSock,
constants.SSHAgentPID: agentPID,
}
var rt map[string]string

View File

@ -45,69 +45,71 @@ var sshHostCmd = &cobra.Command{
Short: "Retrieve the ssh host key of the specified node",
Long: "Retrieve the ssh host key of the specified node.",
Run: func(cmd *cobra.Command, args []string) {
cname := ClusterFlagValue()
co := mustload.Running(cname)
if co.CP.Host.DriverName == driver.None {
exit.Message(reason.Usage, "'none' driver does not support 'minikube ssh-host' command")
}
appendKnownHelper(nodeName, appendKnown)
},
}
var err error
var n *config.Node
if nodeName == "" {
n = co.CP.Node
} else {
n, _, err = node.Retrieve(*co.Config, nodeName)
if err != nil {
exit.Message(reason.GuestNodeRetrieve, "Node {{.nodeName}} does not exist.", out.V{"nodeName": nodeName})
}
}
func appendKnownHelper(nodeName string, appendKnown bool) {
cname := ClusterFlagValue()
co := mustload.Running(cname)
if co.CP.Host.DriverName == driver.None {
exit.Message(reason.Usage, "'none' driver does not support 'minikube ssh-host' command")
}
scanArgs := []string{"-t", "rsa"}
keys, err := machine.RunSSHHostCommand(co.API, *co.Config, *n, "ssh-keyscan", scanArgs)
var err error
var n *config.Node
if nodeName == "" {
n = co.CP.Node
} else {
n, _, err = node.Retrieve(*co.Config, nodeName)
if err != nil {
// This is typically due to a non-zero exit code, so no need for flourish.
out.ErrLn("ssh-keyscan: %v", err)
// It'd be nice if we could pass up the correct error code here :(
exit.Message(reason.GuestNodeRetrieve, "Node {{.nodeName}} does not exist.", out.V{"nodeName": nodeName})
}
}
scanArgs := []string{"-t", "rsa"}
keys, err := machine.RunSSHHostCommand(co.API, *co.Config, *n, "ssh-keyscan", scanArgs)
if err != nil {
// This is typically due to a non-zero exit code, so no need for flourish.
out.ErrLn("ssh-keyscan: %v", err)
// It'd be nice if we could pass up the correct error code here :(
os.Exit(1)
}
if appendKnown {
addr, port, err := machine.GetSSHHostAddrPort(co.API, *co.Config, *n)
if err != nil {
out.ErrLn("GetSSHHostAddrPort: %v", err)
os.Exit(1)
}
if appendKnown {
addr, port, err := machine.GetSSHHostAddrPort(co.API, *co.Config, *n)
if err != nil {
out.ErrLn("GetSSHHostAddrPort: %v", err)
os.Exit(1)
}
host := addr
if port != 22 {
host = fmt.Sprintf("[%s]:%d", addr, port)
}
knownHosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
fmt.Fprintf(os.Stderr, "Host added: %s (%s)\n", knownHosts, host)
if sshutil.KnownHost(host, knownHosts) {
return
}
f, err := os.OpenFile(knownHosts, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
out.ErrLn("OpenFile: %v", err)
os.Exit(1)
}
defer f.Close()
_, err = f.WriteString(keys)
if err != nil {
out.ErrLn("WriteString: %v", err)
os.Exit(1)
}
host := addr
if port != 22 {
host = fmt.Sprintf("[%s]:%d", addr, port)
}
knownHosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
fmt.Fprintf(os.Stderr, "Host added: %s (%s)\n", knownHosts, host)
if sshutil.KnownHost(host, knownHosts) {
return
}
fmt.Printf("%s", keys)
},
f, err := os.OpenFile(knownHosts, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
out.ErrLn("OpenFile: %v", err)
os.Exit(1)
}
defer f.Close()
_, err = f.WriteString(keys)
if err != nil {
out.ErrLn("WriteString: %v", err)
os.Exit(1)
}
return
}
}
func init() {

View File

@ -428,6 +428,8 @@ var (
RuntimeEnable = Kind{ID: "RUNTIME_ENABLE", ExitCode: ExRuntimeError}
// minikube failed to cache images for the current container runtime
RuntimeCache = Kind{ID: "RUNTIME_CACHE", ExitCode: ExRuntimeError}
// minikube failed to start an ssh-agent when executing docker-env
SshAgentStart = Kind{ID: "SSH_AGENT_START", ExitCode: ExRuntimeError}
// service check timed out while starting minikube dashboard
SvcCheckTimeout = Kind{ID: "SVC_CHECK_TIMEOUT", ExitCode: ExSvcTimeout}

View File

@ -184,35 +184,15 @@ func TestDockerEnvContainerd(t *testing.T) {
}
time.Sleep(time.Second * 10)
// if we are in a shell, we need to run 'ssh-agent bash' to enable the ssh-agent
// but if we are in an integration test, we don't have a bash, so we need to get the environment variables set by ssh-agent, and use them in the following tests
result, err := Run(t, exec.CommandContext(ctx, "ssh-agent"))
if err != nil {
t.Errorf("failed to execute ssh-agent bash, error: %v, output: %s", err, result.Output())
}
output := result.Output()
// get SSH_AUTH_SOCK
groups := regexp.MustCompile(`SSH_AUTH_SOCK=(\S*);`).FindStringSubmatch(output)
if len(groups) < 2 {
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
}
sshAuthSock := groups[1]
// get SSH_AGENT_PID
groups = regexp.MustCompile(`SSH_AGENT_PID=(\S*);`).FindStringSubmatch(output)
if len(groups) < 2 {
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
}
sshAgentPid := groups[1]
// execute 'minikube docker-env --ssh-host --ssh-add' and extract the 'DOCKER_HOST' environment value
cmd = exec.CommandContext(ctx, "/bin/bash", "-c", fmt.Sprintf("SSH_AUTH_SOCK=%s SSH_AGENT_PID=%s %s docker-env --ssh-host --ssh-add -p %s", sshAuthSock, sshAgentPid, Target(), profile))
result, err = Run(t, cmd)
cmd = exec.CommandContext(ctx, "/bin/bash", "-c", fmt.Sprintf("%s docker-env --ssh-host --ssh-add -p %s", Target(), profile))
result, err := Run(t, cmd)
if err != nil {
t.Errorf("failed to execute minikube docker-env --ssh-host --ssh-add, error: %v, output: %s", err, result.Output())
}
output = result.Output()
groups = regexp.MustCompile(`DOCKER_HOST="(\S*)"`).FindStringSubmatch(output)
output := result.Output()
groups := regexp.MustCompile(`DOCKER_HOST="(\S*)"`).FindStringSubmatch(output)
if len(groups) < 2 {
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
}
@ -221,19 +201,19 @@ func TestDockerEnvContainerd(t *testing.T) {
if len(segments) < 3 {
t.Errorf("failed to acquire dockerHost, output is %s", dockerHost)
}
port := segments[2]
// clear remaining keys
clearResult, err := Run(t, exec.CommandContext(ctx, "ssh-keygen", "-R", "[127.0.0.1]:"+port))
if err != nil {
t.Logf("failed to clear duplicate keys: %q : %v", clearResult.Command(), err)
// get SSH_AUTH_SOCK
groups = regexp.MustCompile(`SSH_AUTH_SOCK=(\S*)`).FindStringSubmatch(output)
if len(groups) < 2 {
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
}
// execute 'minikube ssh-host --append-known'
result, err = Run(t, exec.CommandContext(ctx, Target(), "ssh-host", "--append-known", "-p", profile))
if err != nil {
t.Errorf("failed to execute 'minikube ssh-host --append-known', error: %v, output: %s", err, result.Output())
sshAuthSock := groups[1]
// get SSH_AGENT_PID
groups = regexp.MustCompile(`SSH_AGENT_PID=(\S*)`).FindStringSubmatch(output)
if len(groups) < 2 {
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
}
sshAgentPid := groups[1]
cmd = exec.CommandContext(ctx, "/bin/bash", "-c", fmt.Sprintf("SSH_AUTH_SOCK=%s SSH_AGENT_PID=%s DOCKER_HOST=%s docker version", sshAuthSock, sshAgentPid, dockerHost))