Phase 406 — authenticated SSH proof
| Item | Value |
|---|---|
| Command | make phase 406 |
| Underlying make target/scripts | vm/phase4/materialize-etc.sh --ssh, then vm/phase4/ssh-probe.sh |
| Mutates disk/image? | Yes, it mounts artifacts/onix-image/onix.raw and installs a bootstrap SSH server, user, keys, and service |
| Boots QEMU? | Yes, it runs an automated SSH proof through QEMU port forwarding |
| Main proof | The host authenticates with an SSH key to onix@127.0.0.1:7626 and receives ONIX_SSH_OK user=onix uid=1000. |
What this phase proves
Phase 405 proved host-to-guest TCP reachability, but it was not authenticated.
Phase 406 proves a stronger thing:
the host can authenticate to the booted ONIX VM over SSH using a public key
This is the first real remote-access proof.
Why Dropbear, not OpenSSH yet?
Both pkgsMusl.dropbear and pkgsMusl.openssh exist in the pinned Nix world.
Phase 406 chooses Dropbear because it is small and good for bootstrap systems.
That fits the current image better:
tiny booted base
temporary bootstrap services
prove the concept first
final policy later
OpenSSH may still be the final choice later. This phase does not decide that forever.
Authentication policy
Phase 406 is intentionally stricter than Phase 405.
The Dropbear service is started with:
-s disable password logins
-w disallow root logins
-j disable local port forwarding
-k disable remote port forwarding
So the proof is:
public-key auth only
non-root user only
no password auth
no root SSH login
The bootstrap user is:
user onix
uid 1000
gid 100
home /home/onix
shell /bin/sh
The root account remains non-interactive from the normal account database point of view:
root ... /usr/sbin/nologin
That means Phase 406 does not silently undo the safety decision from Phase 402.
Where the key lives
The host-side proof key is:
vm/state/id_ed25519
vm/state/id_ed25519.pub
If the key does not exist, Phase 406 generates it.
The guest-side authorized key is installed under the persistent home tree:
/persist/home/onix/.ssh/authorized_keys
Why /persist/home instead of /home while building the image?
Because at boot ONIX bind-mounts:
/persist/home -> /home
So if we wrote only to the root filesystem’s /home, it would be hidden after
the real persistent home mount appears.
This is the same kind of mount lesson we learned earlier with /persist/nix.
Host keys
SSH servers need host keys too.
The host key identifies the guest server to clients.
Phase 406 generates:
/etc/dropbear/dropbear_ed25519_host_key
If that file already exists, it is preserved.
This is still bootstrap policy. A final installed system needs a better story for host-key lifecycle and persistence.
QEMU forwarding
The guest listens on the normal SSH port:
guest 0.0.0.0:22
QEMU forwards a host-local test port:
host 127.0.0.1:7626 -> guest :22
So the host proof command uses:
ssh -i vm/state/id_ed25519 -p 7626 onix@127.0.0.1 ...
The automated proof
make phase 406 first installs the pieces:
./materialize-etc.sh --ssh
That installs:
pkgsMusl.dropbear closure
/usr/lib/sysusers.d/onix-ssh.conf
/persist/home/onix/.ssh/authorized_keys
/etc/dropbear/dropbear_ed25519_host_key
/usr/lib/onix/bootstrap-ssh-status
/usr/lib/onix/bootstrap-ssh-proof
onix-bootstrap-dropbear.service
Then it boots QEMU:
./ssh-probe.sh
The probe uses the serial shell first to ask the guest:
/usr/lib/onix/bootstrap-network-proof &&
/usr/lib/onix/bootstrap-ssh-proof
The guest must answer:
ONIX_SSH_READY user=onix port=22
Then the host runs SSH:
ssh -i vm/state/id_ed25519 -p 7626 onix@127.0.0.1 \
'printf "ONIX_SSH_OK user=$(/bin/id -un) uid=$(/bin/id -u) ...\n"'
The host must receive:
ONIX_SSH_OK user=onix uid=1000
That proves:
- Dropbear started in the guest,
- QEMU forwarded the host port to the guest,
- the
onixuser exists, /home/onix/.ssh/authorized_keysis visible through/persist/home,- password auth is not needed,
- public-key auth succeeds.
Run it
From the repo root:
make phase 406
Expected output includes:
policy : /usr/lib/sysusers.d/onix-ssh.conf
ssh-auth : /persist/home/onix/.ssh/authorized_keys
ssh-host : /etc/dropbear/dropbear_ed25519_host_key generated
unit : /nix/store/.../onix-bootstrap-dropbear.service
unit : /persist/nix/store/.../onix-bootstrap-dropbear.service
Expected proof output includes:
ONIX_SSH_READY user=onix port=22
ONIX_SSH_OK user=onix uid=1000 home=/home/onix shell=/bin/sh host=onix kernel=Linux
==> success
Phase 406 proved authenticated SSH access through QEMU port forwarding.
What this phase does not do
Phase 406 does not finalize remote administration.
Still open:
- whether final ONIX uses Dropbear or OpenSSH,
- how users are created on first boot,
- where user-provided SSH keys come from,
- whether root SSH is always forbidden,
- where persistent host keys should live long-term,
- firewall policy,
- SSH hardening policy,
- whether remote access is enabled by default.
Phase 406 proves the essential mechanism:
authenticated key-based SSH into the booted ONIX image works