GitHub - OperatorProject/extctl: Super-simple systemd-sysext wrapper · GitHub
/" data-turbo-transient="true" />
Skip to content
Search/
Sign in<br>Sign upAppearance settings
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
Uh oh!
There was an error while loading. Please reload this page.
OperatorProject
extctl
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Latest commit
History<br>1 Commit<br>1 Commit
Folders and files<br>NameNameLast commit message<br>Last commit date<br>app
app
.gitignore
.gitignore
LICENSE
LICENSE
README.md
README.md
build-rpm
build-rpm
extctl.spec
extctl.spec
View all files
Repository files navigation
extctl
extctl is a super simple systemd-sysext wrapper for signing and<br>installing system extensions on a running Linux machine. It wraps the raw<br>veritysetup / openssl / install / refresh incantations into a<br>single command with a docker-like feel.
extctl is a super simple systemd-sysext wrapper. It runs on any distro<br>with systemd-sysext, veritysetup, openssl, and mkfs.erofs, and is<br>not tied to any particular distribution.
Quick start
The whole lifecycle, exactly as you would type it:
mytool.raw<br>$ extctl sign mytool.raw # sign (uses the keygen'd key)<br>$ sudo extctl install mytool.raw # verify + copy + merge<br>$ extctl ls # see it installed + merged<br>$ sudo extctl remove mytool # tear it back down">$ sudo extctl keygen # one-time setup; like `docker login`<br>$ extctl init mytool # scaffold ./mytool/ + manifest<br>$ $EDITOR mytool/usr/bin/* # drop your tool in<br>$ extctl build mytool # package -> mytool.raw<br>$ extctl sign mytool.raw # sign (uses the keygen'd key)<br>$ sudo extctl install mytool.raw # verify + copy + merge<br>$ extctl ls # see it installed + merged<br>$ sudo extctl remove mytool # tear it back down
Only keygen, install, and remove need root (they write under /etc<br>and the extension directories, and merging overlays /usr). Everything<br>else runs as a normal user.
Installation
Build and install the binary:
cargo install --path app --locked
Or build an RPM (requires rpmbuild):
.rpm">./build-rpm # produces dist/extctl-.rpm
Commands
Subcommand<br>What it does
keygen<br>Generate a signing key/cert and trust it for verification
init<br>Scaffold an extension tree with a host-derived manifest
build<br>Package .// into .raw (mkfs.erofs)
sign<br>Produce .verity / .roothash / .roothash.p7s sidecars
verify<br>Check metadata + signature without installing
install [--boot] [--dry-run]<br>Verify, copy, merge, confirm
ls<br>One-line list of installed extensions + merge state
remove [--boot] [--dry-run]<br>Tear an extension back down
status / doctor<br>Human "why is this not merged" diagnostics
refresh<br>systemd-sysext refresh
unmerge<br>systemd-sysext unmerge
Building and signing
init scaffolds a tree with the extension-release manifest auto-filled<br>from the host's own os-release (ID=, VERSION_ID=, and SYSEXT_LEVEL=<br>if the host sets it). This removes the most common failure mode — a<br>hand-written manifest with a mismatched ID/VERSION_ID.
mytool.raw<br>$ extctl sign mytool.raw # -> mytool.raw.{verity,roothash,p7s}">$ extctl init mytool<br>Created mytool/<br>usr/bin/ - drop your tool here<br>usr/lib/extension-release.d/extension-release.mytool<br>Manifest populated from host os-release. Package it with:<br>extctl build mytool
$ $EDITOR mytool/usr/bin/mytool # put your tool inside<br>$ extctl build mytool # -> mytool.raw<br>$ extctl sign mytool.raw # -> mytool.raw.{verity,roothash,p7s}
Each step prints the next command, so the tool walks you through it.
sign produces byte-exact sidecars: the .roothash is asserted to be<br>exactly 64 hex chars with no trailing newline, since systemd requires that<br>for verity. If you keep your key elsewhere, pass --cert / --key; by<br>default they resolve to the keygen'd pair.
First-time setup: keygen
extctl keygen generates an RSA signing key and self-signed certificate<br>under /etc/extctl/ (the private key is root-only, mode 0600), then drops<br>the certificate into the systemd trust store at /etc/verity.d/sysext.crt.
That second step is the important one: because the cert is trusted, every<br>extension you sign with this key is accepted by verify and install<br>without any further ceremony. Run it once; it refuses to overwrite an<br>existing key (regenerating would invalidate already-installed extensions).
Installing, listing, removing
$ sudo extctl install mytool.raw # verify + copy to /var/lib + merge<br>Installed and merged: mytool
$ extctl ls # docker ps-style<br>mytool /var/lib/extensions merged
$ sudo extctl remove mytool # delete raw + sidecars, unmerge<br>Removed: mytool
install re-verifies metadata and signature, copies atomically, runs<br>refresh, confirms the extension actually merged, and rolls back if it<br>did...