Skip to content

Commit 3d1b440

Browse files
Add auto add-host and ssh-agent for docker-env
1 parent d1138d8 commit 3d1b440

File tree

4 files changed

+90
-86
lines changed

4 files changed

+90
-86
lines changed

cmd/minikube/cmd/docker-env.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
"k8s.io/minikube/pkg/minikube/out"
4949
"k8s.io/minikube/pkg/minikube/reason"
5050
"k8s.io/minikube/pkg/minikube/shell"
51+
"k8s.io/minikube/pkg/minikube/sshagent"
5152
"k8s.io/minikube/pkg/minikube/sysinit"
5253
pkgnetwork "k8s.io/minikube/pkg/network"
5354
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
296297
}
297298

298299
cname := ClusterFlagValue()
300+
301+
// start the ssh-agent
302+
// this must be done before the cluster config is loaded
303+
// otherwise we won't be able to get SSH_AUTH_SOCK and SSH_AGENT_PID from cluster config.
304+
if err := sshagent.Start(cname); err != nil {
305+
exit.Message(reason.SshAgentStart, err.Error())
306+
}
307+
299308
co := mustload.Running(cname)
300309

301310
driverName := co.CP.Host.DriverName
@@ -316,6 +325,7 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
316325
// for the sake of docker-env command, start nerdctl and nerdctld
317326
if cr == constants.Containerd {
318327
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")
328+
319329
startNerdctld()
320330

321331
// 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
328338
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")
329339
}
330340

341+
// set the ssh-agent envs for current process
342+
os.Setenv("SSH_AUTH_SOCK", co.Config.SSHAuthSock)
343+
os.Setenv("SSH_AGENT_PID", strconv.Itoa(co.Config.SSHAgentPID))
344+
331345
r := co.CP.Runner
332346

333347
if cr == constants.Docker {
@@ -400,14 +414,18 @@ docker-cli install instructions: https://minikube.sigs.k8s.io/docs/tutorials/doc
400414
if err != nil {
401415
exit.Error(reason.IfSSHClient, "Error with ssh-add", err)
402416
}
403-
404417
cmd := exec.Command(path, d.GetSSHKeyPath())
405418
cmd.Stderr = os.Stderr
419+
cmd.Env = append(cmd.Env, fmt.Sprintf("SSH_AUTH_SOCK=%s", co.Config.SSHAuthSock))
420+
cmd.Env = append(cmd.Env, fmt.Sprintf("SSH_AGENT_PID=%d", co.Config.SSHAgentPID))
406421
err = cmd.Run()
407422
if err != nil {
408423
exit.Error(reason.IfSSHClient, "Error with ssh-add", err)
409424
}
410425
}
426+
427+
// eventually, run something similar to ssh --append-known
428+
appendKnownHelper(nodeName, true)
411429
},
412430
}
413431

@@ -558,6 +576,8 @@ func dockerEnvVars(ec DockerEnvConfig) map[string]string {
558576
envSSH := map[string]string{
559577
constants.DockerHostEnv: sshURL(ec.username, ec.hostname, ec.sshport),
560578
constants.MinikubeActiveDockerdEnv: ec.profile,
579+
constants.SSHAuthSock: ec.sshAuthSock,
580+
constants.SSHAgentPID: agentPID,
561581
}
562582

563583
var rt map[string]string

cmd/minikube/cmd/ssh-host.go

+53-51
Original file line numberDiff line numberDiff line change
@@ -45,69 +45,71 @@ var sshHostCmd = &cobra.Command{
4545
Short: "Retrieve the ssh host key of the specified node",
4646
Long: "Retrieve the ssh host key of the specified node.",
4747
Run: func(cmd *cobra.Command, args []string) {
48-
cname := ClusterFlagValue()
49-
co := mustload.Running(cname)
50-
if co.CP.Host.DriverName == driver.None {
51-
exit.Message(reason.Usage, "'none' driver does not support 'minikube ssh-host' command")
52-
}
48+
appendKnownHelper(nodeName, appendKnown)
49+
},
50+
}
5351

54-
var err error
55-
var n *config.Node
56-
if nodeName == "" {
57-
n = co.CP.Node
58-
} else {
59-
n, _, err = node.Retrieve(*co.Config, nodeName)
60-
if err != nil {
61-
exit.Message(reason.GuestNodeRetrieve, "Node {{.nodeName}} does not exist.", out.V{"nodeName": nodeName})
62-
}
52+
func appendKnownHelper(nodeName string, appendKnown bool) {
53+
cname := ClusterFlagValue()
54+
co := mustload.Running(cname)
55+
if co.CP.Host.DriverName == driver.None {
56+
exit.Message(reason.Usage, "'none' driver does not support 'minikube ssh-host' command")
57+
}
58+
59+
var err error
60+
var n *config.Node
61+
if nodeName == "" {
62+
n = co.CP.Node
63+
} else {
64+
n, _, err = node.Retrieve(*co.Config, nodeName)
65+
if err != nil {
66+
exit.Message(reason.GuestNodeRetrieve, "Node {{.nodeName}} does not exist.", out.V{"nodeName": nodeName})
6367
}
68+
}
6469

65-
scanArgs := []string{"-t", "rsa"}
70+
scanArgs := []string{"-t", "rsa"}
6671

67-
keys, err := machine.RunSSHHostCommand(co.API, *co.Config, *n, "ssh-keyscan", scanArgs)
72+
keys, err := machine.RunSSHHostCommand(co.API, *co.Config, *n, "ssh-keyscan", scanArgs)
73+
if err != nil {
74+
// This is typically due to a non-zero exit code, so no need for flourish.
75+
out.ErrLn("ssh-keyscan: %v", err)
76+
// It'd be nice if we could pass up the correct error code here :(
77+
os.Exit(1)
78+
}
79+
80+
if appendKnown {
81+
addr, port, err := machine.GetSSHHostAddrPort(co.API, *co.Config, *n)
6882
if err != nil {
69-
// This is typically due to a non-zero exit code, so no need for flourish.
70-
out.ErrLn("ssh-keyscan: %v", err)
71-
// It'd be nice if we could pass up the correct error code here :(
83+
out.ErrLn("GetSSHHostAddrPort: %v", err)
7284
os.Exit(1)
7385
}
7486

75-
if appendKnown {
76-
addr, port, err := machine.GetSSHHostAddrPort(co.API, *co.Config, *n)
77-
if err != nil {
78-
out.ErrLn("GetSSHHostAddrPort: %v", err)
79-
os.Exit(1)
80-
}
81-
82-
host := addr
83-
if port != 22 {
84-
host = fmt.Sprintf("[%s]:%d", addr, port)
85-
}
86-
knownHosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
87-
88-
fmt.Fprintf(os.Stderr, "Host added: %s (%s)\n", knownHosts, host)
89-
if sshutil.KnownHost(host, knownHosts) {
90-
return
91-
}
92-
93-
f, err := os.OpenFile(knownHosts, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
94-
if err != nil {
95-
out.ErrLn("OpenFile: %v", err)
96-
os.Exit(1)
97-
}
98-
defer f.Close()
99-
100-
_, err = f.WriteString(keys)
101-
if err != nil {
102-
out.ErrLn("WriteString: %v", err)
103-
os.Exit(1)
104-
}
87+
host := addr
88+
if port != 22 {
89+
host = fmt.Sprintf("[%s]:%d", addr, port)
90+
}
91+
knownHosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
10592

93+
fmt.Fprintf(os.Stderr, "Host added: %s (%s)\n", knownHosts, host)
94+
if sshutil.KnownHost(host, knownHosts) {
10695
return
10796
}
10897

109-
fmt.Printf("%s", keys)
110-
},
98+
f, err := os.OpenFile(knownHosts, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
99+
if err != nil {
100+
out.ErrLn("OpenFile: %v", err)
101+
os.Exit(1)
102+
}
103+
defer f.Close()
104+
105+
_, err = f.WriteString(keys)
106+
if err != nil {
107+
out.ErrLn("WriteString: %v", err)
108+
os.Exit(1)
109+
}
110+
111+
return
112+
}
111113
}
112114

113115
func init() {

pkg/minikube/reason/reason.go

+2
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,8 @@ var (
428428
RuntimeEnable = Kind{ID: "RUNTIME_ENABLE", ExitCode: ExRuntimeError}
429429
// minikube failed to cache images for the current container runtime
430430
RuntimeCache = Kind{ID: "RUNTIME_CACHE", ExitCode: ExRuntimeError}
431+
// minikube failed to start an ssh-agent when executing docker-env
432+
SshAgentStart = Kind{ID: "SSH_AGENT_START", ExitCode: ExRuntimeError}
431433

432434
// service check timed out while starting minikube dashboard
433435
SvcCheckTimeout = Kind{ID: "SVC_CHECK_TIMEOUT", ExitCode: ExSvcTimeout}

test/integration/docker_test.go

+14-34
Original file line numberDiff line numberDiff line change
@@ -184,35 +184,15 @@ func TestDockerEnvContainerd(t *testing.T) {
184184
}
185185
time.Sleep(time.Second * 10)
186186

187-
// if we are in a shell, we need to run 'ssh-agent bash' to enable the ssh-agent
188-
// 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
189-
result, err := Run(t, exec.CommandContext(ctx, "ssh-agent"))
190-
if err != nil {
191-
t.Errorf("failed to execute ssh-agent bash, error: %v, output: %s", err, result.Output())
192-
}
193-
output := result.Output()
194-
// get SSH_AUTH_SOCK
195-
groups := regexp.MustCompile(`SSH_AUTH_SOCK=(\S*);`).FindStringSubmatch(output)
196-
if len(groups) < 2 {
197-
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
198-
}
199-
sshAuthSock := groups[1]
200-
// get SSH_AGENT_PID
201-
groups = regexp.MustCompile(`SSH_AGENT_PID=(\S*);`).FindStringSubmatch(output)
202-
if len(groups) < 2 {
203-
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
204-
}
205-
sshAgentPid := groups[1]
206-
207187
// execute 'minikube docker-env --ssh-host --ssh-add' and extract the 'DOCKER_HOST' environment value
208-
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))
209-
result, err = Run(t, cmd)
188+
cmd = exec.CommandContext(ctx, "/bin/bash", "-c", fmt.Sprintf("%s docker-env --ssh-host --ssh-add -p %s", Target(), profile))
189+
result, err := Run(t, cmd)
210190
if err != nil {
211191
t.Errorf("failed to execute minikube docker-env --ssh-host --ssh-add, error: %v, output: %s", err, result.Output())
212192
}
213193

214-
output = result.Output()
215-
groups = regexp.MustCompile(`DOCKER_HOST="(\S*)"`).FindStringSubmatch(output)
194+
output := result.Output()
195+
groups := regexp.MustCompile(`DOCKER_HOST="(\S*)"`).FindStringSubmatch(output)
216196
if len(groups) < 2 {
217197
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
218198
}
@@ -221,19 +201,19 @@ func TestDockerEnvContainerd(t *testing.T) {
221201
if len(segments) < 3 {
222202
t.Errorf("failed to acquire dockerHost, output is %s", dockerHost)
223203
}
224-
port := segments[2]
225204

226-
// clear remaining keys
227-
clearResult, err := Run(t, exec.CommandContext(ctx, "ssh-keygen", "-R", "[127.0.0.1]:"+port))
228-
if err != nil {
229-
t.Logf("failed to clear duplicate keys: %q : %v", clearResult.Command(), err)
205+
// get SSH_AUTH_SOCK
206+
groups = regexp.MustCompile(`SSH_AUTH_SOCK=(\S*)`).FindStringSubmatch(output)
207+
if len(groups) < 2 {
208+
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
230209
}
231-
232-
// execute 'minikube ssh-host --append-known'
233-
result, err = Run(t, exec.CommandContext(ctx, Target(), "ssh-host", "--append-known", "-p", profile))
234-
if err != nil {
235-
t.Errorf("failed to execute 'minikube ssh-host --append-known', error: %v, output: %s", err, result.Output())
210+
sshAuthSock := groups[1]
211+
// get SSH_AGENT_PID
212+
groups = regexp.MustCompile(`SSH_AGENT_PID=(\S*)`).FindStringSubmatch(output)
213+
if len(groups) < 2 {
214+
t.Errorf("failed to acquire SSH_AUTH_SOCK, output is %s", output)
236215
}
216+
sshAgentPid := groups[1]
237217

238218
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))
239219

0 commit comments

Comments
 (0)