-
v0.3.1 — per-ISO password gate Pre-Release
released this
2026-05-06 22:35:11 -04:00 | 49 commits to main since this releasev0.3.1 — per-ISO boot password gate
Operators can now lock individual ISOs behind a password set in the WebUI. Picking a locked image at the PXE menu prompts the operator on the client console; the boot script is only released after a correct match. The plaintext never leaves the request — server stores bcrypt hashes, scripts never echo the candidate.
Pull
docker pull gitea.milesward.dev/mward4/openpxe:0.3.1How it looks
In the WebUI's Storage tab, each image row gains an Auth column (
open/protected) and a per-row "Set password" / "Password ✎" button that toggles an inline editor — checkbox + masked input + Save. A 🔒 appears next to the filename when locked.In the PXE menu, locked entries get a leading
*next to the size box:item --key 1 win11-test-winpe *[ 5234 MB] Windows 11 TestWhen a locked entry is selected, iPXE shows a "This image requires a password" banner, accepts input via
read --secret password(no echo), and chains back with?token=${password:uristring}so passwords with&,?,=, spaces, etc. survive transport. Wrong password sleeps 2s, printsWrong password., then re-prompts. Empty input bails to the main menu.API
PUT /api/isos/:id/passwordbody { "password": "..." }to set,{ "password": null }(or empty string) to clear.DELETE /api/isos/:id/passwordexplicit clear. Both 204 on success, 404 for unknown ids.
Security posture
- bcrypt cost =
DEFAULT_COST(10). One verify takes ~50ms on modern x86 — acceptable interactive latency, hostile to brute force on a leaked meta.json. - Server logs only that a wrong-password attempt happened plus the entry id. Never the candidate, never the correct value, never the bcrypt hash.
- Boot scripts never echo any password value back to the client console.
- The token rides in the query string — acceptable on a trusted boot VLAN, but if you reverse-proxy OpenPXE the token will end up in proxy access logs. Don't expose this to untrusted networks.
Tests
74 passing across the workspace (was 66 in v0.3.0):
- 3 store unit tests (bcrypt round-trip, unknown-id error, meta.json persistence across restart)
- 2 ipxe_script unit tests (prompt + auth-fail invariants:
read --secret,:uristring, no candidate echo) - 3 HTTP integration tests (full upload → set → prompt → fail → success → clear flow, null/empty bodies, 404 on unknown id)
cargo clippy --workspace --all-targetsclean.Local smoke verified end-to-end on a real release binary: upload
Win11_Test.iso→ PUT password → menu shows the lock indicator → no token returns prompt → wrong token returnsWrong password.→ correct token returns the wimboot chain → password values do not appear in the server log.Image details
- Base:
debian:12-slim - Architecture:
linux/amd64 - Size: ~97 MB
- Digest:
sha256:f3e5ee78079c25f55cb826837b8dda9428bf6b9592d9f15a2f6b413c5642fa1e - Runs as uid 10001
- Required cap:
NET_BIND_SERVICE - Optional cap:
SYS_ADMINfor NFS share mounting
Upgrade from v0.3.0
Drop-in. New
password_hashfield onIsoMetaisOption<String>and skipped during serialize when None — existing meta.json files are forward-compatible. Existing settings.json carries through.:latestnow points at0.3.1.Downloads
- bcrypt cost =