Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use dynamic identity file names by default #18487

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
rhatdan marked this conversation as resolved.
Show resolved Hide resolved
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would imagine this change is also applicable to the hyperv and applehv implementations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hyper-V was covered in original changeset. I added applevh changes. Haven't tested either of them locally (for applehv it seems there are some patches needed to enable it), but the implementations of the ssh keys part looked exactly like ones from QEMU implementation (which is logical as all these flavors are using CoreOS).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applehv code should all be in main now .. it is not complete but booting it works. See https://fedorapeople.org/groups/podman/testing/applehv/

Copy link
Contributor Author

@arixmkii arixmkii May 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applehv code should all be in main now

I noticed it. The parts, which were available before my change should be enough to implement the functionality for applehv (the change I added), but I can rebase to latest main if you insist. Will test applehv locally later this week.

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")
}