diff --git a/cmd/run.go b/cmd/run.go index ce61f43..f73a99b 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -61,8 +61,8 @@ var runCmd = &cobra.Command{ os.Exit(1) } - if luksFlag && !allowLUKSLowMemoryFlag { - if vmMemAllocFlag < 2048 { + if (luksFlag || luksContainerFlag != "") && !allowLUKSLowMemoryFlag { + if vmMemAllocFlag < defaultMemAllocLUKS { if vmMemAllocFlag != defaultMemAlloc { slog.Warn("Enforcing minimum LUKS memory allocation. Please add --allow-luks-low-memory to disable this.", "min", vmMemAllocFlag, "specified", vmMemAllocFlag) } @@ -75,6 +75,8 @@ var runCmd = &cobra.Command{ slog.Info("Mounting the device", "dev", vmMountDevName, "fs", fsType, "luks", luksFlag) err := fm.Mount(vmMountDevName, vm.MountOptions{ + LUKSContainerPreopen: luksContainerFlag, + FSType: fsType, LUKS: luksFlag, }) @@ -128,6 +130,7 @@ var runCmd = &cobra.Command{ var ( luksFlag bool + luksContainerFlag string allowLUKSLowMemoryFlag bool shareListenIPFlag string ftpExtIPFlag string @@ -138,6 +141,7 @@ var ( func init() { runCmd.Flags().BoolVarP(&luksFlag, "luks", "l", false, "Use cryptsetup to open a LUKS volume (password will be prompted).") + runCmd.Flags().StringVar(&luksContainerFlag, "luks-container", "", `Specifies a device path (without "dev/" prefix) to preopen as a LUKS container (password will be prompted). Useful for accessing LVM partitions behind LUKS.`) runCmd.Flags().BoolVar(&allowLUKSLowMemoryFlag, "allow-luks-low-memory", false, "Allow VM memory allocation lower than 2048 MiB when LUKS is enabled.") runCmd.Flags().BoolVar(&debugShellFlag, "debug-shell", false, "Start a VM shell when the network file share is active.") diff --git a/cmd/runvm/runvm.go b/cmd/runvm/runvm.go index a5ea171..90a1fe0 100644 --- a/cmd/runvm/runvm.go +++ b/cmd/runvm/runvm.go @@ -93,9 +93,9 @@ func RunVM(vi *vm.VM, initFileManager bool, tapRuntimeCtx *share.NetTapRuntimeCo return 1 case <-vi.SSHUpNotifyChan(): if fm != nil { - err := fm.Init() + err := fm.InitLVM() if err != nil { - slog.Error("Failed to initialize File Manager", "error", err.Error()) + slog.Error("Failed to initialize File Manager LVM", "error", err.Error()) return 1 } } diff --git a/vm/filemanager.go b/vm/filemanager.go index 0eb147a..73f3fff 100644 --- a/vm/filemanager.go +++ b/vm/filemanager.go @@ -52,7 +52,7 @@ func NewFileManager(logger *slog.Logger, vm *VM) *FileManager { } } -func (fm *FileManager) Init() error { +func (fm *FileManager) InitLVM() error { sc, err := fm.vm.DialSSH() if err != nil { return errors.Wrap(err, "dial vm ssh") @@ -83,13 +83,13 @@ func (fm *FileManager) Lsblk() ([]byte, error) { } type MountOptions struct { + LUKSContainerPreopen string + FSType string LUKS bool } -const luksDMName = "cryptmnt" - -func (fm *FileManager) luksOpen(sc *ssh.Client, fullDevPath string) error { +func (fm *FileManager) luksOpen(sc *ssh.Client, fullDevPath string, luksDMName string) error { lg := fm.logger.With("vm-path", fullDevPath) return sshutil.NewSSHSessionWithDelayedTimeout(fm.vm.ctx, time.Second*15, sc, func(sess *ssh.Session, startTimeout func(preTimeout func())) error { @@ -197,8 +197,30 @@ func (fm *FileManager) Mount(devName string, mo MountOptions) error { defer func() { _ = sc.Close() }() + if mo.LUKSContainerPreopen != "" { + if !utils.ValidateDevName(mo.LUKSContainerPreopen) { + return fmt.Errorf("bad luks container device name") + } + + fullContainerDevPath := "/dev/" + mo.LUKSContainerPreopen + + fm.logger.Info("Preopening a LUKS container", "container", fullContainerDevPath) + + err := fm.luksOpen(sc, fullContainerDevPath, "cryptcontainer") + if err != nil { + return errors.Wrap(err, "luks (pre)open container") + } + + err = fm.InitLVM() + if err != nil { + return errors.Wrap(err, "reinit lvm") + } + } + if mo.LUKS { - err = fm.luksOpen(sc, fullDevPath) + luksDMName := "cryptmnt" + + err = fm.luksOpen(sc, fullDevPath, luksDMName) if err != nil { return errors.Wrap(err, "luks open") }