Show HN: Extctl, a super simple systemd-sysext wrapper

fluorocaster1 pts0 comments

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...

extctl mytool sign install systemd build

Related Articles