mirror of
				https://github.com/linka-cloud/d2vm.git
				synced 2025-10-31 01:22:27 +00:00 
			
		
		
		
	luks: implements support for centos
Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
		
							
								
								
									
										33
									
								
								builder.go
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								builder.go
									
									
									
									
									
								
							| @@ -150,10 +150,6 @@ func NewBuilder(ctx context.Context, workdir, imgTag, disk string, size uint64, | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	if luksPassword != "" { | 	if luksPassword != "" { | ||||||
| 		// TODO(adphi): remove this check when we support luks encryption on other distros |  | ||||||
| 		if osRelease.ID == ReleaseCentOS { |  | ||||||
| 			return nil, fmt.Errorf("luks encryption is not supported on centos") |  | ||||||
| 		} |  | ||||||
| 		if !splitBoot { | 		if !splitBoot { | ||||||
| 			return nil, fmt.Errorf("luks encryption requires split boot") | 			return nil, fmt.Errorf("luks encryption requires split boot") | ||||||
| 		} | 		} | ||||||
| @@ -314,11 +310,7 @@ func (b *builder) mountImg(ctx context.Context) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	b.bootPart = fmt.Sprintf("/dev/mapper/%sp1", filepath.Base(b.loDevice)) | 	b.bootPart = fmt.Sprintf("/dev/mapper/%sp1", filepath.Base(b.loDevice)) | ||||||
| 	if b.splitBoot { | 	b.rootPart = ifElse(b.splitBoot, fmt.Sprintf("/dev/mapper/%sp2", filepath.Base(b.loDevice)), b.bootPart) | ||||||
| 		b.rootPart = fmt.Sprintf("/dev/mapper/%sp2", filepath.Base(b.loDevice)) |  | ||||||
| 	} else { |  | ||||||
| 		b.rootPart = b.bootPart |  | ||||||
| 	} |  | ||||||
| 	if b.isLuksEnabled() { | 	if b.isLuksEnabled() { | ||||||
| 		logrus.Infof("encrypting root partition") | 		logrus.Infof("encrypting root partition") | ||||||
| 		f, err := os.CreateTemp("", "key") | 		f, err := os.CreateTemp("", "key") | ||||||
| @@ -408,7 +400,10 @@ func diskUUID(ctx context.Context, disk string) (string, error) { | |||||||
|  |  | ||||||
| func (b *builder) setupRootFS(ctx context.Context) (err error) { | func (b *builder) setupRootFS(ctx context.Context) (err error) { | ||||||
| 	logrus.Infof("setting up rootfs") | 	logrus.Infof("setting up rootfs") | ||||||
| 	b.rootUUID, err = diskUUID(ctx, b.rootPart) | 	b.rootUUID, err = diskUUID(ctx, ifElse(b.isLuksEnabled(), b.mappedCryptRoot, b.rootPart)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	var fstab string | 	var fstab string | ||||||
| 	if b.splitBoot { | 	if b.splitBoot { | ||||||
| 		b.bootUUID, err = diskUUID(ctx, b.bootPart) | 		b.bootUUID, err = diskUUID(ctx, b.bootPart) | ||||||
| @@ -503,12 +498,15 @@ func (b *builder) installKernel(ctx context.Context) error { | |||||||
| 	} | 	} | ||||||
| 	var cfg string | 	var cfg string | ||||||
| 	if b.isLuksEnabled() { | 	if b.isLuksEnabled() { | ||||||
| 		if b.osRelease.ID != ReleaseAlpine { | 		switch b.osRelease.ID { | ||||||
| 			cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s root=/dev/mapper/root cryptopts=target=root,source=UUID=%s", b.cmdLineExtra, b.cryptUUID)) | 		case ReleaseAlpine: | ||||||
| 			cfg = strings.Replace(cfg, "root=UUID="+b.rootUUID, "", 1) |  | ||||||
| 		} else { |  | ||||||
| 			cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s root=/dev/mapper/root cryptdm=root", b.cmdLineExtra)) | 			cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s root=/dev/mapper/root cryptdm=root", b.cmdLineExtra)) | ||||||
| 			cfg = strings.Replace(cfg, "root=UUID="+b.rootUUID, "cryptroot=UUID="+b.cryptUUID, 1) | 			cfg = strings.Replace(cfg, "root=UUID="+b.rootUUID, "cryptroot=UUID="+b.cryptUUID, 1) | ||||||
|  | 		case ReleaseCentOS: | ||||||
|  | 			cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s rd.luks.name=UUID=%s rd.luks.uuid=%s rd.luks.crypttab=0", b.cmdLineExtra, b.rootUUID, b.cryptUUID)) | ||||||
|  | 		default: | ||||||
|  | 			cfg = fmt.Sprintf(sysconfig, b.rootUUID, fmt.Sprintf("%s root=/dev/mapper/root cryptopts=target=root,source=UUID=%s", b.cmdLineExtra, b.cryptUUID)) | ||||||
|  | 			cfg = strings.Replace(cfg, "root=UUID="+b.rootUUID, "", 1) | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		cfg = fmt.Sprintf(sysconfig, b.rootUUID, b.cmdLineExtra) | 		cfg = fmt.Sprintf(sysconfig, b.rootUUID, b.cmdLineExtra) | ||||||
| @@ -577,3 +575,10 @@ func checkDependencies() error { | |||||||
| func OutputFormats() []string { | func OutputFormats() []string { | ||||||
| 	return formats[:] | 	return formats[:] | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func ifElse(v bool, t string, f string) string { | ||||||
|  | 	if v { | ||||||
|  | 		return t | ||||||
|  | 	} | ||||||
|  | 	return f | ||||||
|  | } | ||||||
|   | |||||||
| @@ -38,11 +38,16 @@ type test struct { | |||||||
| 	args []string | 	args []string | ||||||
| } | } | ||||||
|  |  | ||||||
| var images = []string{ | type img struct { | ||||||
| 	"alpine:3.17", | 	name string | ||||||
| 	"ubuntu:20.04", | 	luks string | ||||||
| 	"debian:11", | } | ||||||
| 	"centos:8", |  | ||||||
|  | var images = []img{ | ||||||
|  | 	{name: "alpine:3.17", luks: "Enter passphrase for /dev/sda2:"}, | ||||||
|  | 	{name: "ubuntu:20.04", luks: "Please unlock disk root:"}, | ||||||
|  | 	{name: "debian:11", luks: "Please unlock disk root:"}, | ||||||
|  | 	{name: "centos:8", luks: "Please enter passphrase for disk"}, | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestConvert(t *testing.T) { | func TestConvert(t *testing.T) { | ||||||
| @@ -55,6 +60,10 @@ func TestConvert(t *testing.T) { | |||||||
| 			name: "split-boot", | 			name: "split-boot", | ||||||
| 			args: []string{"--split-boot"}, | 			args: []string{"--split-boot"}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "luks", | ||||||
|  | 			args: []string{"--luks-password=root"}, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, tt := range tests { | 	for _, tt := range tests { | ||||||
| @@ -64,21 +73,21 @@ func TestConvert(t *testing.T) { | |||||||
| 			require.NoError(os.MkdirAll(dir, os.ModePerm)) | 			require.NoError(os.MkdirAll(dir, os.ModePerm)) | ||||||
|  |  | ||||||
| 			defer os.RemoveAll(dir) | 			defer os.RemoveAll(dir) | ||||||
| 			for _, i := range images { | 			for _, img := range images { | ||||||
| 				t.Run(i, func(t *testing.T) { | 				t.Run(img.name, func(t *testing.T) { | ||||||
| 					ctx, cancel := context.WithCancel(context.Background()) | 					ctx, cancel := context.WithCancel(context.Background()) | ||||||
| 					defer cancel() | 					defer cancel() | ||||||
|  |  | ||||||
| 					// t.Parallel() | 					// t.Parallel() | ||||||
| 					require := require2.New(t) | 					require := require2.New(t) | ||||||
|  |  | ||||||
| 					out := filepath.Join(dir, strings.NewReplacer(":", "-", ".", "-").Replace(i)+".qcow2") | 					out := filepath.Join(dir, strings.NewReplacer(":", "-", ".", "-").Replace(img.name)+".qcow2") | ||||||
|  |  | ||||||
| 					if _, err := os.Stat(out); err == nil { | 					if _, err := os.Stat(out); err == nil { | ||||||
| 						require.NoError(os.Remove(out)) | 						require.NoError(os.Remove(out)) | ||||||
| 					} | 					} | ||||||
|  | 					 | ||||||
| 					require.NoError(docker.RunD2VM(ctx, d2vm.Image, d2vm.Version, dir, dir, "convert", append([]string{"-p", "root", "-o", "/out/" + filepath.Base(out), "-v", i}, tt.args...)...)) | 					require.NoError(docker.RunD2VM(ctx, d2vm.Image, d2vm.Version, dir, dir, "convert", append([]string{"-p", "root", "-o", "/out/" + filepath.Base(out), "-v", "--keep-cache", img.name}, tt.args...)...)) | ||||||
|  |  | ||||||
| 					inr, inw := io.Pipe() | 					inr, inw := io.Pipe() | ||||||
| 					defer inr.Close() | 					defer inr.Close() | ||||||
| @@ -93,6 +102,9 @@ func TestConvert(t *testing.T) { | |||||||
| 						password := []byte("Password:") | 						password := []byte("Password:") | ||||||
| 						s := bufio.NewScanner(outr) | 						s := bufio.NewScanner(outr) | ||||||
| 						s.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { | 						s.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { | ||||||
|  | 							if i := bytes.Index(data, []byte(img.luks)); i >= 0 { | ||||||
|  | 								return i + len(img.luks), []byte(img.luks), nil | ||||||
|  | 							} | ||||||
| 							if i := bytes.Index(data, login); i >= 0 { | 							if i := bytes.Index(data, login); i >= 0 { | ||||||
| 								return i + len(login), login, nil | 								return i + len(login), login, nil | ||||||
| 							} | 							} | ||||||
| @@ -106,8 +118,14 @@ func TestConvert(t *testing.T) { | |||||||
| 						}) | 						}) | ||||||
| 						for s.Scan() { | 						for s.Scan() { | ||||||
| 							b := s.Bytes() | 							b := s.Bytes() | ||||||
|  | 							if bytes.Contains(b, []byte(img.luks)) { | ||||||
|  | 								t.Logf("sending luks password") | ||||||
|  | 								if _, err := inw.Write([]byte("root\n")); err != nil { | ||||||
|  | 									t.Logf("failed to write luks password: %v", err) | ||||||
|  | 									cancel() | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
| 							if bytes.Contains(b, login) { | 							if bytes.Contains(b, login) { | ||||||
| 								t.Logf("vm ready") |  | ||||||
| 								t.Logf("sending login") | 								t.Logf("sending login") | ||||||
| 								if _, err := inw.Write([]byte("root\n")); err != nil { | 								if _, err := inw.Write([]byte("root\n")); err != nil { | ||||||
| 									t.Logf("failed to write login: %v", err) | 									t.Logf("failed to write login: %v", err) | ||||||
| @@ -134,7 +152,7 @@ func TestConvert(t *testing.T) { | |||||||
| 							cancel() | 							cancel() | ||||||
| 						} | 						} | ||||||
| 					}() | 					}() | ||||||
| 					if err := qemu.Run(ctx, out, qemu.WithStdin(inr), qemu.WithStdout(io.MultiWriter(outw, os.Stdout)), qemu.WithStderr(io.Discard)); err != nil && !success.Load() { | 					if err := qemu.Run(ctx, out, qemu.WithStdin(inr), qemu.WithStdout(io.MultiWriter(outw, os.Stdout)), qemu.WithStderr(io.Discard), qemu.WithMemory(2048)); err != nil && !success.Load() { | ||||||
| 						t.Fatalf("failed to run qemu: %v", err) | 						t.Fatalf("failed to run qemu: %v", err) | ||||||
| 					} | 					} | ||||||
| 				}) | 				}) | ||||||
|   | |||||||
| @@ -7,12 +7,20 @@ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \ | |||||||
|  |  | ||||||
| RUN yum update -y | RUN yum update -y | ||||||
|  |  | ||||||
| RUN yum install -y kernel systemd NetworkManager e2fsprogs sudo && \ | RUN yum install -y \ | ||||||
|  |     kernel \ | ||||||
|  |     systemd \ | ||||||
|  |     NetworkManager \ | ||||||
|  |     e2fsprogs \ | ||||||
|  |     {{- if .Luks }} | ||||||
|  |     cryptsetup \ | ||||||
|  |     {{- end }} | ||||||
|  |     sudo && \ | ||||||
|     systemctl enable NetworkManager && \ |     systemctl enable NetworkManager && \ | ||||||
|     systemctl unmask systemd-remount-fs.service && \ |     systemctl unmask systemd-remount-fs.service && \ | ||||||
|     systemctl unmask getty.target |     systemctl unmask getty.target | ||||||
|  |  | ||||||
| RUN dracut --no-hostonly --regenerate-all --force && \ | RUN dracut --no-hostonly --regenerate-all --force {{ if .Luks }}--install="/usr/sbin/cryptsetup"{{ end }}&& \ | ||||||
|     cd /boot && \ |     cd /boot && \ | ||||||
|     ln -s $(find . -name 'vmlinuz-*') vmlinuz && \ |     ln -s $(find . -name 'vmlinuz-*') vmlinuz && \ | ||||||
|     ln -s $(find . -name 'initramfs-*.img') initrd.img |     ln -s $(find . -name 'initramfs-*.img') initrd.img | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user