v0.4.0
Fixed
SSH_CA_VAULT_ALLOWED_USERS/SSH_CA_VAULT_ALLOWED_HOST_DOMAINS
now actually take effect from.env.prod. The prod overlay
hardcoded a small env block onbootstrap-substrateand didn't
forward the SSH-CA role allowlists, so an operator extending
SSH_CA_VAULT_ALLOWED_USERSto add a custom login account (e.g.
justinfudally) saw their edit silently ignored — Compose's
--env-fileonly loads values for YAML interpolation, not for
container env. Vault then kept refusing to sign user certs with
the new principal at client provision time
(<user> is not a valid value for valid_principals).
Adds the passthrough indocker-compose.prod.yml(mirroring the
existingDEFAULT_SUBNETshape), the example entry in
.env.prod.example, and a regression test in
tests/test_compose_prod_bootstrap.pyso a future env-block
cleanup can't quietly regress this.
Changed
-
Register-server flow can now bootstrap the host in the same
task. Replaces the standalone "Bootstrap host" dashboard action
andPOST /bootstrap-hostendpoint that shipped in v0.3.x with
a collapsible "Bootstrap this host first" section inside the
Register-server form. When the operator pastes their OOB SSH
private key there,provision_server_taskopens one
BootstrapSSHRunnersession (TOFU + operator key) before the
regular CA-mode provision session, laying down the SSH CA trust- signed host cert + sshd drop-in. One row, one task, one click
for fresh boxes; same behaviour as today when the box was
already bootstrapped (CLI path, baked AMI).
ServerCreateschema (src/wg_manager/schemas.py) gains
optionalbootstrap_ssh_key_pem+bootstrap_ssh_key_passphrase
fields.POST /serversencrypts both via the crypto backend
(Vault Transit in prod) before queueing and forwards the
ciphertext to the task. Passphrase without PEM is rejected at
the schema layer so the operator's intent isn't silently
dropped.provision_server_task(src/wg_manager/tasks.py) accepts
the new encrypted-bootstrap kwargs, decrypts in worker memory,
and runsbootstrap_host()before opening the CA-mode session.
The bootstrap step is skipped entirely when no PEM was supplied;
today's "you forgot to bootstrap" failure mode
(host cert signed by an untrusted CA) is preserved verbatim.- Dashboard
/servers(web/app/servers/page.tsx) drops the
standalone "Bootstrap host" button; the bootstrap section now
lives inside the Register form behind a<details>toggle,
defaulting collapsed so the common (already-bootstrapped) case
stays one click. - Removed:
POST /bootstrap-host,bootstrap_host_task,
BootstrapHostRequest/BootstrapHostResponseschemas,
api.bootstrapHost()client method, and the matching tests.
The CLI (wg-manager bootstrap-host) still exists for
scripted/CI use that wants the install separate from
registration. - Docs:
docs/deploy/single-host-prod.mdupdates "Path A —
Dashboard" to describe the combined Register-with-bootstrap
flow; Path B (CLI) is unchanged.
- signed host cert + sshd drop-in. One row, one task, one click
Published images
ghcr.io/jfudally/wg_manager:v0.4.0— API + workerghcr.io/jfudally/wg_manager-web:v0.4.0— dashboard
Pull either with a granularity-appropriate tag (vX.Y.Z, vX.Y, vX, or latest).
Supply-chain attestation
Both images are signed via cosign keyless OIDC and carry an
in-toto CycloneDX SBOM attestation. Verify with:
cosign verify \
--certificate-identity-regexp \
'https://github.com/jfudally/wg_manager/.github/workflows/release.yml@.*' \
--certificate-oidc-issuer \
'https://token.actions.githubusercontent.com' \
ghcr.io/jfudally/wg_manager:v0.4.0The SBOMs are also attached as release assets:
sbom-api.cdx.json— CycloneDX SBOM of the API + worker image's Python depssbom-web.cdx.json— CycloneDX SBOM of the dashboard image's Node deps