diff --git a/internal/distro/rhel9/partition_tables.go b/internal/distro/rhel9/partition_tables.go index a3b56e06f..17ca6c0db 100644 --- a/internal/distro/rhel9/partition_tables.go +++ b/internal/distro/rhel9/partition_tables.go @@ -222,13 +222,23 @@ var edgeBasePartitionTables = distro.BasePartitionTableMap{ Policy: "{}", RemovePassphrase: true, }, - Payload: &disk.Filesystem{ - Type: "xfs", - Label: "root", - Mountpoint: "/", - FSTabOptions: "defaults", - FSTabFreq: 0, - FSTabPassNo: 0, + Payload: &disk.LVMVolumeGroup{ + Name: "rootvg", + Description: "built with lvm2 and osbuild", + LogicalVolumes: []disk.LVMLogicalVolume{ + { + Size: 9 * 1024 * 1024 * 1024, // 9 GB + Name: "rootlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, }, }, }, @@ -282,13 +292,23 @@ var edgeBasePartitionTables = distro.BasePartitionTableMap{ Policy: "{}", RemovePassphrase: true, }, - Payload: &disk.Filesystem{ - Type: "xfs", - Label: "root", - Mountpoint: "/", - FSTabOptions: "defaults", - FSTabFreq: 0, - FSTabPassNo: 0, + Payload: &disk.LVMVolumeGroup{ + Name: "rootvg", + Description: "built with lvm2 and osbuild", + LogicalVolumes: []disk.LVMLogicalVolume{ + { + Size: 9 * 1024 * 1024 * 1024, // 9 GB + Name: "rootlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, }, }, }, diff --git a/internal/osbuild/common_test.go b/internal/osbuild/common_test.go index 30cd7f489..913ae53ef 100644 --- a/internal/osbuild/common_test.go +++ b/internal/osbuild/common_test.go @@ -2,7 +2,8 @@ package osbuild import "github.com/osbuild/osbuild-composer/internal/disk" -// This is a copy of `internal/disk/disk_test.go`: +// This is a copy of `internal/disk/disk_test.go` +// (but ours has one more entry: "luks+lvm+clevisBind"): var testPartitionTables = map[string]disk.PartitionTable{ "plain": { @@ -202,6 +203,83 @@ var testPartitionTables = map[string]disk.PartitionTable{ }, }, + "luks+lvm+clevisBind": { + UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", + Type: "gpt", + Partitions: []disk.Partition{ + { + Size: 1048576, // 1MB + Bootable: true, + Type: disk.BIOSBootPartitionGUID, + UUID: disk.BIOSBootPartitionUUID, + }, + { + Size: 209715200, // 200 MB + Type: disk.EFISystemPartitionGUID, + UUID: disk.EFISystemPartitionUUID, + Payload: &disk.Filesystem{ + Type: "vfat", + UUID: disk.EFIFilesystemUUID, + Mountpoint: "/boot/efi", + Label: "EFI-SYSTEM", + FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", + FSTabFreq: 0, + FSTabPassNo: 2, + }, + }, + { + Size: 1024000, // 500 MB + Type: disk.FilesystemDataGUID, + UUID: disk.FilesystemDataUUID, + Payload: &disk.Filesystem{ + Type: "xfs", + Mountpoint: "/boot", + Label: "boot", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + { + Type: disk.FilesystemDataGUID, + UUID: disk.RootPartitionUUID, + Payload: &disk.LUKSContainer{ + Label: "crypt_root", + Cipher: "cipher_null", + Passphrase: "osbuild", + PBKDF: disk.Argon2id{ + Memory: 32, + Iterations: 4, + Parallelism: 1, + }, + Clevis: &disk.ClevisBind{ + Pin: "null", + Policy: "{}", + RemovePassphrase: true, + }, + Payload: &disk.LVMVolumeGroup{ + Name: "rootvg", + Description: "built with lvm2 and osbuild", + LogicalVolumes: []disk.LVMLogicalVolume{ + { + Size: 9 * 1024 * 1024 * 1024, // 9 GB + Name: "rootlv", + Payload: &disk.Filesystem{ + Type: "xfs", + Label: "root", + Mountpoint: "/", + FSTabOptions: "defaults", + FSTabFreq: 0, + FSTabPassNo: 0, + }, + }, + }, + }, + }, + }, + }, + }, + "btrfs": { UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0", Type: "gpt", diff --git a/internal/osbuild/device.go b/internal/osbuild/device.go index 12d58ed93..942cd4ba4 100644 --- a/internal/osbuild/device.go +++ b/internal/osbuild/device.go @@ -97,6 +97,7 @@ func GenDeviceCreationStages(pt *disk.PartitionTable, filename string) []*Stage func GenDeviceFinishStages(pt *disk.PartitionTable, filename string) []*Stage { stages := make([]*Stage, 0) + removeKeyStages := make([]*Stage, 0) genStages := func(e disk.Entity, path []disk.Entity) error { @@ -111,7 +112,7 @@ func GenDeviceFinishStages(pt *disk.PartitionTable, filename string) []*Stage { if ent.Clevis != nil { if ent.Clevis.RemovePassphrase { - stages = append(stages, NewLUKS2RemoveKeyStage(&LUKS2RemoveKeyStageOptions{ + removeKeyStages = append(removeKeyStages, NewLUKS2RemoveKeyStage(&LUKS2RemoveKeyStageOptions{ Passphrase: ent.Passphrase, }, stageDevices)) } @@ -138,6 +139,10 @@ func GenDeviceFinishStages(pt *disk.PartitionTable, filename string) []*Stage { } _ = pt.ForEachEntity(genStages) + // Ensure that "org.osbuild.luks2.remove-key" stages are done after + // "org.osbuild.lvm2.metadata" stages, we cannot open a device if its + // password has changed + stages = append(stages, removeKeyStages...) return stages } diff --git a/internal/osbuild/device_test.go b/internal/osbuild/device_test.go index ca292ab14..3a37fa468 100644 --- a/internal/osbuild/device_test.go +++ b/internal/osbuild/device_test.go @@ -114,3 +114,28 @@ func TestGenDeviceFinishStages(t *testing.T) { assert.True(ok, "Need LVM2MetadataStageOptions for org.osbuild.lvm2.metadata") assert.Equal("root", opts.VGName) } + +func TestGenDeviceFinishStagesOrderWithLVMClevisBind(t *testing.T) { + assert := assert.New(t) + + // math/rand is good enough in this case + /* #nosec G404 */ + rng := rand.New(rand.NewSource(13)) + + luks_lvm := testPartitionTables["luks+lvm+clevisBind"] + + pt, err := disk.NewPartitionTable(&luks_lvm, []blueprint.FilesystemCustomization{}, 0, false, rng) + assert.NoError(err) + + stages := GenDeviceFinishStages(pt, "image.raw") + + // we should have two stages + assert.Equal(2, len(stages)) + lvm := stages[0] + luks := stages[1] + + // the first one should be "org.osbuild.lvm2.metadata" + assert.Equal("org.osbuild.lvm2.metadata", lvm.Type) + // followed by "org.osbuild.luks2.remove-key" + assert.Equal("org.osbuild.luks2.remove-key", luks.Type) +}