1. Overview and file inventory
The toolset automates the three-phase kernel update process described in the Kernel Update: Temporary PCR Relaxation & Re-enrollment guide. It replaces the manual slot management steps with a script that persists across reboots via a sentinel file and a systemd oneshot unit.
Files
| File | Install path | Purpose |
|---|---|---|
kernel-update-tpm.sh |
/usr/local/sbin/kernel-update-tpm.sh |
Main script. Runs Phase 1, 2, and 3. Called directly by user or by the APT hook. |
kernel-update-tpm-apt-hook |
/usr/local/sbin/kernel-update-tpm-apt-hook |
APT Pre-Install-Pkgs hook. Detects boot-sensitive packages and triggers Phase 1 automatically. |
90-kernel-update-tpm.conf |
/etc/apt/apt.conf.d/90-kernel-update-tpm.conf |
APT configuration that registers the hook with dpkg. |
Runtime artifacts (created automatically, not installed manually)
| Path | Purpose | Lifetime |
|---|---|---|
/var/lib/kernel-update-tpm/state |
Sentinel file tracking current phase, slot numbers, kernel version, timestamps. | Phase 1 → Phase 3. Removed on successful completion. |
/etc/systemd/system/kernel-update-tpm-resume.service |
Systemd oneshot unit that resumes the script after each reboot. | Phase 1 → Phase 3. Removed on successful completion. |
/etc/apt/apt.conf.d/99-kernel-update-tpm-reboot |
One-shot Post-Invoke drop-in that reboots after apt finishes (hook-mode only). |
Written at end of hook-mode Phase 1. Self-deletes on first execution. |
/var/log/kernel-update-tpm-apt-hook.log |
APT hook log. Records every transaction the hook evaluated, triggered or not. | Persistent. Rotate or inspect manually. |
Flow summary
| Phase | Trigger | Actions | Ends with |
|---|---|---|---|
| 1 | User runs script, or APT hook detects boot-sensitive package | Preflight checks → bind loose PCR-7 slot → test → remove strict slot → [apt upgrade + initramfs/grub if manual] → install systemd unit | Reboot |
| 2 | systemd unit fires on first post-update boot | Confirm new kernel → verify temp slot → re-enroll strict slot → test strict slot | Reboot |
| 3 | systemd unit fires on second post-update boot | Verify strict slot via full TPM cycle → remove temp slot → final report → remove unit and sentinel | Done — no reboot |
2. Prerequisites
The following must be true before installing. The script checks most of these at runtime but confirming them in advance avoids surprises.
| Requirement | How to confirm |
|---|---|
| Debian system with LUKS2 encrypted root, Secure Boot enabled | sudo cryptsetup luksDump /dev/nvme0n1p3 | grep Version → 2 |
| Exactly one Clevis TPM2 slot enrolled | sudo clevis luks list -d /dev/nvme0n1p3 → one tpm2 entry |
| At least one human passphrase slot enrolled | Confirmed by Phase 1 preflight automatically |
| TPM currently unseals (system auto-unlocked on last boot) | Confirmed by Phase 1 preflight automatically |
| Required commands available | clevis cryptsetup update-initramfs update-grub apt awk sort comm tpm2_pcrread systemctl lsblk |
| Perl-compatible regex support in grep | grep -P '' /dev/null && echo ok |
3. Installation
Option A — self-contained installer (recommended)
pcr-apt-update-install.sh
embeds all four scripts and deploys them in a single command:
sudo bash pcr-apt-update-install.sh
The installer writes, permissions, and verifies each file. Run it once; it is not needed afterward and can be discarded.
Option B — manual copy
sudo cp kernel-update-tpm.sh /usr/local/sbin/
sudo cp kernel-update-tpm-apt-hook /usr/local/sbin/
sudo cp update-clevis-pcrs.sh /usr/local/sbin/
sudo chmod 755 /usr/local/sbin/kernel-update-tpm.sh \
/usr/local/sbin/kernel-update-tpm-apt-hook \
/usr/local/sbin/update-clevis-pcrs.sh
sudo chown root:root /usr/local/sbin/kernel-update-tpm.sh \
/usr/local/sbin/kernel-update-tpm-apt-hook \
/usr/local/sbin/update-clevis-pcrs.sh
sudo cp 90-kernel-update-tpm.conf /etc/apt/apt.conf.d/
sudo chown root:root /etc/apt/apt.conf.d/90-kernel-update-tpm.conf
sudo chmod 644 /etc/apt/apt.conf.d/90-kernel-update-tpm.conf
/usr/local/sbin/ must be owned by root and not
world-writable. The APT hook runs as root during every apt transaction.
A writable hook script is a privilege escalation path.
Confirm file ownership and permissions
ls -l /usr/local/sbin/kernel-update-tpm.sh \
/usr/local/sbin/kernel-update-tpm-apt-hook \
/usr/local/sbin/update-clevis-pcrs.sh \
/etc/apt/apt.conf.d/90-kernel-update-tpm.conf
Expected: all owned root:root. Scripts mode -rwxr-xr-x (755). Config mode -rw-r--r-- (644).
4. Verifying the installation
Run these checks after installation and before any kernel update occurs.
4a. Confirm the hook is registered
apt-config dump | grep -i "kernel-update-tpm"
Expected output:
DPkg::Pre-Install-Pkgs:: "/usr/local/sbin/kernel-update-tpm-apt-hook";
DPkg::Tools::Options::/usr/local/sbin/kernel-update-tpm-apt-hook::Version "3";
4b. Dry-run the hook against a known-trigger package
Use apt-get --simulate to exercise the hook without installing anything.
The hook receives the package list on stdin and should log a trigger decision.
# This simulates an upgrade of linux-image — the hook fires but sees
# apt is in simulate mode and the script is not yet in a real transaction.
# Watch the log to confirm the hook ran and evaluated the package list.
sudo apt-get --simulate upgrade 2>&1 | grep -i "kernel-update-tpm" || true
sudo tail -20 /var/log/kernel-update-tpm-apt-hook.log
apt-get --simulate is not a completely inert operation with
this hook registered.
4c. Test auto-detection without running a real update
# Show usage and confirm the script is installed correctly (safe — reads nothing)
sudo /usr/local/sbin/kernel-update-tpm.sh --help
# Verify what LUKS block device will be detected
sudo blkid | grep crypto_LUKS
# Expected: the LUKS partition, e.g. /dev/nvme0n1p3: UUID="..." TYPE="crypto_LUKS"
# Verify which Clevis slot will be used as the strict PCR source
sudo clevis luks list -d /dev/nvme0n1p3 # substitute your device from blkid output above
# Expected: one tpm2 slot listing the strict PCR policy
4d. Confirm no sentinel exists from a previous run
ls /var/lib/kernel-update-tpm/state 2>/dev/null \
&& echo "WARNING: sentinel exists — a previous run may be in progress" \
|| echo "No sentinel — clean state"
4e. Confirm the systemd resume unit is not already present
systemctl status kernel-update-tpm-resume.service 2>&1 | head -5 || echo "Unit not present — expected"
5. Manual operation
Run the script directly when you want to trigger a kernel update and TPM re-enrollment on your own schedule, without waiting for an apt transaction to trigger the hook. This is also the path to use when the hook is not installed.
Basic usage — auto-detect everything
sudo /usr/local/sbin/kernel-update-tpm.sh
Explicit device and PCR policy
sudo /usr/local/sbin/kernel-update-tpm.sh /dev/nvme0n1p3 0,1,2,4,5,7,8,9
What to expect
Phase 1 output looks like this (exact slot numbers will differ):
[kernel-update-tpm] Auto-detected LUKS device: /dev/nvme0n1p3
[kernel-update-tpm] Auto-detected strict PCRs from existing binding: 0,1,2,4,5,7,8,9
[kernel-update-tpm] === Phase 1: preflight and kernel update ===
[kernel-update-tpm] Human passphrase slot confirmed: slot 0
[kernel-update-tpm] Detecting existing Clevis slot...
[kernel-update-tpm] Found Clevis slot: 1
[kernel-update-tpm] Verifying TPM unseal on slot 1...
[kernel-update-tpm] TPM unseal OK
[kernel-update-tpm] Stable PCR values before update (0,1,2,4,5,7):
sha256:
0 : ...
...
[kernel-update-tpm] Binding temporary loose slot (PCR 7)...
[kernel-update-tpm] Temporary slot created: 2
[kernel-update-tpm] Testing temporary slot 2...
[kernel-update-tpm] Temporary slot OK
[kernel-update-tpm] Removing strict slot 1...
[kernel-update-tpm] Strict slot 1 removed
[kernel-update-tpm] Running apt update && apt upgrade...
[kernel-update-tpm] Rebuilding initramfs...
[kernel-update-tpm] Updating GRUB...
[kernel-update-tpm] Phase 1 complete.
[kernel-update-tpm] Kernel: 6.1.0-30-amd64 — will update on next boot.
[kernel-update-tpm] Rebooting in 5 seconds — Ctrl-C to cancel
If no kernel update is available
If apt upgrade finds nothing to install, Phase 1 will still complete:
it will have swapped slots, rebuilt initramfs against the current kernel,
and scheduled the re-enrollment reboot. This is harmless — Phase 2 will detect
that the kernel version is unchanged and abort.
r to
re-enroll the strict slot against the current boot state and clean up immediately —
no reboot required. See
Recovery: Phase 2 kernel check.
6. APT hook operation
Once the hook is installed, kernel updates are handled automatically whenever
apt, apt-get, or aptitude installs or
upgrades a boot-sensitive package.
Trigger packages
The hook fires when any package name matches:
linux-image | linux-headers | linux-kbuild | linux-modules |
initramfs-tools | dracut | grub | shim | mokutil | fwupd |
firmware | microcode | amd64-microcode | intel-microcode |
clevis | cryptsetup | tpm2 | libtss2 | systemd
Typical automatic flow
# User runs a routine upgrade
sudo apt upgrade
# What happens behind the scenes:
# 1. apt evaluates the transaction
# 2. dpkg calls kernel-update-tpm-apt-hook with the package list on stdin
# 3. Hook detects linux-image-6.1.0-31-amd64 in the list
# 4. Hook calls kernel-update-tpm.sh --hook-mode
# 5. Phase 1 runs: preflight, slot swap, sentinel written, systemd unit installed
# 6. Hook exits 0; apt continues and installs packages normally
# 7. Package postinst scripts run update-initramfs and update-grub
# 8. After apt finishes, the Post-Invoke reboot drop-in fires
# 9. System reboots
# 10. Phase 2 runs automatically via systemd unit
# 11. System reboots again
# 12. Phase 3 runs automatically via systemd unit
# 13. Done — strict slot re-enrolled, temp slot removed
Terminal output during a hook-triggered run
Reading package lists... Done
...
kernel-update-tpm: boot-sensitive package(s) detected in this transaction:
linux-image-6.1.0-31-amd64
Preparing TPM Clevis slot transition before package installation...
(See /var/log/kernel-update-tpm-apt-hook.log for details)
kernel-update-tpm: Clevis slot transition prepared successfully.
The system will reboot automatically after apt completes.
Setting up linux-image-6.1.0-31-amd64 ...
update-initramfs: Generating /boot/initrd.img-6.1.0-31-amd64
...
Broadcast message: The system will reboot now!
Hook log
# Review all hook decisions — triggered and skipped
sudo cat /var/log/kernel-update-tpm-apt-hook.log
# Watch in real time during an apt run
sudo tail -f /var/log/kernel-update-tpm-apt-hook.log
Transactions that do NOT trigger the hook
Any apt transaction containing only non-boot-sensitive packages passes through
silently. The hook logs a SKIP: no boot-sensitive package detected
entry and exits 0 immediately.
# Example: installing curl does not trigger the hook
sudo apt install curl
# Hook log will show: SKIP: no boot-sensitive package detected
7. Monitoring a run in progress
Check current phase
sudo cat /var/lib/kernel-update-tpm/state
If the file does not exist, no run is in progress. If it exists, the
phase field shows where the process is: 2 means
waiting for the first post-update reboot, 3 means waiting for
the verification reboot.
Check systemd unit status
sudo systemctl status kernel-update-tpm-resume.service
The unit should show enabled when a run is in progress between
reboots. After Phase 3 completes it will show disabled and then
be removed entirely.
Follow Phase 2 or 3 in the journal
# Watch journal for the unit's output after a reboot
sudo journalctl -f -u kernel-update-tpm-resume.service
# Or review the completed run after the fact
sudo journalctl -u kernel-update-tpm-resume.service --no-pager
Confirm final Clevis state after Phase 3
export DEV=/dev/nvme0n1p3
sudo clevis luks list -d "$DEV"
# Expected: exactly one tpm2 entry with the strict PCR policy
sudo cryptsetup luksDump "$DEV" | sed -n '/Keyslots:/,/Tokens:/p'
# Expected: one passphrase slot (argon2id, no token) + one Clevis slot (pbkdf2, token 0)
8. The sentinel file
The sentinel at /var/lib/kernel-update-tpm/state is a plain
key=value file. Understanding it helps with monitoring and recovery.
Example sentinel after Phase 1
phase=2
luksdev=/dev/nvme0n1p3
strict_pcr_ids=0,1,2,4,5,7,8,9
created_at=2026-06-03T14:22:10+00:00
phase_started_at=2026-06-03T14:22:10+00:00
kernel_at_phase1=6.1.0-30-amd64
temp_slot=2
strict_slot_removed=1
Example sentinel after Phase 2
phase=3
luksdev=/dev/nvme0n1p3
strict_pcr_ids=0,1,2,4,5,7,8,9
created_at=2026-06-03T14:22:10+00:00
phase_started_at=2026-06-03T14:28:45+00:00
kernel_at_phase1=6.1.0-30-amd64
temp_slot=2
strict_slot_removed=1
new_strict_slot=3
Key fields
| Field | Meaning |
|---|---|
phase | Next phase to run. 2 = waiting for first reboot. 3 = waiting for verification reboot. |
temp_slot | The loose PCR-7 slot created in Phase 1. Still present until Phase 3 removes it. |
strict_slot_removed | The original strict slot that was removed in Phase 1. Informational only. |
new_strict_slot | The new strict slot created in Phase 2. Present after Phase 2 completes. |
kernel_at_phase1 | Kernel version at Phase 1. Phase 2 checks that the running kernel differs. |
phase_started_at | Timestamp updated at the start of each phase. Used for the age check. |
temp_slot value could cause the wrong slot to be removed.
9. Recovery procedures
First step for any failure: assess the state
# What phase are we in?
sudo cat /var/lib/kernel-update-tpm/state
# What Clevis slots currently exist?
sudo clevis luks list -d /dev/nvme0n1p3
# Is the systemd unit enabled?
sudo systemctl is-enabled kernel-update-tpm-resume.service 2>/dev/null || echo "not present"
# What does the journal show for the last unit run?
sudo journalctl -u kernel-update-tpm-resume.service -n 50 --no-pager
Phase 1 preflight failed: TPM unseal failed (PCRs changed)
The existing Clevis slot cannot unseal because PCR values have changed since the slot was created — for example, due to a hardware change, chassis intrusion detection event, firmware update, or a stale temp slot left by an interrupted prior run.
If you ran the script interactively, it offers a recovery prompt:
[r] Re-enroll from LUKS passphrase — bind a new slot to the current
PCR state, then remove the broken slot (no reboot required)
[q] Quit — inspect TPM and PCR state, then re-run
Press r. Clevis will prompt for your LUKS passphrase, bind a new slot sealed to the current PCR state, verify it unseals, and remove the broken slot. No reboot is required. If the script was triggered non-interactively (e.g. by the APT hook), it fails hard; run it manually to get the interactive prompt:
sudo /usr/local/sbin/kernel-update-tpm.sh /dev/nvme0n1p3
If you want to understand why PCRs changed, read the values with
tpm2_pcrread sha256:0,1,2,4,5,7,8,9 and compare against the
values logged by a prior Phase 1 run in the journal.
Phase 1 cancelled (Ctrl-C before reboot)
The slot swap has already happened: the strict slot is gone and the temp slot exists. The sentinel and systemd unit are written. The system has not rebooted — it is still running the old kernel. You can either reboot manually to continue, or abort cleanly.
Option A — Continue (reboot and let Phase 2 run)
sudo reboot
Option B — Abort and restore strict slot
The system has not rebooted, so the current boot state is unchanged and the strict PCR policy is still valid. This reads the slot numbers from the sentinel so you do not need to look them up manually.
export DEV=/dev/nvme0n1p3
TEMP_SLOT=$(sudo awk -F= '/^temp_slot/{print $2}' /var/lib/kernel-update-tpm/state)
STRICT_PCR_IDS=$(sudo awk -F= '/^strict_pcr_ids/{print $2}' /var/lib/kernel-update-tpm/state)
STRICT_POLICY="{\"pcr_bank\":\"sha256\",\"pcr_ids\":\"${STRICT_PCR_IDS}\"}"
# Re-enroll strict slot from the temp slot's passphrase
sudo clevis luks pass -d "$DEV" -s "$TEMP_SLOT" | \
sudo clevis luks bind -y -k - -d "$DEV" tpm2 "$STRICT_POLICY"
# Verify the new strict slot, then remove the temp slot
NEW_STRICT_SLOT=$(sudo clevis luks list -d "$DEV" | awk -F: '/tpm2/ {gsub(/^[ \t]+/,"",$1); print $1}' | sort -n | tail -1)
sudo clevis luks pass -d "$DEV" -s "$NEW_STRICT_SLOT" >/dev/null \
&& sudo clevis luks unbind -f -d "$DEV" -s "$TEMP_SLOT"
# Remove sentinel and unit
sudo systemctl disable kernel-update-tpm-resume.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/kernel-update-tpm-resume.service
sudo systemctl daemon-reload
sudo rm -f /var/lib/kernel-update-tpm/state
Phase 2 aborted: kernel version unchanged
Phase 2 detected that uname -r matches the kernel recorded in the
sentinel. The kernel update did not take effect. The temp slot is still present.
The systemd unit is now disabled (boot-loop guard fired).
Run the script manually — it will detect the unchanged kernel and offer a choice:
sudo /usr/local/sbin/kernel-update-tpm.sh
# You will see:
# [kernel-update-tpm] Kernel is still X.X.X — same as Phase 1.
# [kernel-update-tpm] The strict slot is gone; temp slot (PCR 7, slot N) is still active.
#
# [r] Restore strict slot from temp slot and clean up (recommended)
# [q] Quit — leave temp slot in place, fix /boot manually, then reboot
#
# Choice [r/q]:
Option r — Restore immediately (no kernel update needed)
Press r. The script re-enrolls the strict slot against the current
(unchanged) boot state using the temp slot as authorization, verifies it, removes
the temp slot, and cleans up the sentinel and unit. No reboot required.
Option q — Fix boot config and retry the update
Press q if a kernel update really should have installed but did not.
Investigate, fix, then retry:
# Investigate why the new kernel did not boot
ls -lh /boot/vmlinuz-* /boot/initrd.img-*
sudo update-grub
sudo grep menuentry /boot/grub/grub.cfg | head -10
# If the new kernel is present but not the default, correct it, then re-enable the unit
sudo systemctl enable kernel-update-tpm-resume.service
# Reset the phase_started_at timestamp so the age check passes
sudo sed -i "s|^phase_started_at=.*|phase_started_at=$(date --iso-8601=seconds)|" \
/var/lib/kernel-update-tpm/state
sudo reboot
Phase 2 aborted: temp slot failed to unseal
The PCR-7 binding did not unseal in the new boot state. This is unexpected — PCR 7 should not change during a kernel update. A simultaneous MOK enrollment or Secure Boot key change is the likely cause. The strict slot is already gone. Unlock using the human LUKS passphrase.
# Unlock manually if required, then investigate PCR 7
sudo tpm2_pcrread sha256:7
# Read back what PCR 7 was when the temp slot was bound
# (it was sealed against the value at Phase 1 time — if MOK changed, it shifted)
sudo journalctl -u kernel-update-tpm-resume.service --no-pager | grep -i "pcr\|fail\|slot"
# If you need to re-enroll everything from scratch using the human passphrase:
export DEV=/dev/nvme0n1p3
STRICT_PCR_IDS=$(sudo awk -F= '/^strict_pcr_ids/{print $2}' /var/lib/kernel-update-tpm/state)
STRICT_POLICY="{\"pcr_bank\":\"sha256\",\"pcr_ids\":\"${STRICT_PCR_IDS}\"}"
TEMP_SLOT=$(sudo awk -F= '/^temp_slot/{print $2}' /var/lib/kernel-update-tpm/state)
# Enroll new strict slot using passphrase
sudo clevis luks bind -y -d "$DEV" tpm2 "$STRICT_POLICY"
# Remove the failed temp slot using the new strict slot
NEW_SLOT=$(sudo clevis luks list -d "$DEV" | awk -F: '/tpm2/{gsub(/^[ \t]+/,"",$1); print $1}' | sort -n | tail -1)
sudo clevis luks pass -d "$DEV" -s "$NEW_SLOT" | \
sudo clevis luks unbind -d "$DEV" -s "$TEMP_SLOT"
# Clean up sentinel and unit
sudo systemctl disable kernel-update-tpm-resume.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/kernel-update-tpm-resume.service
sudo systemctl daemon-reload
sudo rm -f /var/lib/kernel-update-tpm/state
Phase 3 aborted: new strict slot failed verification
The strict slot created in Phase 2 did not unseal on the Phase 3 boot. The temp slot is still present. The systemd unit is disabled. The PCR state has shifted again between Phase 2 and Phase 3 — this should not happen on a normal boot with no changes, so investigate carefully.
# Read current PCR values
sudo tpm2_pcrread sha256:0,1,2,4,5,7,8,9
# Check what policy the new strict slot was bound to
sudo clevis luks list -d /dev/nvme0n1p3
# The temp slot (PCR 7) is still working. Use it to re-enroll strict.
export DEV=/dev/nvme0n1p3
TEMP_SLOT=$(sudo awk -F= '/^temp_slot/{print $2}' /var/lib/kernel-update-tpm/state)
NEW_STRICT_SLOT=$(sudo awk -F= '/^new_strict_slot/{print $2}' /var/lib/kernel-update-tpm/state)
STRICT_PCR_IDS=$(sudo awk -F= '/^strict_pcr_ids/{print $2}' /var/lib/kernel-update-tpm/state)
STRICT_POLICY="{\"pcr_bank\":\"sha256\",\"pcr_ids\":\"${STRICT_PCR_IDS}\"}"
# Remove the stale strict slot from Phase 2
sudo clevis luks pass -d "$DEV" -s "$TEMP_SLOT" | \
sudo clevis luks unbind -d "$DEV" -s "$NEW_STRICT_SLOT"
# Re-enroll strict against the current (Phase 3) boot state
sudo clevis luks pass -d "$DEV" -s "$TEMP_SLOT" | \
sudo clevis luks bind -y -k - -d "$DEV" tpm2 "$STRICT_POLICY"
# Verify the new enrollment
FINAL_SLOT=$(sudo clevis luks list -d "$DEV" | awk -F: '/tpm2/{gsub(/^[ \t]+/,"",$1); print $1}' | sort -n | tail -1)
sudo clevis luks pass -d "$DEV" -s "$FINAL_SLOT" >/dev/null \
&& echo "New strict slot OK"
# Remove temp slot and clean up
sudo clevis luks pass -d "$DEV" -s "$FINAL_SLOT" | \
sudo clevis luks unbind -d "$DEV" -s "$TEMP_SLOT"
sudo rm -f /etc/systemd/system/kernel-update-tpm-resume.service
sudo systemctl daemon-reload
sudo rm -f /var/lib/kernel-update-tpm/state
Age check expired
If the system was shut down (not rebooted) between phases, or if the unit ran
more than 30 minutes after boot, the age check fires. When running interactively,
the script offers a prompt — press c to reset the timer and continue,
or q to abort:
sudo /usr/local/sbin/kernel-update-tpm.sh
# [kernel-update-tpm] Sentinel is 37 minutes old (max 30) — Phase 2 did not run promptly after reboot.
#
# [c] Reset the age timer and continue Phase 2 now
# [q] Quit and inspect /var/lib/kernel-update-tpm/state manually
#
# Choice [c/q]: c
If the unit fired non-interactively (systemd) and hard-aborted, reset manually and re-enable:
sudo sed -i "s|^phase_started_at=.*|phase_started_at=$(date --iso-8601=seconds)|" \
/var/lib/kernel-update-tpm/state
sudo systemctl enable kernel-update-tpm-resume.service
sudo reboot
10. Uninstalling
ls /var/lib/kernel-update-tpm/state.
If one exists, complete or abort the current run before uninstalling.
# Remove APT hook configuration (disables automatic triggering)
sudo rm -f /etc/apt/apt.conf.d/90-kernel-update-tpm.conf
# Remove scripts
sudo rm -f /usr/local/sbin/kernel-update-tpm.sh
sudo rm -f /usr/local/sbin/kernel-update-tpm-apt-hook
# Remove any leftover runtime artifacts
sudo systemctl disable kernel-update-tpm-resume.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/kernel-update-tpm-resume.service
sudo systemctl daemon-reload
sudo rm -rf /var/lib/kernel-update-tpm/
sudo rm -f /etc/apt/apt.conf.d/99-kernel-update-tpm-reboot
# Logs are left in place for audit purposes — remove manually if desired
# sudo rm -f /var/log/kernel-update-tpm-apt-hook.log
Uninstalling does not affect the current Clevis enrollment. Whatever slots exist at uninstall time remain.
11. Quick reference
Key paths
| Path | Purpose |
|---|---|
/usr/local/sbin/kernel-update-tpm.sh | Main script (Phases 1–3) |
/usr/local/sbin/kernel-update-tpm-apt-hook | APT hook |
/usr/local/sbin/update-clevis-pcrs.sh | Lower-level helper for manual slot management |
/etc/apt/apt.conf.d/90-kernel-update-tpm.conf | Hook registration |
/var/lib/kernel-update-tpm/state | Sentinel file |
/etc/systemd/system/kernel-update-tpm-resume.service | Resume unit (runtime) |
/var/log/kernel-update-tpm-apt-hook.log | Hook log |
Common commands
| Task | Command |
|---|---|
| Show help / usage | sudo /usr/local/sbin/kernel-update-tpm.sh --help |
| Run manually | sudo /usr/local/sbin/kernel-update-tpm.sh |
| Check current phase | sudo cat /var/lib/kernel-update-tpm/state |
| Watch Phase 2/3 journal | sudo journalctl -f -u kernel-update-tpm-resume.service |
| Check hook log | sudo tail -f /var/log/kernel-update-tpm-apt-hook.log |
| Confirm hook registered | apt-config dump | grep kernel-update-tpm |
| Check Clevis slots | sudo clevis luks list -d /dev/nvme0n1p3 |
| Reset age check | sudo sed -i "s|^phase_started_at=.*|phase_started_at=$(date --iso-8601=seconds)|" /var/lib/kernel-update-tpm/state |