TacidOS
Developers
Documentation

Decision 0098

98. The installer makes the host key, and the machine answers to its name

Architecture decision record 0098: 98. The installer makes the host key, and the machine answers to its name

Status
accepted
Date
2026-10-06

Refines ADR-0095 · ADR-0036

Context

The installer could import a person’s SSH keys. Three things still stood between that and ssh dom@box working the first time, the way it does after Ubuntu Server’s installer.

  1. The host key was made at first boot. It did not exist until the installed machine first booted. The first ssh asked the person to trust a fingerprint nobody had seen, which is the step SSH’s security rests on and the step everyone skips.
  2. The machine had no name on the network. The person had to find its address from the router.
  3. passwd did not last. ADR-0095 kept the password’s hash on /persist and noted that passwd lasts only until the next boot. That is a surprise in exactly the command people use to change a password.

Decision

The installer makes the machine’s Ed25519 host key and prints its fingerprint. The machine answers to <hostname>.local while it listens for SSH. A change made with passwd is carried to /persist.

  • The host key. The keeper generates an Ed25519 key with tacid_install::HostKey and writes it in OpenSSH’s own format. A test proves the bytes match what ssh-keygen writes for the same seed. It goes to /persist/etc/ssh/ssh_host_ed25519_key through a new guarded stem operation, HostKeyWrite: only into the install mount, private key 0600, public key 0644, both root’s. The private half is registered with the scrubber and appears nowhere else. The fingerprint is printed at the end of the installation, as ssh-keygen -l prints it, beside the recovery key. This happens for every machine that will listen for SSH: asked for, or headless.
  • The name. Enabling openssh turns on multicast DNS in systemd-resolved and on the default networkd links, and opens UDP 5353. The installer’s last screen says ssh <user>@<host>.local. A machine that does not listen for SSH announces nothing.
  • passwd. A path unit watches /etc/shadow. When it changes, tacid-passwords.service copies the new hash into /persist/etc/tacid-passwords/<user>, for users who already have a file there. A locked account or an emptied password is not copied. tacid password remains the verb that changes both at once.

Consequences

  • The first ssh from the person’s laptop can be checked against a fingerprint they have already seen.
  • ssh dom@box.local works on a home or office network with no address to look up. On networks that block multicast it does not, and the IP address still works.
  • The stem gains one guarded operation. It writes a file whose shape it checks itself: a PEM block and a single ssh-ed25519 line.
  • The install test asserts the fingerprint shown equals ssh-keygen -lf on the machine and equals what ssh-keyscan sees. It also asserts that a password changed with chpasswd is the one the account has after the next reboot.

Alternatives rejected

  • Generate the host key with ssh-keygen in the stem. That adds a tool and parses its output, and the live image would need OpenSSH’s keygen on the stem’s path. Writing the format is about forty lines, and a test holds it to ssh-keygen’s bytes.
  • Avahi. It is a second daemon and a second resolver on a machine that already runs systemd-resolved, which speaks mDNS.
  • users.mutableUsers = false with no passwd. That would make the surprise a refusal instead of a fix, and a person changing their password should not have to learn a new verb.