Skip to content

Add dynamic PCR policy support for disk key sealing#5398

Merged
eriknordmark merged 3 commits intolf-edge:masterfrom
shjala:pcr.dynamic
Feb 3, 2026
Merged

Add dynamic PCR policy support for disk key sealing#5398
eriknordmark merged 3 commits intolf-edge:masterfrom
shjala:pcr.dynamic

Conversation

@shjala
Copy link
Member

@shjala shjala commented Nov 12, 2025

Description

This commit introduces the ability to dynamically update the PCR policy used for sealing the disk encryption key, allowing the controller to define which PCRs are used for sealing.

Key changes:

  • evetpm: Added functionality to persist and validate PCR policy
    configuration in policy-pcr.json, plus recovring policy in case
    of configuration corruption.
  • vaultmgr: Updated key handling logic to detect policy changes from the
    controller, persist the new policy, and trigger a reseal of
    the disk encryption key.
  • zedagent: Added extraction of PCR policy information from
    AttestStorageKeys protobuf messages to pass to vaultmgr.
  • types: Introduced VaultKeyPolicyPCR struct and PolicyPcrFile constant
    to support policy propagation.
  • tests: Added unit tests for policy digest computation and validation.

PR dependencies

lf-edge/eve-api#125

How to test and validate this PR

Automated Tests

  • New unit tests TestSaveDiskKeySealingPCRsValidPolicy, TestSaveDiskKeySealingPCRsInvalidPolicy, TestSaveDiskKeySealingPCRsPolicyUnchanged, TestGetDiskKeySealingPCRsFromFile, and TestGetDiskKeySealingPCRsCorruptedFile have been added to pkg/pillar/evetpm/tpm_test.go to verify the policy validation, saving, and loading logic.

Manual Verification

To validate the full end-to-end flow with a controller:

  1. Preparation:

    • Build an EVE image with these changes and onboard a device (TPM required).
    • Ensure the device has successfully sealed the volume using the default PCR set.
  2. Controller Integration (Dynamic Policy Update):

    • Trigger a configuration update from the controller that includes a EncryptedVaultKey message with a new PCR policy (e.g., adding or removing a valid PCR index like PCR 4 or 6).
    • Verify in the device logs (logread | grep vaultmgr) that:
      • The new policy is received ([ATTEST] received Controller-given encrypted key with Policy PCR version).
      • vaultmgr detects the policy change (Policy Changed: true)
      • vaultmgr validates the new policy and accepts it (Policy Changed: true)
      • The disk key is re-sealed (Re-sealed disk key in TPM).
    • Reboot the device.
    • Verify that the device successfully unlocks the vault and boots up using the new PCR policy.
  3. Controller Integration (Invalid Policy):

    • Send an update with an invalid policy (e.g., including PCR 5, or an index > 15).
    • Verify in logs that vaultmgr rejects the policy with an error and does not update the sealing policy (Failed to save controller provided Policy).
  4. No-Op Update:

    • Send an update with the same policy as currently applied.
    • Verify in logs that vaultmgr detects no change and skips the re-sealing process ( content of persist/status/policy-pcr.json should not change, same for policy-pcr-digest in the same directory)

Changelog notes

Added support for dynamic configuration of TPM PCR policies for disk encryption. The device can now receive updated sealing policies from the controller, allowing for more flexible security configurations without requiring a full system update.

PR Backports

  • 16.0-stable
  • 14.5-stable
  • 13.4-stable

Checklist

  • I've provided a proper description
  • I've added the proper documentation
  • I've tested my PR on amd64 device
  • I've tested my PR on arm64 device
  • I've written the test verification instructions
  • I've set the proper labels to this PR

For backport PRs (remove it if it's not a backport):

  • I've added a reference link to the original PR
  • PR's title follows the template

And the last but not least:

  • I've checked the boxes above, or I've provided a good reason why I didn't
    check them.

Please, check the boxes above after submitting the PR in interactive mode.

@codecov
Copy link

codecov bot commented Nov 12, 2025

Codecov Report

❌ Patch coverage is 45.23810% with 92 lines in your changes missing coverage. Please review.
✅ Project coverage is 29.49%. Comparing base (2281599) to head (2afb691).
⚠️ Report is 264 commits behind head on master.

Files with missing lines Patch % Lines
pkg/pillar/evetpm/tpm.go 45.23% 82 Missing and 10 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5398      +/-   ##
==========================================
+ Coverage   19.52%   29.49%   +9.96%     
==========================================
  Files          19       18       -1     
  Lines        3021     2417     -604     
==========================================
+ Hits          590      713     +123     
+ Misses       2310     1552     -758     
- Partials      121      152      +31     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@eriknordmark eriknordmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yetus issues to fix

@github-actions github-actions bot requested a review from eriknordmark January 20, 2026 14:25
@shjala shjala changed the title [WIP] Add dynamic PCR policy support for disk key sealing Add dynamic PCR policy support for disk key sealing Jan 20, 2026
@shjala shjala added enhancement New feature or request stable Should be backported to stable release(s) labels Jan 20, 2026
@shjala shjala self-assigned this Jan 20, 2026
Copy link
Contributor

@eriknordmark eriknordmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kick off tests

@eriknordmark
Copy link
Contributor

@shjala a number of eden tests fail even after re-running.
I've seen TestEdenScripts/metadata fail consistently which is interesting because

  • this is not a test which I've seen fail intermittently before
  • tests cloud-init hence relies on the object encryption thus has some relationship to the changes in this PR

@shjala
Copy link
Member Author

shjala commented Jan 28, 2026

@eriknordmark made some changes, please review (in the meantime I'll debug the eden).

Copy link
Contributor

@eriknordmark eriknordmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Run tests

@eriknordmark
Copy link
Contributor

Something is broken in this PR.
I tried onboarding with Qemu and a TPM by running
make -e TPM=y ACCEL=y QEMU_MEMORY=16384 MEDIA_SIZE=65536 SSH_PORT=2345 installer-raw run-installer-raw
make -e TPM=y ACCEL=y QEMU_MEMORY=16384 MEDIA_SIZE=65536 SSH_PORT=2345 run-target
(needs to be split across two commands since swtpm seems to exit when the installer powers off the VM)

Once the device has been onboarded to the controller I see this error

INFO: updated diag information at 2026-01-29T18:18:03.569550018Z due to Network
ERROR: device: maintenance_mode attest: InternalEscrowWait error [ATTEST] No escrow data vault: ERROR error [ERROR] fscrypt status: file or directory "/persist/vault" is not encrypted
pcr: ENABLED
INFO: applications: 0 starting, 0 running
INFO: Summary: Connected to EV Controller and onboarded

So this causes some ordering issue for bringing up the vault.

@github-actions github-actions bot requested a review from eriknordmark February 3, 2026 12:46
@shjala shjala force-pushed the pcr.dynamic branch 2 times, most recently from c0d339b to ed9799d Compare February 3, 2026 13:52
Update eve-api to include the latest changes that
support dynamic PCRs

Signed-off-by: Shahriyar Jalayeri <shahriyar@posteo.de>
@shjala
Copy link
Member Author

shjala commented Feb 3, 2026

@eriknordmark made some changes, local run of Eden networking and upgrade tests all passed, smoke test all pass except TestEdenScripts/userdata, virtualization tests fails at TestEdenScripts/app_nonat (both fail with command ssh failed: exit status 1). I think this due to some network misconfiguration, because I can ssh to EVE and it is onboarded, but ping fails:

b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# cat /run/diag.out 

INFO: updated diag information at 2026-02-03T15:24:42.976220828Z due to Appinstance
INFO: device: online attest: Complete vault: ENABLED pcr: ENABLED
INFO: applications: 0 starting, 1 running
INFO: Summary: Connected to EV Controller and onboarded
INFO: Using highest priority DevicePortConfig key zedagent
INFO: Have 3 total ports. 1 ports should be connected to EV controller
INFO: Port eth0: Mac: 02:fe:24:97:b1:67 link: up use: mgmt 192.168.0.10
INFO: Port eth1: Mac: 02:fe:b7:98:b1:68 link: up use: app-shared 192.168.0.11
INFO: Port eth2: link: down use: app-shared No IP address
INFO: App eclient uuid be34d456-c33f-477b-8d7c-e6c42b222831 state RUNNING
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# pping -c 4 google.com
-ash: pping: not found
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# ping -c 4 google.com
PING google.com (142.250.201.174): 56 data bytes

--- google.com ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# 

Apps are running too,

b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# eve list-app-consoles
PID     APP-UUID                                CONS-TYPE       CONS-ID
---     --------                                ---------       ---------
5746    be34d456-c33f-477b-8d7c-e6c42b222831    CONTAINER       be34d456-c33f-477b-8d7c-e6c42b222831.1.1/cons
5746    be34d456-c33f-477b-8d7c-e6c42b222831    VM              be34d456-c33f-477b-8d7c-e6c42b222831.1.1/shim-cons
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# eve attach-app-console be34d456-c33f-477b-8d7c-e6c42b222831.1.1/shim-cons
[15:41:50.607] tio v1.37
[15:41:50.607] Press ctrl-t q to quit
[15:41:50.607] Connected

root@shim ~# 
root@shim ~# 
root@shim ~# 
root@shim ~# 
root@shim ~# 
[15:41:59.323] Disconnected
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# 
b0cc8f38-ebb8-4b73-a15c-40ffa67fb174:~# eve attach-app-console be34d456-c33f-477b-8d7c-e6c42b222831.1.1/cons
[15:42:13.228] tio v1.37
[15:42:13.228] Press ctrl-t q to quit
[15:42:13.228] Connected

/ # 
/ # 

Copy link
Contributor

@eriknordmark eriknordmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll run this on some physical test device today.

@eriknordmark
Copy link
Contributor

Two yetus things to fix:
yetus: pkg/pillar/evetpm/tpm.go#L481
codespell: requirments ==> requirements
yetus: pkg/pillar/evetpm/tpm.go#L1268
revive: comment on exported function UnsealDiskKeyWithRecovery should be of the form "UnsealDiskKeyWithRecovery ..." https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported

Also, is there some comment syntax to tell revive to not complain about the TPM_CC_ name?

@shjala
Copy link
Member Author

shjala commented Feb 3, 2026

Also, is there some comment syntax to tell revive to not complain about the TPM_CC_ name?

Seems adding revive:disable-line:var-naming worked!

This commit introduces the ability to dynamically update the PCR policy
used for sealing the disk encryption key, allowing the controller to
define which PCRs are used for sealing.

Key changes:
evetpm: Added functionality to persist and validate PCR policy
  configuration in policy-pcr.json, plus recovring policy in case
  of configuration corruption.
vaultmgr: Updated key handling logic to detect policy changes from the
  controller, persist the new policy, and trigger a reseal of
  the disk encryption key.
zedagent: Added extraction of PCR policy information from
  AttestStorageKeys protobuf messages to pass to vaultmgr.
types: Introduced VaultKeyPolicyPCR struct and PolicyPcrFile constant
  to support policy propagation.
tests: Added unit tests for policy digest computation and validation.

Signed-off-by: Shahriyar Jalayeri <shahriyar@posteo.de>
Update docs/SECURITY-ARCHITECTURE.md to include a new section
that briefly explains  the concept of dynamic PRC policy.

Signed-off-by: Shahriyar Jalayeri <shahriyar@posteo.de>

lockFile, err := fileutils.AcquireLock(policyPath, true)
if err != nil {
// xxx : should we fatal here?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it try again to save the policyPCR if you return an error?

@eriknordmark eriknordmark merged commit b6b4116 into lf-edge:master Feb 3, 2026
48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request stable Should be backported to stable release(s)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants