Skip to content

Commit 286aed7

Browse files
committed
Migrate tpm cleanup method from kcrypt-challenger
because local passphrase logic is now removed from kcrypt-challenger Signed-off-by: Dimitris Karakasilis <[email protected]>
1 parent 0653a1b commit 286aed7

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

main.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,58 @@ The output will be a tarball with logs organized by type (journal/, files/).`,
12281228
return agent.ExecuteLogsCommand(cfg.Fs, cfg.Logger, cfg.Runner, outputPath)
12291229
},
12301230
},
1231+
{
1232+
Name: "kcrypt",
1233+
Usage: "kcrypt subcommands",
1234+
Description: "kcrypt subcommands for managing encryption-related operations",
1235+
Subcommands: []*cli.Command{
1236+
{
1237+
Name: "cleanup",
1238+
Usage: "Clean up TPM NV memory",
1239+
Description: `Clean up TPM NV memory by undefining specific NV indices.
1240+
1241+
?? DANGER: This command removes data from TPM memory!
1242+
?? If you delete the wrong index, your encrypted disk may become UNBOOTABLE!
1243+
1244+
This command helps clean up TPM NV memory. It can be used to clean up
1245+
legacy local passphrase storage (now handled by kairos-sdk) or any other
1246+
TPM NV indices that need to be removed.
1247+
1248+
The command will prompt for confirmation before deletion unless you use
1249+
the --i-know-what-i-am-doing flag to skip the safety prompt.
1250+
1251+
Default behavior:
1252+
- Uses NV index from config or defaults to 0x1500000 (legacy local passphrase index)
1253+
- Uses the same TPM device as configured (or system default if none specified)
1254+
- Prompts for confirmation with safety warnings`,
1255+
Flags: []cli.Flag{
1256+
&cli.StringFlag{
1257+
Name: "nv-index",
1258+
Value: "0x1500000",
1259+
Usage: "NV index to clean up (defaults to configured index or 0x1500000)",
1260+
},
1261+
&cli.StringFlag{
1262+
Name: "tpm-device",
1263+
Usage: "TPM device path (defaults to configured device or system default)",
1264+
},
1265+
&cli.BoolFlag{
1266+
Name: "i-know-what-i-am-doing",
1267+
Usage: "Skip confirmation prompt (DANGEROUS: may make encrypted disks unbootable)",
1268+
},
1269+
},
1270+
Before: func(c *cli.Context) error {
1271+
return checkRoot()
1272+
},
1273+
Action: func(c *cli.Context) error {
1274+
cfg, err := agentConfig.Scan(collector.Directories(constants.GetUserConfigDirs()...), collector.NoLogs)
1275+
if err != nil {
1276+
return fmt.Errorf("failed to scan config: %w", err)
1277+
}
1278+
return action.KcryptCleanup(cfg, c.String("nv-index"), c.String("tpm-device"), c.Bool("i-know-what-i-am-doing"))
1279+
},
1280+
},
1281+
},
1282+
},
12311283
}
12321284

12331285
func main() {

pkg/action/kcrypt_cleanup.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package action
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"strings"
8+
9+
"github.com/kairos-io/kairos-agent/v2/pkg/config"
10+
"github.com/kairos-io/tpm-helpers"
11+
)
12+
13+
// KcryptCleanup cleans up TPM NV memory by undefining specific NV indices.
14+
// This is used to clean up legacy local passphrase storage (now handled by kairos-sdk)
15+
// or any other TPM NV indices that need to be removed.
16+
func KcryptCleanup(cfg *config.Config, nvIndex, tpmDevice string, skipConfirmation bool) error {
17+
logger := cfg.Logger
18+
19+
// Get kcrypt config from the embedded collector.Config
20+
var challengerNVIndex, challengerTPMDevice string
21+
if kcryptConfig, ok := cfg.Config.Values["kcrypt"].(map[string]interface{}); ok {
22+
if nvIdx, ok := kcryptConfig["nv_index"].(string); ok && nvIdx != "" {
23+
challengerNVIndex = nvIdx
24+
}
25+
if tpmDev, ok := kcryptConfig["tpm_device"].(string); ok && tpmDev != "" {
26+
challengerTPMDevice = tpmDev
27+
}
28+
}
29+
30+
// Determine NV index to clean up
31+
// Priority: explicit flag > config > default
32+
targetIndex := nvIndex
33+
if targetIndex == "" || targetIndex == "0x1500000" {
34+
// If flag is empty or default, check config first
35+
if challengerNVIndex != "" {
36+
targetIndex = challengerNVIndex
37+
} else if targetIndex == "" {
38+
// Only use default if flag was truly empty (not just default value)
39+
targetIndex = "0x1500000" // Legacy local passphrase NV index (for backward compatibility)
40+
}
41+
}
42+
43+
// Determine TPM device
44+
targetDevice := tpmDevice
45+
if targetDevice == "" {
46+
targetDevice = challengerTPMDevice
47+
}
48+
49+
logger.Debugf("Cleaning up TPM NV index: %s", targetIndex)
50+
if targetDevice != "" {
51+
logger.Debugf("Using TPM device: %s", targetDevice)
52+
}
53+
54+
// Check if the NV index exists first
55+
opts := []tpm.TPMOption{tpm.WithIndex(targetIndex)}
56+
if targetDevice != "" {
57+
opts = append(opts, tpm.WithDevice(targetDevice))
58+
}
59+
60+
// Try to read from the index to see if it exists
61+
logger.Debugf("Checking if NV index %s exists", targetIndex)
62+
_, err := tpm.ReadBlob(opts...)
63+
if err != nil {
64+
// If we can't read it, it might not exist or be empty
65+
logger.Debugf("NV index %s appears to be empty or non-existent: %v", targetIndex, err)
66+
fmt.Printf("NV index %s appears to be empty or does not exist\n", targetIndex)
67+
return nil
68+
}
69+
70+
// Confirmation prompt with warning
71+
if !skipConfirmation {
72+
fmt.Printf("\n?? WARNING: You are about to delete TPM NV index %s\n", targetIndex)
73+
fmt.Printf("?? If this index contains your disk encryption passphrase, your encrypted disk will become UNBOOTABLE!\n")
74+
fmt.Printf("?? This action CANNOT be undone.\n\n")
75+
fmt.Printf("Are you sure you want to continue? (type 'yes' to confirm): ")
76+
77+
scanner := bufio.NewScanner(os.Stdin)
78+
scanner.Scan()
79+
response := strings.TrimSpace(strings.ToLower(scanner.Text()))
80+
81+
if response != "yes" {
82+
fmt.Printf("Cleanup cancelled.\n")
83+
return nil
84+
}
85+
}
86+
87+
// Use native Go TPM library to undefine the NV space
88+
logger.Debugf("Using native TPM library to undefine NV index")
89+
fmt.Printf("Cleaning up TPM NV index %s...\n", targetIndex)
90+
91+
err = tpm.UndefineBlob(opts...)
92+
if err != nil {
93+
return fmt.Errorf("failed to undefine NV index %s: %w", targetIndex, err)
94+
}
95+
96+
fmt.Printf("Successfully cleaned up NV index %s\n", targetIndex)
97+
logger.Debugf("Successfully undefined NV index %s", targetIndex)
98+
return nil
99+
}

0 commit comments

Comments
 (0)