Skip to content

Commit 774a042

Browse files
committed
internal/exec/stages/files: add x-initrd.attach for LUKS on ostree
On ostree systems, soft-reboot fails with LUKS because systemd tears down the crypto device during shutdown. Unlike traditional systems where the kernel root mount prevents this, ostree's /sysroot is a regular mount. Add x-initrd.attach to crypttab entries on ostree systems (detected via /run/ostree-booted or OSTREE_BOOTED=1 env var). This tells systemd- cryptsetup-generator to skip adding Conflicts=umount.target, preventing device teardown. Non-ostree systems are unchanged. Fixes: #2216
1 parent a1a82e2 commit 774a042

2 files changed

Lines changed: 41 additions & 5 deletions

File tree

docs/release-notes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ nav_order: 9
1414

1515
### Bug fixes
1616

17+
- Add `x-initrd.attach` to crypttab entries on ostree systems to fix soft-reboot with LUKS ([#2219](https://github.com/coreos/ignition/pull/2219))
18+
1719

1820
## Ignition 2.26.0 (2026-02-17)
1921

internal/exec/stages/files/filesystemEntries.go

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,37 @@ import (
3333
"github.com/vincent-petithory/dataurl"
3434
)
3535

36+
// isOstreeSystem checks if the system is running ostree by checking for
37+
// the presence of /run/ostree-booted. This marker file is created by
38+
// ostree during boot. Also supports OSTREE_BOOTED=1 environment variable
39+
// for testing.
40+
func isOstreeSystem(ostreeBootedPath string) bool {
41+
if os.Getenv("OSTREE_BOOTED") == "1" {
42+
return true
43+
}
44+
_, err := os.Stat(ostreeBootedPath)
45+
return err == nil
46+
}
47+
48+
// buildCrypttabOptions constructs the options suffix for a crypttab entry.
49+
// It adds _netdev if network is needed and x-initrd.attach on ostree systems.
50+
// The x-initrd.attach option prevents systemd-cryptsetup-generator from adding
51+
// Conflicts=umount.target, which is necessary for soft-reboot to work correctly
52+
// on ostree systems where /sysroot is not the kernel root mount.
53+
func buildCrypttabOptions(hasNetworkDev, isOstree bool) string {
54+
var options []string
55+
if hasNetworkDev {
56+
options = append(options, "_netdev")
57+
}
58+
if isOstree {
59+
options = append(options, "x-initrd.attach")
60+
}
61+
if len(options) == 0 {
62+
return ""
63+
}
64+
return "," + strings.Join(options, ",")
65+
}
66+
3667
// createCrypttabEntries creates entries inside of /etc/crypttab for LUKS volumes,
3768
// as well as copying keyfiles to the sysroot.
3869
func (s *stage) createCrypttabEntries(config types.Config) error {
@@ -55,17 +86,19 @@ func (s *stage) createCrypttabEntries(config types.Config) error {
5586
Mode: cutil.IntToPtr(0600),
5687
},
5788
}
89+
90+
// Detect if we're on an ostree system
91+
// Check the host's /run directory, not the target sysroot
92+
isOstree := isOstreeSystem("/run/ostree-booted")
93+
5894
extrafiles := []filesystemEntry{}
5995
for _, luks := range config.Storage.Luks {
6096
out, err := exec.Command(distro.CryptsetupCmd(), "luksUUID", util.DeviceAlias(*luks.Device)).CombinedOutput()
6197
if err != nil {
6298
return fmt.Errorf("gathering luks uuid: %s: %v", out, err)
6399
}
64100
uuid := strings.TrimSpace(string(out))
65-
netdev := ""
66-
if len(luks.Clevis.Tang) > 0 || cutil.NotEmpty(luks.Clevis.Custom.Pin) && cutil.IsTrue(luks.Clevis.Custom.NeedsNetwork) {
67-
netdev = ",_netdev"
68-
}
101+
hasNetworkDev := len(luks.Clevis.Tang) > 0 || cutil.NotEmpty(luks.Clevis.Custom.Pin) && cutil.IsTrue(luks.Clevis.Custom.NeedsNetwork)
69102
keyfile := "none"
70103
if !luks.Clevis.IsPresent() {
71104
keyfile = filepath.Join(distro.LuksRealRootKeyFilePath(), luks.Name)
@@ -91,7 +124,8 @@ func (s *stage) createCrypttabEntries(config types.Config) error {
91124
},
92125
})
93126
}
94-
uri := dataurl.EncodeBytes([]byte(fmt.Sprintf("%s UUID=%s %s luks%s\n", luks.Name, uuid, keyfile, netdev)))
127+
options := buildCrypttabOptions(hasNetworkDev, isOstree)
128+
uri := dataurl.EncodeBytes([]byte(fmt.Sprintf("%s UUID=%s %s luks%s\n", luks.Name, uuid, keyfile, options)))
95129
crypttab.Append = append(crypttab.Append, types.Resource{
96130
Source: &uri,
97131
})

0 commit comments

Comments
 (0)