diff --git a/README.md b/README.md index d2f4fa9ef12..e0b91064dc6 100644 --- a/README.md +++ b/README.md @@ -250,7 +250,7 @@ The current default spec: ## How it works - Hypervisor: QEMU with HVF accelerator -- Filesystem sharing: [reverse sshfs](https://github.com/lima-vm/sshocker/blob/v0.2.0/pkg/reversesshfs/reversesshfs.go) (likely to be replaced with 9p or Samba in future) +- Filesystem sharing: [Reverse SSHFS (default), or virtio-9p-pci aka virtfs](./docs/mount.md) - Port forwarding: `ssh -L`, automated by watching `/proc/net/tcp` and `iptables` events in the guest ## Developer guide @@ -266,6 +266,7 @@ The current default spec: - Performance optimization - More guest distros - Windows hosts +- virtio-fs to replace virtio-9p-pci aka virtfs (work has to be done on QEMU repo) - [vsock](https://github.com/apple/darwin-xnu/blob/xnu-7195.81.3/bsd/man/man4/vsock.4) to replace SSH (work has to be done on QEMU repo) ## FAQs & Troubleshooting diff --git a/docs/mount.md b/docs/mount.md new file mode 100644 index 00000000000..228a339b0d6 --- /dev/null +++ b/docs/mount.md @@ -0,0 +1,77 @@ +# Filesystem mounts + +Lima supports several methods for mounting the host filesystem into the guest. + +The default mount type is shown in the following table: + +| Lima Version | Default | +| ---------------- | ----------------------------------- | +| < 0.10 | reverse-sshfs + Builtin SFTP server | +| >= 0.10 | reverse-sshfs + OpenSSH SFTP server | +| >= 1.0 (Planned) | 9p | + +## Mount types + +### reverse-sshfs +The "reverse-sshfs" mount type exposes the host filesystem by running an SFTP server on the host. +While the host works as an SFTP server, the host does not open any TCP port, +as the host initiates an SSH connection into the guest and let the guest connect to the SFTP server via the stdin. + +An example configuration: +```yaml +mountType: "reverse-sshfs" +mounts: +- location: "~" + sshfs: + # Enabling the SSHFS cache will increase performance of the mounted filesystem, at + # the cost of potentially not reflecting changes made on the host in a timely manner. + # Warning: It looks like PHP filesystem access does not work correctly when + # the cache is disabled. + # 🟢 Builtin default: true + cache: null + # SSHFS has an optional flag called 'follow_symlinks'. This allows mounts + # to be properly resolved in the guest os and allow for access to the + # contents of the symlink. As a result, symlinked files & folders on the Host + # system will look and feel like regular files directories in the Guest OS. + # 🟢 Builtin default: false + followSymlinks: null + # SFTP driver, "builtin" or "openssh-sftp-server". "openssh-sftp-server" is recommended. + # 🟢 Builtin default: "openssh-sftp-server" if OpenSSH SFTP Server binary is found, otherwise "builtin" + sftpDriver: null +``` + +The default value of `sftpDriver` has been set to "openssh-sftp-server" since Lima v0.10, when an OpenSSH SFTP Server binary +such as `/usr/libexec/sftp-server` is detected on the host. +Lima prior to v0.10 had used "builtin" as the SFTP driver. + +#### Caveats +- A mount is disabled when the SSH connection was shut down. +- A compromised `sshfs` process in the guest may have an access to unexposed host directories. + +### 9p +The "9p" mount type is implemented by using QEMU's virtio-9p-pci devices. +virtio-9p-pci is also known as "virtfs", but note that this is unrelated to [virtio-fs](https://virtio-fs.gitlab.io/). + +An example configuration: +```yaml +mountType: "9p" +mounts: +- location: "~" + 9p: + # Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none". + # 🟢 Builtin default: "mapped-xattr" + securityModel: null + # Select 9P protocol version. Valid options are: "9p2000" (legacy), "9p2000.u", "9p2000.L". + # 🟢 Builtin default: "9p2000.L" + protocolVersion: null + # The number of bytes to use for 9p packet payload, where 4KiB is the absolute minimum. + # 🟢 Builtin default: "128KiB" + msize: null + # Specifies a caching policy. Valid options are: "none", "loose", "fscache" and "mmap". + # Try choosing "mmap" or "none" if you see a stability issue with the default "fscache". + # See https://www.kernel.org/doc/Documentation/filesystems/9p.txt + # 🟢 Builtin default: "fscache" for non-writable mounts, "mmap" for writable mounts + cache: null +``` +#### Caveats +- The "9p" mount type is known to be incompatible with CentOS, Rocky Linux, and AlmaLinux as their kernel do not support `CONFIG_NET_9P_VIRTIO`. diff --git a/examples/default.yaml b/examples/default.yaml index 86695c770b8..3028a9e4ad5 100644 --- a/examples/default.yaml +++ b/examples/default.yaml @@ -61,6 +61,9 @@ mounts: # system will look and feel like regular files directories in the Guest OS. # 🟢 Builtin default: false followSymlinks: null + # SFTP driver, "builtin" or "openssh-sftp-server". "openssh-sftp-server" is recommended. + # 🟢 Builtin default: "openssh-sftp-server" if OpenSSH SFTP Server binary is found, otherwise "builtin" + sftpDriver: null 9p: # Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none". # 🟢 Builtin default: "mapped-xattr" diff --git a/go.mod b/go.mod index 1f92fdf38ee..a6c0808be35 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/google/go-cmp v0.5.7 github.com/gorilla/mux v1.8.0 github.com/hashicorp/go-multierror v1.1.1 - github.com/lima-vm/sshocker v0.2.3 + github.com/lima-vm/sshocker v0.3.0 github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-shellwords v1.0.12 github.com/miekg/dns v1.1.48 diff --git a/go.sum b/go.sum index 4252ba51c31..6033ffca16b 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lima-vm/sshocker v0.2.3 h1:z4xTGS51Bo03adLHcetl3WjSK4zbJeFe6GT0ChiZI7I= -github.com/lima-vm/sshocker v0.2.3/go.mod h1:tdwxS0o2d2vNfe2CN+QN9J8XF3VPX4y9IUu7fpy2ibc= +github.com/lima-vm/sshocker v0.3.0 h1:4W7AFfwqkhPwBIOtwfnxxggdS3/bs6JkTYT1RfrXwfQ= +github.com/lima-vm/sshocker v0.3.0/go.mod h1:LtQ68MCRh2MPgAczFNyElrOObNR1lsb31YCeFGgeLyc= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= diff --git a/pkg/hostagent/mount.go b/pkg/hostagent/mount.go index 6621313cec6..ee42fe7ab9b 100644 --- a/pkg/hostagent/mount.go +++ b/pkg/hostagent/mount.go @@ -51,6 +51,7 @@ func (a *HostAgent) setupMount(ctx context.Context, m limayaml.Mount) (*mount, e } logrus.Infof("Mounting %q", expanded) rsf := &reversesshfs.ReverseSSHFS{ + Driver: *m.SSHFS.SFTPDriver, SSHConfig: a.sshConfig, LocalPath: expanded, Host: "127.0.0.1", diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 0e4867dd1c5..a73fb2c842f 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -376,6 +376,9 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { if mount.SSHFS.FollowSymlinks != nil { mounts[i].SSHFS.FollowSymlinks = mount.SSHFS.FollowSymlinks } + if mount.SSHFS.SFTPDriver != nil { + mounts[i].SSHFS.SFTPDriver = mount.SSHFS.SFTPDriver + } if mount.NineP.SecurityModel != nil { mounts[i].NineP.SecurityModel = mount.NineP.SecurityModel } @@ -406,6 +409,9 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { if mount.SSHFS.FollowSymlinks == nil { mount.SSHFS.FollowSymlinks = pointer.Bool(false) } + if mount.SSHFS.SFTPDriver == nil { + mount.SSHFS.SFTPDriver = pointer.String("") + } if mount.NineP.SecurityModel == nil { mounts[i].NineP.SecurityModel = pointer.String(Default9pSecurityModel) } diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index 8d6e05633ee..a7327a4cecb 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -146,6 +146,7 @@ func TestFillDefault(t *testing.T) { expect.Mounts[0].Writable = pointer.Bool(false) expect.Mounts[0].SSHFS.Cache = pointer.Bool(true) expect.Mounts[0].SSHFS.FollowSymlinks = pointer.Bool(false) + expect.Mounts[0].SSHFS.SFTPDriver = pointer.String("") expect.Mounts[0].NineP.SecurityModel = pointer.String(Default9pSecurityModel) expect.Mounts[0].NineP.ProtocolVersion = pointer.String(Default9pProtocolVersion) expect.Mounts[0].NineP.Msize = pointer.String(Default9pMsize) @@ -297,6 +298,7 @@ func TestFillDefault(t *testing.T) { expect.Containerd.Archives[0].Arch = *d.Arch expect.Mounts[0].SSHFS.Cache = pointer.Bool(true) expect.Mounts[0].SSHFS.FollowSymlinks = pointer.Bool(false) + expect.Mounts[0].SSHFS.SFTPDriver = pointer.String("") expect.Mounts[0].NineP.SecurityModel = pointer.String(Default9pSecurityModel) expect.Mounts[0].NineP.ProtocolVersion = pointer.String(Default9pProtocolVersion) expect.Mounts[0].NineP.Msize = pointer.String(Default9pMsize) diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index 013000d7511..c7ba62f0f95 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -57,9 +57,17 @@ type Mount struct { NineP NineP `yaml:"9p,omitempty" json:"9p,omitempty"` } +type SFTPDriver = string + +const ( + SFTPDriverBuiltin = "builtin" + SFTPDriverOpenSSHSFTPServer = "openssh-sftp-server" +) + type SSHFS struct { - Cache *bool `yaml:"cache,omitempty" json:"cache,omitempty"` - FollowSymlinks *bool `yaml:"followSymlinks,omitempty" json:"followSymlinks,omitempty"` + Cache *bool `yaml:"cache,omitempty" json:"cache,omitempty"` + FollowSymlinks *bool `yaml:"followSymlinks,omitempty" json:"followSymlinks,omitempty"` + SFTPDriver *SFTPDriver `yaml:"sftpDriver,omitempty" json:"sftpDriver,omitempty"` } type NineP struct {