Replace root-SSH deploy with least-privilege chroot user #8

Open
opened 2026-05-21 21:55:42 +02:00 by dominik.polakovics · 0 comments

The forgejo-action deploy key currently has root SSH access on the forgejo container (git.cloonar.com), authorized via root's authorizedKeys. This matches the pre-existing admin model — the shared RSA in fleet.nix:15 already grants root there — but it's a wider blast radius than the runner actually needs.

Goal: replace root SSH with a dedicated low-privilege deploy user whose only capability is updating the SFTP chroots.

Target shape

  • New system user (e.g. bento-deploy) on the forgejo container.
  • Group ownership / write on /home/chroot/<host>/config/, /home/chroot/<host>/logs/, /home/chroot/<host>/last_change_date, set up via systemd.tmpfiles.rules in fleet.nix.
  • The forgejo-action SSH key authorizes login as bento-deploy with command="..." pinning to a fixed deploy script; remove the key from root's authorizedKeys once this lands.
  • The deploy script accepts a host name (e.g. via SSH_ORIGINAL_COMMAND) and performs the bento-style install / rsync --chown / touch last_change_date operations within its narrow permission surface.

Why this is deferred

The PR adopting Forgejo Actions for deploys (path A in ADR-0002) ships first as a literal translation of bento deploy. Path B is net-new infra (new user, new tmpfiles rules, restricted-shell glue, possibly a chroot-ownership rework) and was scoped out to keep the migration focused.

Open subquestions

  • Multi-host vs per-host SSH sessions for the restricted shell.
  • command="..." + arg validation vs sshd-level ForceCommand.
  • Whether rsync --delete survives the constrained shell, or whether to switch to plain sftp put/rm sequences for atomicity.

References

  • ADR-0002 (docs/adr/0002-deploy-via-forgejo-action.md) — "Considered options" lists path B as a deferred alternative; path C (chroot-restructure) is a related but distinct rewrite.
  • .forgejo/workflows/deploy.yml and scripts/sync-host — current path A implementation.
The `forgejo-action` deploy key currently has root SSH access on the forgejo container (`git.cloonar.com`), authorized via root's `authorizedKeys`. This matches the pre-existing admin model — the shared RSA in `fleet.nix:15` already grants root there — but it's a wider blast radius than the runner actually needs. Goal: replace root SSH with a dedicated low-privilege deploy user whose only capability is updating the SFTP chroots. ## Target shape - New system user (e.g. `bento-deploy`) on the forgejo container. - Group ownership / write on `/home/chroot/<host>/config/`, `/home/chroot/<host>/logs/`, `/home/chroot/<host>/last_change_date`, set up via `systemd.tmpfiles.rules` in `fleet.nix`. - The `forgejo-action` SSH key authorizes login as `bento-deploy` with `command="..."` pinning to a fixed deploy script; remove the key from root's `authorizedKeys` once this lands. - The deploy script accepts a host name (e.g. via `SSH_ORIGINAL_COMMAND`) and performs the bento-style `install` / `rsync --chown` / `touch last_change_date` operations within its narrow permission surface. ## Why this is deferred The PR adopting Forgejo Actions for deploys (path A in ADR-0002) ships first as a literal translation of `bento deploy`. Path B is net-new infra (new user, new tmpfiles rules, restricted-shell glue, possibly a chroot-ownership rework) and was scoped out to keep the migration focused. ## Open subquestions - Multi-host vs per-host SSH sessions for the restricted shell. - `command="..."` + arg validation vs sshd-level `ForceCommand`. - Whether `rsync --delete` survives the constrained shell, or whether to switch to plain `sftp` put/rm sequences for atomicity. ## References - ADR-0002 (`docs/adr/0002-deploy-via-forgejo-action.md`) — "Considered options" lists path B as a deferred alternative; path C (chroot-restructure) is a related but distinct rewrite. - `.forgejo/workflows/deploy.yml` and `scripts/sync-host` — current path A implementation.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/nixos#8
No description provided.