1
0
mirror of https://github.com/containers/podman.git synced 2026-02-05 06:45:31 +01:00
Files
podman/pkg/machine/ssh.go
Brent Baude 76e14f79f7 use bootc for os apply
Instead of using rpm-ostree, we now use bootc for os apply.  the
implementation is a little murky right now and will require some cleanup
to implement bootc's transports.  for now, we only support oci images
from registries.

once we have an upgrade command, the transports can be added and the
docs for apply can be ammended to be more clear.

Fixes: RUN-3836

Signed-off-by: Brent Baude <bbaude@redhat.com>
2026-01-08 13:32:39 -06:00

171 lines
5.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package machine
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strconv"
"strings"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)
// LocalhostSSH is a common function for ssh'ing to a podman machine using system-connections
// and a port
// TODO This should probably be taught about an machineconfig to reduce input
func LocalhostSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
return localhostBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
}
// LocalhostSSHShellForceTerm runs the native ssh shell client and forces a terminal (-t)
func LocalhostSSHShellForceTerm(username, identityPath, name string, sshPort int, inputArgs []string) error {
return localhostNativeSSH(username, identityPath, name, sshPort, inputArgs, os.Stdin, true)
}
func LocalhostSSHShell(username, identityPath, name string, sshPort int, inputArgs []string) error {
return localhostNativeSSH(username, identityPath, name, sshPort, inputArgs, os.Stdin, false)
}
func LocalhostSSHSilent(username, identityPath, name string, sshPort int, inputArgs []string) error {
return localhostBuiltinSSH(username, identityPath, name, sshPort, inputArgs, false, nil)
}
func LocalhostSSHWithStdin(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
return localhostBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, stdin)
}
func localhostBuiltinSSH(username, identityPath, name string, sshPort int, inputArgs []string, passOutput bool, stdin io.Reader) error {
config, err := createLocalhostConfig(username, identityPath) // WARNING: This MUST NOT be generalized to allow communication over untrusted networks.
if err != nil {
return err
}
client, err := ssh.Dial("tcp", fmt.Sprintf("localhost:%d", sshPort), config)
if err != nil {
return err
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
return err
}
defer session.Close()
cmd := strings.Join(inputArgs, " ")
logrus.Debugf("Running ssh command on machine %q: %s", name, cmd)
session.Stdin = stdin
if passOutput {
session.Stdout = os.Stdout
session.Stderr = os.Stderr
} else if logrus.IsLevelEnabled(logrus.DebugLevel) {
return runSessionWithDebug(session, cmd)
}
return session.Run(cmd)
}
func runSessionWithDebug(session *ssh.Session, cmd string) error {
outPipe, err := session.StdoutPipe()
if err != nil {
return err
}
errPipe, err := session.StderrPipe()
if err != nil {
return err
}
logOuput := func(pipe io.Reader, done chan struct{}) {
scanner := bufio.NewScanner(pipe)
for scanner.Scan() {
logrus.Debugf("ssh output: %s", scanner.Text())
}
done <- struct{}{}
}
if err := session.Start(cmd); err != nil {
return err
}
completed := make(chan struct{}, 2)
go logOuput(outPipe, completed)
go logOuput(errPipe, completed)
<-completed
<-completed
return session.Wait()
}
// createLocalhostConfig returns a *ssh.ClientConfig for authenticating a user using a private key
//
// WARNING: This MUST NOT be used to communicate over untrusted networks.
func createLocalhostConfig(user string, identityPath string) (*ssh.ClientConfig, error) {
key, err := os.ReadFile(identityPath)
if err != nil {
return nil, err
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return nil, err
}
return &ssh.ClientConfig{
// Not specifying ciphers / MACs seems to allow fairly weak ciphers. This config is restricted
// to connecting to localhost: where we rely on the kernels process isolation, not primarily on cryptography.
User: user,
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
// This config is restricted to connecting to localhost (and to a VM we manage),
// we rely on the kernels process isolation, not on cryptography,
// This would be UNACCEPTABLE for most other uses.
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}, nil
}
func localhostNativeSSH(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader, forceTerm bool) error {
sshDestination := username + "@localhost"
port := strconv.Itoa(sshPort)
interactive := true
args := append([]string{"-i", identityPath, "-p", port, sshDestination}, LocalhostSSHArgs()...) // WARNING: This MUST NOT be generalized to allow communication over untrusted networks.
if len(inputArgs) > 0 {
// on the other condition, the term is forced
// anyway
if forceTerm {
args = append(args, "-t")
}
interactive = false
args = append(args, inputArgs...)
} else {
// ensure we have a tty
args = append(args, "-t")
fmt.Printf("Connecting to vm %s. To close connection, use `~.` or `exit`\n", name)
}
cmd := exec.Command("ssh", args...)
logrus.Debugf("Executing: ssh %v\n", args)
if err := setupIOPassthrough(cmd, interactive, stdin); err != nil {
return err
}
return cmd.Run()
}
// LocalhostSSHArgs returns OpenSSH command-line options for connecting with no host key identity checks.
//
// WARNING: This MUST NOT be used to communicate over untrusted networks.
func LocalhostSSHArgs() []string {
// This config is restricted to connecting to localhost (and to a VM we manage),
// we rely on the kernels process isolation, not on cryptography,
// This would be UNACCEPTABLE for most other uses.
return []string{
"-o", "IdentitiesOnly=yes",
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=" + os.DevNull,
"-o", "CheckHostIP=no",
"-o", "LogLevel=ERROR",
"-o", "SetEnv=LC_ALL=",
}
}