diff --git a/docs/how-to/how-to-run-rootless-vmm.md b/docs/how-to/how-to-run-rootless-vmm.md index 3986de252..7711c1325 100644 --- a/docs/how-to/how-to-run-rootless-vmm.md +++ b/docs/how-to/how-to-run-rootless-vmm.md @@ -1,5 +1,5 @@ ## Introduction -To improve security, Kata Container supports running the VMM process (currently only QEMU) as a non-`root` user. +To improve security, Kata Container supports running the VMM process (QEMU and cloud-hypervisor) as a non-`root` user. This document describes how to enable the rootless VMM mode and its limitations. ## Pre-requisites @@ -27,7 +27,7 @@ Another necessary change is to move the hypervisor runtime files (e.g. `vhost-fs ## Limitations 1. Only the VMM process is running as a non-root user. Other processes such as Kata Container shimv2 and `virtiofsd` still run as the root user. -2. Currently, this feature is only supported in QEMU. Still need to bring it to Firecracker and Cloud Hypervisor (see https://github.com/kata-containers/kata-containers/issues/2567). +2. Currently, this feature is only supported in QEMU and cloud-hypervisor. For firecracker, you can use jailer to run the VMM process with a non-root user. 3. Certain features will not work when rootless VMM is enabled, including: 1. Passing devices to the guest (`virtio-blk`, `virtio-scsi`) will not work if the non-privileged user does not have permission to access it (leading to a permission denied error). A more permissive permission (e.g. 666) may overcome this issue. However, you need to be aware of the potential security implications of reducing the security on such devices. 2. `vfio` device will also not work because of permission denied error. \ No newline at end of file diff --git a/src/runtime/config/configuration-clh.toml.in b/src/runtime/config/configuration-clh.toml.in index df7cc7ac5..d79770487 100644 --- a/src/runtime/config/configuration-clh.toml.in +++ b/src/runtime/config/configuration-clh.toml.in @@ -41,6 +41,11 @@ rootfs_type=@DEFROOTFSTYPE@ # Default false # confidential_guest = true +# Enable running clh VMM as a non-root user. +# By default clh VMM run as root. When this is set to true, clh VMM process runs as +# a non-root random user. See documentation for the limitations of this mode. +# rootless = true + # disable applying SELinux on the VMM process (default false) disable_selinux=@DEFDISABLESELINUX@ diff --git a/src/runtime/pkg/katautils/config.go b/src/runtime/pkg/katautils/config.go index 993ca36b7..763e9a6f4 100644 --- a/src/runtime/pkg/katautils/config.go +++ b/src/runtime/pkg/katautils/config.go @@ -1056,6 +1056,7 @@ func newClhHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { EnableAnnotations: h.EnableAnnotations, DisableSeccomp: h.DisableSeccomp, ConfidentialGuest: h.ConfidentialGuest, + Rootless: h.Rootless, DisableSeLinux: h.DisableSeLinux, DisableGuestSeLinux: h.DisableGuestSeLinux, NetRateLimiterBwMaxRate: h.getNetRateLimiterBwMaxRate(), diff --git a/src/runtime/virtcontainers/clh.go b/src/runtime/virtcontainers/clh.go index 1f493772d..1cf40c4d2 100644 --- a/src/runtime/virtcontainers/clh.go +++ b/src/runtime/virtcontainers/clh.go @@ -19,6 +19,7 @@ import ( "net/http/httputil" "os" "os/exec" + "os/user" "path/filepath" "regexp" "strconv" @@ -37,6 +38,8 @@ import ( "github.com/kata-containers/kata-containers/src/runtime/pkg/device/config" hv "github.com/kata-containers/kata-containers/src/runtime/pkg/hypervisors" "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils/katatrace" + pkgUtils "github.com/kata-containers/kata-containers/src/runtime/pkg/utils" + "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/rootless" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils" ) @@ -653,7 +656,7 @@ func (clh *cloudHypervisor) StartVM(ctx context.Context, timeout int) error { clh.Logger().WithField("function", "StartVM").Info("starting Sandbox") vmPath := filepath.Join(clh.config.VMStorePath, clh.id) - err := os.MkdirAll(vmPath, DirMode) + err := utils.MkdirAllWithInheritedOwner(vmPath, DirMode) if err != nil { return err } @@ -1359,9 +1362,16 @@ func (clh *cloudHypervisor) launchClh() (int, error) { cmdHypervisor.Stdout = clh.console } } - cmdHypervisor.Stderr = cmdHypervisor.Stdout + attr := syscall.SysProcAttr{} + attr.Credential = &syscall.Credential{ + Uid: clh.config.Uid, + Gid: clh.config.Gid, + Groups: clh.config.Groups, + } + cmdHypervisor.SysProcAttr = &attr + err = utils.StartCmd(cmdHypervisor) if err != nil { return -1, err @@ -1686,6 +1696,30 @@ func (clh *cloudHypervisor) cleanupVM(force bool) error { clh.Logger().WithError(err).WithField("path", dir).Warnf("failed to remove vm path") } } + if rootless.IsRootless() { + if _, err := user.Lookup(clh.config.User); err != nil { + clh.Logger().WithError(err).WithFields( + log.Fields{ + "user": clh.config.User, + "uid": clh.config.Uid, + }).Warn("failed to find the user, it might have been removed") + return nil + } + + if err := pkgUtils.RemoveVmmUser(clh.config.User); err != nil { + clh.Logger().WithError(err).WithFields( + log.Fields{ + "user": clh.config.User, + "uid": clh.config.Uid, + }).Warn("failed to delete the user") + return nil + } + clh.Logger().WithFields( + log.Fields{ + "user": clh.config.User, + "uid": clh.config.Uid, + }).Debug("successfully removed the non root user") + } clh.reset() diff --git a/src/runtime/virtcontainers/qemu.go b/src/runtime/virtcontainers/qemu.go index 16872c126..3c8cad520 100644 --- a/src/runtime/virtcontainers/qemu.go +++ b/src/runtime/virtcontainers/qemu.go @@ -1183,6 +1183,7 @@ func (q *qemu) cleanupVM() error { "user": q.config.User, "uid": q.config.Uid, }).Warn("failed to delete the user") + return nil } q.Logger().WithFields( logrus.Fields{