Measured boot needs a TPM2 Storage Root Key, and systemd-tpm2-setup is the quiet service meant to generate one first. This guide gives you a safe way to inspect that setup, tell whether the services were allowed to run, and check the public-key files they are meant to leave behind. The examples match systemd 255.4-1ubuntu8.17 on this machine, from Ubuntu's systemd 255 package.
Allow about fifteen minutes. You need a shell and permission to read systemd's unit state. Most checks are ordinary commands. Starting either service or running the helper directly can create TPM state, so this guide treats that as an explicit administrative action, not a casual test.
Begin with the installed binary and its help output. This is read-only and does not need elevated privileges:
$ command -v systemd-tpm2-setup
/usr/lib/systemd/systemd-tpm2-setup
$ systemd-tpm2-setup --help
systemd-tpm2-setup [OPTIONS...]
Set up the TPM2 Storage Root Key (SRK).
Options:
-h --help Show this help
--version Show package version
--tpm2-device=PATH
Pick TPM2 device
--early=BOOL Store SRK public key in /run/ rather than /var/lib/
Do not infer that --help is a dry-run switch. The helper is the service's executable; its normal job is to generate the SRK when it has not been generated yet and store it in the TPM.
Checkpoint: record the package version as well as the systemd version if you are documenting a host:
$ systemd-tpm2-setup --version
systemd 255 (255.4-1ubuntu8.17)
$ dpkg-query -W -f='${Package} ${Version}\n' systemd
systemd 255.4-1ubuntu8.17
systemd-tpm2-setup-early.service can run in the initrd, before /var is normally available, and writes the public key under /run/systemd/.systemd-tpm2-setup.service runs later and writes the persistent copy under /var/lib/systemd/.Both services are oneshot units that remain marked active after a successful run. They are static units, so there is no enablement step to perform. Their installed unit files also require the measured-uki security condition, so on this system they are skipped when that condition is not met.
The file names are easy to mix up. The early stage uses:
/run/systemd/tpm2-srk-public-key.pem
/run/systemd/tpm2-srk-public-key.tpm2b_public
The later stage uses:
/var/lib/systemd/tpm2-srk-public-key.pem
/var/lib/systemd/tpm2-srk-public-key.tpm2_public
These are public-key representations, not the SRK private material. Do not treat either directory as a place to copy, edit or replace TPM objects by hand.
Read the unit definitions and current status first. These commands do not start, stop or reload a service:
$ systemctl cat systemd-tpm2-setup.service systemd-tpm2-setup-early.service
$ systemctl --no-pager --full status systemd-tpm2-setup.service systemd-tpm2-setup-early.service
Look for three useful facts: the unit is loaded, its ExecStart path, and any line beginning with Condition:. A condition such as start condition unmet is a deliberate skip, not necessarily a failure in TPM access.
Checkpoint: ask systemd to report the condition-related properties directly:
$ systemctl show systemd-tpm2-setup.service \
-p LoadState -p ActiveState -p SubState -p ConditionResult -p Conditions
$ systemctl show systemd-tpm2-setup-early.service \
-p LoadState -p ActiveState -p SubState -p ConditionResult -p Conditions
Warning: on a machine without the required measured-UKI environment, ConditionResult=no is the key result. Do not try to bypass it by adding arbitrary unit overrides: that changes a boot security boundary and can make the host's measured-boot assumptions false.
Inspect both locations with ordinary read-only commands:
$ for f in \
/run/systemd/tpm2-srk-public-key.pem \
/run/systemd/tpm2-srk-public-key.tpm2b_public \
/var/lib/systemd/tpm2-srk-public-key.pem \
/var/lib/systemd/tpm2-srk-public-key.tpm2_public; do
if test -s "$f"; then
stat -c '%n %s bytes' "$f"
else
printf 'missing or empty: %s\n' "$f"
fi
done
A present, non-empty PEM file should start with a public-key PEM marker. Check it without printing the whole file:
$ sed -n '1p' /var/lib/systemd/tpm2-srk-public-key.pem
-----BEGIN PUBLIC KEY-----
The exact byte sizes vary with the TPM and systemd build. The /run files are temporary and normally disappear at reboot; the /var/lib files are the later, persistent copies. An absent file is meaningful only alongside the unit status and boot environment. Do not create an empty placeholder to make a check pass.
In normal operation, let the boot transaction invoke these services. A manual start is an elevated, state-changing operation: it may generate an SRK and write TPM-related output. Before using it, confirm the host is intended to use measured UKIs, that the TPM is available, and that you have a maintenance window:
$ sudo systemctl start systemd-tpm2-setup-early.service
$ sudo systemctl start systemd-tpm2-setup.service
Do not run these commands merely because the files are absent. On a host where the measured-UKI condition is false, systemd should skip the units. If you deliberately start a unit and it fails, capture the result before changing anything:
$ systemctl --no-pager --full status systemd-tpm2-setup-early.service systemd-tpm2-setup.service
$ journalctl -b -u systemd-tpm2-setup-early.service -u systemd-tpm2-setup.service --no-pager
Destructive action: do not clear the TPM, delete the public-key files, or replace the unit with a hand-written command as a recovery attempt. TPM clearing is destructive and can make sealed data or measured-boot workflows unusable. If a real boot integration is broken, preserve the journal and investigate the image, TPM device selection and measured-UKI deployment with the platform owner.
The installed helper accepts --tpm2-device=PATH when a deployment must select a particular TPM device. The service units do not set this option in their default ExecStart. Do not guess a device path or add an override just to silence an error; a wrong TPM can produce a key that is unavailable to the software expecting another device.
The --early=yes form is used by the early unit to select /run, while the normal service omits it and writes to /var/lib. Keep those roles separate. If you need to test a custom device selection, review the resulting unit drop-in and its rollback path first, then remove only that drop-in with your normal systemd configuration process after the test.
/run output apart from the later /var/lib output.