diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 5912456..a467fe3 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -36,6 +36,7 @@ const ( OpWaitForSysroot = "wait-for-sysroot" OpLvmActivate = "lvm-activation" OpKcryptUnlock = "unlock-all" + OpKcryptUpgrade = "upgrade-kcrypt" PersistentStateTarget = "/usr/local/.state" LogDir = "/run/immucore" LinuxFs = "ext4" diff --git a/internal/utils/upgrade_kcrypt.go b/internal/utils/upgrade_kcrypt.go new file mode 100644 index 0000000..258fdda --- /dev/null +++ b/internal/utils/upgrade_kcrypt.go @@ -0,0 +1,61 @@ +package utils + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/gofrs/uuid" + "github.com/jaypipes/ghw" + "github.com/kairos-io/kairos-sdk/utils" +) + +// UpgradeKcryptPartitions will try check for the uuid of the persistent partition and upgrade its uuid. +func UpgradeKcryptPartitions() error { + // Generate the predictable UUID + persistentUUID := uuid.NewV5(uuid.NamespaceURL, "COS_PERSISTENT") + // Check if there are any LUKS partitions, otherwise ignore + blk, err := ghw.Block() + if err != nil { + return err + } + + for _, disk := range blk.Disks { + for _, p := range disk.Partitions { + if p.Type == "crypto_LUKS" { + // Check against known partition label on persistent + Log.Debug().Str("label", p.Label).Str("dev", p.Name).Msg("found luks partition") + if p.Label == "persistent" { + // Get current UUID + volumeUUID, err := utils.SH(fmt.Sprintf("cryptsetup luksUUID %s", filepath.Join("/dev", p.Name))) + if err != nil { + Log.Err(err).Send() + return err + } + volumeUUID = strings.TrimSpace(volumeUUID) + volumeUUIDParsed, err := uuid.FromString(volumeUUID) + Log.Debug().Interface("volumeUUID", volumeUUIDParsed).Send() + Log.Debug().Interface("persistentUUID", persistentUUID).Send() + if err != nil { + Log.Err(err).Send() + return err + } + + // Check to see if it's the same already to not do anything + if volumeUUIDParsed.String() != persistentUUID.String() { + Log.Debug().Str("old", volumeUUIDParsed.String()).Str("new", persistentUUID.String()).Msg("Uuid is different, updating") + out, err := utils.SH(fmt.Sprintf("cryptsetup luksUUID -q --uuid %s %s", persistentUUID, filepath.Join("/dev", p.Name))) + if err != nil { + Log.Err(err).Str("out", out).Msg("Updating uuid failed") + return err + } + } else { + Log.Debug().Msg("UUIDs are the same, not updating") + } + } + } + } + } + + return nil +} diff --git a/pkg/mount/dag_normal_boot.go b/pkg/mount/dag_normal_boot.go index e3c6249..98e40c9 100644 --- a/pkg/mount/dag_normal_boot.go +++ b/pkg/mount/dag_normal_boot.go @@ -24,11 +24,17 @@ func (s *State) RegisterNormalBoot(g *herd.Graph) error { // Mount Root (COS_STATE or COS_RECOVERY and then the image active/passive/recovery under s.Rootdir) s.LogIfError(s.MountRootDagStep(g), "running mount root stage") - // Run unlock. Depends on mount root because it needs the kcrypt-discovery-challenger available under /sysroot - s.LogIfError(s.RunKcrypt(g, herd.WithDeps(cnst.OpMountRoot)), "kcrypt unlock") + // Upgrade kcrypt partitions to kcrypt 0.6.0 if any + // Depend on LVM in case the LVM is encrypted somehow? Not sure if possible. + s.LogIfError(s.RunKcryptUpgrade(g, herd.WithDeps(cnst.OpLvmActivate)), "upgrade kcrypt partitions") + + // Run unlock. + // Depends on mount root because it needs the kcrypt-discovery-challenger available under /sysroot + // Depends on OpKcryptUpgrade until we don't support upgrading from 1.X to the current version + s.LogIfError(s.RunKcrypt(g, herd.WithDeps(cnst.OpMountRoot, cnst.OpKcryptUpgrade)), "kcrypt unlock") // Mount COS_OEM (After root as it mounts under s.Rootdir/oem) - s.LogIfError(s.MountOemDagStep(g, cnst.OpMountRoot, cnst.OpLvmActivate, cnst.OpKcryptUnlock), "oem mount") + s.LogIfError(s.MountOemDagStep(g, cnst.OpMountRoot, cnst.OpLvmActivate), "oem mount") // Run yip stage rootfs. Requires root+oem+sentinel to be mounted s.LogIfError(s.RootfsStageDagStep(g, herd.WithDeps(cnst.OpMountRoot, cnst.OpMountOEM, cnst.OpSentinel)), "running rootfs stage") diff --git a/pkg/mount/dag_steps.go b/pkg/mount/dag_steps.go index 2cf4069..dde9c4f 100644 --- a/pkg/mount/dag_steps.go +++ b/pkg/mount/dag_steps.go @@ -598,3 +598,12 @@ func (s *State) LVMActivation(g *herd.Graph) error { func (s *State) RunKcrypt(g *herd.Graph, opts ...herd.OpOption) error { return g.Add(cnst.OpKcryptUnlock, append(opts, herd.WithCallback(func(ctx context.Context) error { return kcrypt.UnlockAll() }))...) } + +// RunKcryptUpgrade will upgrade encrypted partitions created with 1.x to the new 2.x format, where +// we inspect the uuid of the partition directly to know which label to use for the key +// As those old installs have an old agent the only way to do it is during the first boot after the upgrade to the newest immucore. +func (s *State) RunKcryptUpgrade(g *herd.Graph, opts ...herd.OpOption) error { + return g.Add(cnst.OpKcryptUpgrade, append(opts, herd.WithCallback(func(ctx context.Context) error { + return internalUtils.UpgradeKcryptPartitions() + }))...) +}