Manage dropbear via a systemd path unit watching authorized_keys - #4896
Manage dropbear via a systemd path unit watching authorized_keys#4896agners wants to merge 1 commit into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
1a173c6 to
79a048a
Compare
Debug SSH access on port 22222 currently has two lifecycle mechanisms: dropbear.service is enabled and gated by ConditionFileNotEmpty=/root/.ssh/authorized_keys at boot, and haos-config explicitly starts/stops the service when importing a CONFIG partition. Keys written through any other path - most notably os-agent's AddSSHAuthKey D-Bus method, which the Supervisor is growing an API on top of - do not start dropbear until the next reboot. Add dropbear.path, watching /root/.ssh/authorized_keys, triggering a oneshot dropbear-lifecycle.service that starts dropbear when the file is non-empty and stops it when it is absent. This makes the file the single source of truth for whether debug SSH runs, regardless of the writer, and lets haos-config drop its explicit systemctl calls. Design notes: - PathChanged= only, no PathExists=: an exists-trigger pointed at a oneshot that does not consume the file re-triggers on every deactivation until the start rate limit is hit. Boot-time presence is already handled by the enabled dropbear.service and its ConditionFileNotEmpty. - The lifecycle service is idempotent since the watch may fire for any change in the directory, including temporary files from atomic writes (rename into place is IN_MOVED_TO, which PathChanged= covers). - RequiresMountsFor=/root/.ssh orders the watch after root-.ssh.mount: inotify events do not cross mount points, so a watch armed on the shadowed rootfs inode would never fire. If the bind mount ever goes away, the directive degenerates to a no-op. - Before=haos-config.service arms the watch before the config import can write the file, closing the missed-event race on first boot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
79a048a to
36d23c7
Compare
The cla error is addressed with the latest commit
|
This feels a bit backwards: Dropbear gets started based on a file instead of explicit start call. This also means that in case the start fails the caller would not directly notice. And finally, it also opens up to a small race condition (e.g. add key then connect through SSH isn't guarantee to work since it may take short moment for Dropbear to start. We need to start Dropbear explicitly in home-assistant/supervisor#7039 anyways. This more explicit lifecycle management of system services seems the better idea. Hence not following through with this file based approach. |
Proposed change
Debug SSH access on port 22222 currently has two lifecycle mechanisms:
dropbear.serviceis enabled and gated byConditionFileNotEmpty=/root/.ssh/authorized_keysat boot, andhaos-configexplicitly starts/stops the service when importing a CONFIG partition. Keys written through any other path — most notably os-agent'sAddSSHAuthKeyD-Bus method (see home-assistant/os-agent#273), which the Supervisor is growing an API on top of — do not start dropbear until the next reboot.This PR adds
dropbear.path, watching/root/.ssh/authorized_keys, which triggers a oneshotdropbear-lifecycle.servicethat starts dropbear when the file is non-empty and stops it when it is absent. The file becomes the single source of truth for whether debug SSH runs, regardless of who wrote it (haos-config import, os-agent, or a manual write on the console), andhaos-configdrops its explicitsystemctl start/stop dropbearcalls.Resulting behavior:
dropbear.servicestarts via its own enablement + condition (unchanged)ConditionFileNotEmpty(unchanged)Design notes
PathChanged=only, deliberately noPathExists=: an exists-trigger pointed at a oneshot that doesn't consume the file re-triggers on every deactivation until the start rate limit is hit and the path unit fails. Boot-time presence is already covered by the enableddropbear.serviceand itsConditionFileNotEmpty.IN_MOVED_TO, whichPathChanged=covers.RequiresMountsFor=/root/.sshorders the watch afterroot-.ssh.mount: inotify events don't cross mount points, so a watch armed before the bind mount would sit on the shadowed rootfs inode and never fire. It also restarts the path unit if the mount is ever restarted, and degenerates to a no-op if the bind mount goes away in a future layout.Before=haos-config.servicearms the watch before the config import can write the file, closing the missed-event race on first boot (PathChanged=is edge-triggered and does not check the initial state).systemctl preset-allinpost-build.sh(implicitenable *policy); no preset change needed.ClearSSHAuthKeys/MkdirAllcycles from os-agent are handled.Type of change
Additional information
🤖 Generated with Claude Code