Skip to content

Commit

Permalink
Use dynamic identity file names by default
Browse files Browse the repository at this point in the history
Dynamically generated names supports up to four hex digits at the end
to detect available file names. The range scan starts from VM SSH port
to reduce collision probability. It is still possible to override
dynamically generated file names using command line option during
machine init.

Signed-off-by: Arthur Sengileyev <[email protected]>
  • Loading branch information
arixmkii committed May 8, 2023
1 parent c74f9ad commit 815d0c7
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 17 deletions.
4 changes: 4 additions & 0 deletions cmd/podman/machine/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ func init() {
flags.StringVar(&initOpts.Username, UsernameFlagName, cfg.ContainersConfDefaultsRO.Machine.User, "Username used in image")
_ = initCmd.RegisterFlagCompletionFunc(UsernameFlagName, completion.AutocompleteDefault)

identityFlagName := "identity"
flags.StringVar(&initOpts.Identity, identityFlagName, "", "Name of the identity used for keys")
_ = initCmd.RegisterFlagCompletionFunc(identityFlagName, completion.AutocompleteDefault)

ImagePathFlagName := "image-path"
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.ContainersConfDefaultsRO.Machine.Image, "Path to bootable image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
Expand Down
8 changes: 8 additions & 0 deletions docs/source/markdown/podman-machine-init.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ Size of the disk for the guest VM in GB.

Print usage statement.

#### **--identity**

Relative or absolute path to use for identity files (private key part). If the
path is relative, then it would be evaluated relative to the default .ssh
directory. All directories should be created in advance. If this is unset or
is whitespace or empty, then the filename would be dynamically chosen for the
machine.

#### **--ignition-path**

Fully qualified path of the ignition file.
Expand Down
10 changes: 7 additions & 3 deletions pkg/machine/applehv/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/homedir"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -124,7 +125,11 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
m.VfkitHelper = *vfhelper

sshDir := filepath.Join(homedir.Get(), ".ssh")
m.IdentityPath = filepath.Join(sshDir, m.Name)
targetIdentity, err := utils.FindTargetIdentityPath(sshDir, opts.Identity, "podman-machine", m.Port)
if err != nil {
return false, err
}
m.IdentityPath = targetIdentity
m.Rootful = opts.Rootful
m.RemoteUsername = opts.Username

Expand All @@ -142,7 +147,6 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
// TODO localhost needs to be restored here
uri := machine.SSHRemoteConnection.MakeSSHURL("192.168.64.2", fmt.Sprintf("/run/user/%d/podman/podman.sock", m.UID), strconv.Itoa(m.Port), m.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(m.Port), "root")
identity := filepath.Join(sshDir, m.Name)

uris := []url.URL{uri, uriRoot}
names := []string{m.Name, m.Name + "-root"}
Expand All @@ -154,7 +158,7 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
}

for i := 0; i < 2; i++ {
if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil {
if err := machine.AddConnection(&uris[i], names[i], m.IdentityPath, opts.IsDefault && i == 0); err != nil {
return false, err
}
}
Expand Down
1 change: 1 addition & 0 deletions pkg/machine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type InitOptions struct {
Rootful bool
UID string // uid of the user that called machine
UserModeNetworking *bool // nil = use backend/system default, false = disable, true = enable
Identity string
}

type Status = string
Expand Down
9 changes: 6 additions & 3 deletions pkg/machine/hyperv/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
m.ReadyHVSock = *eventHVSocket

sshDir := filepath.Join(homedir.Get(), ".ssh")
m.IdentityPath = filepath.Join(sshDir, m.Name)
targetIdentity, err := utils.FindTargetIdentityPath(sshDir, opts.Identity, "podman-machine", m.Port)
if err != nil {
return false, err
}
m.IdentityPath = targetIdentity

// TODO This needs to be fixed in c-common
m.RemoteUsername = "core"
Expand All @@ -110,7 +114,6 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
if len(opts.IgnitionPath) < 1 {
uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", fmt.Sprintf("/run/user/%d/podman/podman.sock", m.UID), strconv.Itoa(m.Port), m.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(m.Port), "root")
identity := filepath.Join(sshDir, m.Name)

uris := []url.URL{uri, uriRoot}
names := []string{m.Name, m.Name + "-root"}
Expand All @@ -122,7 +125,7 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
}

for i := 0; i < 2; i++ {
if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil {
if err := machine.AddConnection(&uris[i], names[i], m.IdentityPath, opts.IsDefault && i == 0); err != nil {
return false, err
}
}
Expand Down
9 changes: 6 additions & 3 deletions pkg/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,11 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
key string
)
sshDir := filepath.Join(homedir.Get(), ".ssh")
v.IdentityPath = filepath.Join(sshDir, v.Name)
targetIdentity, err := utils.FindTargetIdentityPath(sshDir, opts.Identity, "podman-machine", v.Port)
if err != nil {
return false, err
}
v.IdentityPath = targetIdentity
v.Rootful = opts.Rootful

switch opts.ImagePath {
Expand Down Expand Up @@ -320,7 +324,6 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
if len(opts.IgnitionPath) < 1 {
uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", fmt.Sprintf("/run/user/%d/podman/podman.sock", v.UID), strconv.Itoa(v.Port), v.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root")
identity := filepath.Join(sshDir, v.Name)

uris := []url.URL{uri, uriRoot}
names := []string{v.Name, v.Name + "-root"}
Expand All @@ -332,7 +335,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
}

for i := 0; i < 2; i++ {
if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil {
if err := machine.AddConnection(&uris[i], names[i], v.IdentityPath, opts.IsDefault && i == 0); err != nil {
return false, err
}
}
Expand Down
22 changes: 14 additions & 8 deletions pkg/machine/wsl/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,14 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
_ = setupWslProxyEnv()
homeDir := homedir.Get()
sshDir := filepath.Join(homeDir, ".ssh")
v.IdentityPath = filepath.Join(sshDir, v.Name)
targetIdentity, err := utils.FindTargetIdentityPath(sshDir, opts.Identity, "podman-machine", v.Port)
if err != nil {
return false, err
}
if filepath.Dir(targetIdentity) != sshDir {
return false, fmt.Errorf("can only place keys inside `%s` directory", sshDir)
}
v.IdentityPath = targetIdentity
v.Rootful = opts.Rootful
v.Version = currentMachineVersion

Expand Down Expand Up @@ -436,7 +443,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
return false, err
}

if err = createKeys(v, dist, sshDir); err != nil {
if err = createKeys(v, dist, filepath.Dir(targetIdentity), filepath.Base(targetIdentity)); err != nil {
return false, err
}

Expand All @@ -447,7 +454,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
return false, err
}

if err := setupConnections(v, opts, sshDir); err != nil {
if err := setupConnections(v, opts, v.IdentityPath); err != nil {
return false, err
}

Expand Down Expand Up @@ -500,10 +507,9 @@ func (v *MachineVM) writeConfig() error {
return nil
}

func setupConnections(v *MachineVM, opts machine.InitOptions, sshDir string) error {
func setupConnections(v *MachineVM, opts machine.InitOptions, identityPath string) error {
uri := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/user/1000/podman/podman.sock", strconv.Itoa(v.Port), v.RemoteUsername)
uriRoot := machine.SSHRemoteConnection.MakeSSHURL("localhost", "/run/podman/podman.sock", strconv.Itoa(v.Port), "root")
identity := filepath.Join(sshDir, v.Name)

uris := []url.URL{uri, uriRoot}
names := []string{v.Name, v.Name + "-root"}
Expand All @@ -515,7 +521,7 @@ func setupConnections(v *MachineVM, opts machine.InitOptions, sshDir string) err
}

for i := 0; i < 2; i++ {
if err := machine.AddConnection(&uris[i], names[i], identity, opts.IsDefault && i == 0); err != nil {
if err := machine.AddConnection(&uris[i], names[i], identityPath, opts.IsDefault && i == 0); err != nil {
return err
}
}
Expand Down Expand Up @@ -549,7 +555,7 @@ func provisionWSLDist(name string, imagePath string, prompt string) (string, err
return dist, nil
}

func createKeys(v *MachineVM, dist string, sshDir string) error {
func createKeys(v *MachineVM, dist string, sshDir string, keyFile string) error {
user := v.RemoteUsername

if err := os.MkdirAll(sshDir, 0700); err != nil {
Expand All @@ -560,7 +566,7 @@ func createKeys(v *MachineVM, dist string, sshDir string) error {
return fmt.Errorf("could not cycle WSL dist: %w", err)
}

key, err := wslCreateKeys(sshDir, v.Name, dist)
key, err := wslCreateKeys(sshDir, keyFile, dist)
if err != nil {
return fmt.Errorf("could not create ssh keys: %w", err)
}
Expand Down
32 changes: 32 additions & 0 deletions utils/identity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package utils

import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
)

func FindTargetIdentityPath(sshDir string, srcIdentity string, prefix string, rangeStart int) (string, error) {
identityFilepath := strings.TrimSpace(srcIdentity)
if len(identityFilepath) == 0 {
return FindAvailableIdentityPath(sshDir, prefix, rangeStart)
} else if filepath.IsAbs(identityFilepath) {
return identityFilepath, nil
}
return filepath.Join(sshDir, identityFilepath), nil
}

func FindAvailableIdentityPath(sshDir string, prefix string, rangeStart int) (string, error) {
for i := 0; i < 65536; i++ {
nextFilepath := filepath.Join(sshDir, fmt.Sprintf("%s-%04x", prefix, (rangeStart+i)%65536))
_, err1 := os.Stat(nextFilepath)
_, err2 := os.Stat(nextFilepath + ".pub")
if errors.Is(err1, fs.ErrNotExist) && errors.Is(err2, fs.ErrNotExist) {
return nextFilepath, nil
}
}
return "", errors.New("can't determine available identity filename")
}

0 comments on commit 815d0c7

Please sign in to comment.