Skip to content

Commit 265ca77

Browse files
committed
Be explicit about ssh configs suitable only for localhost
... and warn loudly against generalization. Should not change behavior. Signed-off-by: Miloslav Trmač <[email protected]>
1 parent 5fef6b7 commit 265ca77

File tree

10 files changed

+45
-30
lines changed

10 files changed

+45
-30
lines changed

cmd/podman/machine/cp.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func cp(_ *cobra.Command, args []string) error {
9595
cpOpts.SrcPath = srcPath
9696
cpOpts.DestPath = destPath
9797

98-
err = secureCopy(&cpOpts)
98+
err = localhostSSHCopy(&cpOpts)
9999
if err != nil {
100100
return fmt.Errorf("copy failed: %s", err.Error())
101101
}
@@ -105,7 +105,8 @@ func cp(_ *cobra.Command, args []string) error {
105105
return nil
106106
}
107107

108-
func secureCopy(opts *cpOptions) error {
108+
// localhostSSHCopy uses scp to copy files from/to a localhost machine using ssh.
109+
func localhostSSHCopy(opts *cpOptions) error {
109110
srcPath := opts.SrcPath
110111
destPath := opts.DestPath
111112
sshConfig := opts.Machine.SSH
@@ -123,7 +124,7 @@ func secureCopy(opts *cpOptions) error {
123124
}
124125

125126
args := []string{"-r", "-i", sshConfig.IdentityPath, "-P", strconv.Itoa(sshConfig.Port)}
126-
args = append(args, machine.CommonSSHArgs()...)
127+
args = append(args, machine.LocalhostSSHArgs()...) // Warning: This MUST NOT be generalized to allow communication over untrusted networks.
127128
args = append(args, []string{srcPath, destPath}...)
128129

129130
cmd := exec.Command("scp", args...)

cmd/podman/machine/ssh.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,6 @@ func ssh(cmd *cobra.Command, args []string) error {
115115
}
116116
}
117117

118-
err = machine.CommonSSHShell(sshOpts.Username, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, sshOpts.Args)
118+
err = machine.LocalhostSSHShell(sshOpts.Username, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, sshOpts.Args)
119119
return utils.HandleOSExecError(err)
120120
}

pkg/machine/hyperv/volumes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func startShares(mc *vmconfigs.MachineConfig) error {
6464
}
6565
args = append(args, "machine", "client9p", fmt.Sprintf("%d", *mount.VSockNumber), strconv.Quote(mount.Target))
6666

67-
if err := machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
67+
if err := machine.LocalhostSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
6868
return err
6969
}
7070
}

pkg/machine/os/machine_os.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type MachineOS struct {
2424
func (m *MachineOS) Apply(image string, opts ApplyOptions) error {
2525
args := []string{"podman", "machine", "os", "apply", image}
2626

27-
if err := machine.CommonSSH(m.VM.SSH.RemoteUsername, m.VM.SSH.IdentityPath, m.VMName, m.VM.SSH.Port, args); err != nil {
27+
if err := machine.LocalhostSSH(m.VM.SSH.RemoteUsername, m.VM.SSH.IdentityPath, m.VMName, m.VM.SSH.Port, args); err != nil {
2828
return err
2929
}
3030

pkg/machine/proxyenv/env.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@ func getProxyScript(isWSL bool) io.Reader {
5252
}
5353

5454
func ApplyProxies(mc *vmconfigs.MachineConfig) error {
55-
return machine.CommonSSHWithStdin("root", mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"/usr/bin/bash"},
55+
return machine.LocalhostSSHWithStdin("root", mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"/usr/bin/bash"},
5656
getProxyScript(mc.WSLHypervisor != nil))
5757
}

pkg/machine/qemu/stubber.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ func (q *QEMUStubber) MountVolumesToVM(mc *vmconfigs.MachineConfig, quiet bool)
353353
if !strings.HasPrefix(mount.Target, "/home") && !strings.HasPrefix(mount.Target, "/mnt") {
354354
args = append(args, ";", "sudo", "chattr", "+i", "/", ";")
355355
}
356-
err := machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args)
356+
err := machine.LocalhostSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args)
357357
if err != nil {
358358
return err
359359
}
@@ -368,7 +368,7 @@ func (q *QEMUStubber) MountVolumesToVM(mc *vmconfigs.MachineConfig, quiet bool)
368368
mountFlags += ",ro"
369369
}
370370
mountOptions = append(mountOptions, "-o", mountFlags)
371-
err = machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, append([]string{"sudo", "mount"}, mountOptions...))
371+
err = machine.LocalhostSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, append([]string{"sudo", "mount"}, mountOptions...))
372372
if err != nil {
373373
return err
374374
}

pkg/machine/shim/host.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, dirs *machineDe
609609
}
610610

611611
if mp.VMType() == machineDefine.WSLVirt && mc.Ansible != nil && mc.IsFirstBoot() {
612-
if err := machine.CommonSSHSilent(mc.Ansible.User, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"ansible-playbook", mc.Ansible.PlaybookPath}); err != nil {
612+
if err := machine.LocalhostSSHSilent(mc.Ansible.User, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"ansible-playbook", mc.Ansible.PlaybookPath}); err != nil {
613613
logrus.Error(err)
614614
}
615615
}

pkg/machine/shim/networking.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func conductVMReadinessCheck(mc *vmconfigs.MachineConfig, maxBackoffs int, backo
150150
// CoreOS users have reported the same observation but
151151
// the underlying source of the issue remains unknown.
152152

153-
if sshError = machine.CommonSSHSilent(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"true"}); sshError != nil {
153+
if sshError = machine.LocalhostSSHSilent(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"true"}); sshError != nil {
154154
logrus.Debugf("SSH readiness check for machine failed: %v", sshError)
155155
continue
156156
}

pkg/machine/ssh.go

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,27 @@ import (
1313
"golang.org/x/crypto/ssh"
1414
)
1515

16-
// CommonSSH is a common function for ssh'ing to a podman machine using system-connections
16+
// LocalhostSSH is a common function for ssh'ing to a podman machine using system-connections
1717
// and a port
1818
// TODO This should probably be taught about an machineconfig to reduce input
19-
func CommonSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
20-
return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
19+
func LocalhostSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
20+
return localhostBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
2121
}
2222

23-
func CommonSSHShell(username, identityPath, name string, sshPort int, inputArgs []string) error {
24-
return commonNativeSSH(username, identityPath, name, sshPort, inputArgs, os.Stdin)
23+
func LocalhostSSHShell(username, identityPath, name string, sshPort int, inputArgs []string) error {
24+
return localhostNativeSSH(username, identityPath, name, sshPort, inputArgs, os.Stdin)
2525
}
2626

27-
func CommonSSHSilent(username, identityPath, name string, sshPort int, inputArgs []string) error {
28-
return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, false, nil)
27+
func LocalhostSSHSilent(username, identityPath, name string, sshPort int, inputArgs []string) error {
28+
return localhostBuiltinSSH(username, identityPath, name, sshPort, inputArgs, false, nil)
2929
}
3030

31-
func CommonSSHWithStdin(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
32-
return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, stdin)
31+
func LocalhostSSHWithStdin(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
32+
return localhostBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, stdin)
3333
}
3434

35-
func commonBuiltinSSH(username, identityPath, name string, sshPort int, inputArgs []string, passOutput bool, stdin io.Reader) error {
36-
config, err := createConfig(username, identityPath)
35+
func localhostBuiltinSSH(username, identityPath, name string, sshPort int, inputArgs []string, passOutput bool, stdin io.Reader) error {
36+
config, err := createLocalhostConfig(username, identityPath) // WARNING: This MUST NOT be generalized to allow communication over untrusted networks.
3737
if err != nil {
3838
return err
3939
}
@@ -91,7 +91,10 @@ func runSessionWithDebug(session *ssh.Session, cmd string) error {
9191
return session.Wait()
9292
}
9393

94-
func createConfig(user string, identityPath string) (*ssh.ClientConfig, error) {
94+
// createLocalhostConfig returns a *ssh.ClientConfig for authenticating a user using a private key
95+
//
96+
// WARNING: This MUST NOT be used to communicate over untrusted networks.
97+
func createLocalhostConfig(user string, identityPath string) (*ssh.ClientConfig, error) {
9598
key, err := os.ReadFile(identityPath)
9699
if err != nil {
97100
return nil, err
@@ -103,18 +106,23 @@ func createConfig(user string, identityPath string) (*ssh.ClientConfig, error) {
103106
}
104107

105108
return &ssh.ClientConfig{
106-
User: user,
107-
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
109+
// Not specifying ciphers / MACs seems to allow fairly weak ciphers. This config is restricted
110+
// to connecting to localhost: where we rely on the kernel’s process isolation, not primarily on cryptography.
111+
User: user,
112+
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
113+
// This config is restricted to connecting to localhost (and to a VM we manage),
114+
// we rely on the kernel’s process isolation, not on cryptography,
115+
// This would be UNACCEPTABLE for most other uses.
108116
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
109117
}, nil
110118
}
111119

112-
func commonNativeSSH(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
120+
func localhostNativeSSH(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
113121
sshDestination := username + "@localhost"
114122
port := strconv.Itoa(sshPort)
115123
interactive := true
116124

117-
args := append([]string{"-i", identityPath, "-p", port, sshDestination}, CommonSSHArgs()...)
125+
args := append([]string{"-i", identityPath, "-p", port, sshDestination}, LocalhostSSHArgs()...) // WARNING: This MUST NOT be generalized to allow communication over untrusted networks.
118126
if len(inputArgs) > 0 {
119127
interactive = false
120128
args = append(args, inputArgs...)
@@ -134,7 +142,13 @@ func commonNativeSSH(username, identityPath, name string, sshPort int, inputArgs
134142
return cmd.Run()
135143
}
136144

137-
func CommonSSHArgs() []string {
145+
// LocalhostSSHArgs returns OpenSSH command-line options for connecting with no host key identity checks.
146+
//
147+
// WARNING: This MUST NOT be used to communicate over untrusted networks.
148+
func LocalhostSSHArgs() []string {
149+
// This config is restricted to connecting to localhost (and to a VM we manage),
150+
// we rely on the kernel’s process isolation, not on cryptography,
151+
// This would be UNACCEPTABLE for most other uses.
138152
return []string{
139153
"-o", "IdentitiesOnly=yes",
140154
"-o", "StrictHostKeyChecking=no",

pkg/machine/update.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ func UpdatePodmanDockerSockService(mc *vmconfigs.MachineConfig) error {
1414
content := ignition.GetPodmanDockerTmpConfig(mc.HostUser.UID, mc.HostUser.Rootful, false)
1515
command := fmt.Sprintf("'echo %q > %s'", content, ignition.PodmanDockerTmpConfPath)
1616
args := []string{"sudo", "bash", "-c", command}
17-
if err := CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
17+
if err := LocalhostSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
1818
logrus.Warnf("Could not update internal docker sock config")
1919
return err
2020
}
2121

2222
args = []string{"sudo", "systemd-tmpfiles", "--create", "--prefix=/run/docker.sock"}
23-
if err := CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
23+
if err := LocalhostSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
2424
logrus.Warnf("Could not create internal docker sock")
2525
return err
2626
}

0 commit comments

Comments
 (0)