Multi-user hosts: make box work in per-user Incus projects (restricted incus tier) #72

Closed
opened 2026-07-17 16:43:04 +00:00 by dan-claude-bot · 0 comments
dan-claude-bot commented 2026-07-17 16:43:04 +00:00 (Migrated from github.com)

Context

The dev-server will be shared by three operators, multiple boxes each. The identity model (heavy-duty/rig#24) deliberately keeps operators out of incus-admin (host-root-equivalent skeleton key) and instead grants the box role = membership in the incus group, where Incus's incus-user daemon confines each member to their own Incus project: they see and manage only their own instances. This issue makes box work correctly in that world.

Task 0 — verify the substrate (blocks everything)

Confirm on the M900s' Incus version (and in a rehearsal VM) that the restricted tier actually behaves as documented: a user in incus (not incus-admin) gets a per-user project via incus-user, cannot see other projects' instances, and can launch VMs. Record versions and any gaps in the plan doc. If the shipped Incus lacks a working incus-user, this issue's design changes materially — verify before building.

The audit: box's daemon-global assumptions

box today assumes full-socket access and daemon-global resources. Known project-sensitive surfaces (audit for completeness — this list is a starting point, not the spec):

  • profiles/box-net.yaml — the box-net profile is created once, daemon-wide, by setup-host. Profiles are per-project in Incus: each user's project needs the profile present (copy at first use? box doctor --fix? project-creation hook?). Decide the owner and the convergence story.
  • boxnet network + box-isolate ACL — networks and ACLs are daemon-global (visible across projects) but restricted users may lack rights to attach or modify them. Verify a restricted user can launch onto boxnet with the profile; setup (create/modify) stays admin-only via setup-host.
  • Ownership tagsuser.box=1 has no owner identity; under projects that's fine (the project is the owner boundary), but box list / resolve_box must scope to the caller's project and not error on cross-project name collisions (two users can both have a box named work).
  • box expose — binds host loopback and edits ACL ingress + static ipv4.address pins; restricted users may lack ACL/network edit rights. Decide: expose becomes admin-assisted, or the ACL carve-out mechanism is rethought for projects.
  • setup-host / doctor / migrate-host — admin-tier commands; they should detect and say which tier the caller is in (incus-admin vs restricted) instead of failing opaquely.
  • Storage pool — daemon-global; restricted projects can use it, verify quota/limits story (per-project limits are available and may later serve per-user quotas — out of scope, note only).

What changes (shape, refined by the audit)

  1. box detects its access tier and behaves correctly in both: full (incus-admin, today's behavior unchanged) and restricted (per-user project).
  2. Per-project bring-up of the box-net profile (the one resource each project genuinely needs locally), owned by a convergent path (doctor --fix or first box new).
  3. box list/info/lifecycle verbs work identically inside a restricted project.
  4. Docs: multi-user model section — incus group = normal operators (via heavy-duty/rig#24's box role), incus-admin = break-glass; what each tier can and cannot do (expose caveats included).

Non-goals

  • No per-user quotas/limits (note the Incus project-limits mechanism for later).
  • No changes to the isolation stack semantics — the same profile/network/ACL contract, made project-aware.
  • No rig changes (group membership is rig#24's job).

Acceptance

  • On a host where setup-host has run: a user in incus only can box new/list/shell/snapshot/rm their own boxes; a second restricted user cannot see them; name collisions across users are fine.
  • An incus-admin user sees today's behavior unchanged.
  • box doctor reports the caller's tier and the project's health honestly.

Companion: global install (linked below) · rig#24 (box role definition) · rig#25 (machine classes)

Companion global-install issue: https://github.com/heavy-duty/box/issues/71

## Context The dev-server will be shared by three operators, multiple boxes each. The identity model (heavy-duty/rig#24) deliberately keeps operators out of `incus-admin` (host-root-equivalent skeleton key) and instead grants the **`box` role = membership in the `incus` group**, where Incus's `incus-user` daemon confines each member to their own **Incus project**: they see and manage only their own instances. This issue makes box work correctly in that world. ## Task 0 — verify the substrate (blocks everything) Confirm on the M900s' Incus version (and in a rehearsal VM) that the restricted tier actually behaves as documented: a user in `incus` (not `incus-admin`) gets a per-user project via `incus-user`, cannot see other projects' instances, and can launch VMs. Record versions and any gaps in the plan doc. If the shipped Incus lacks a working `incus-user`, this issue's design changes materially — verify before building. ## The audit: box's daemon-global assumptions box today assumes full-socket access and daemon-global resources. Known project-sensitive surfaces (audit for completeness — this list is a starting point, not the spec): - **`profiles/box-net.yaml`** — the `box-net` profile is created once, daemon-wide, by `setup-host`. Profiles are per-project in Incus: each user's project needs the profile present (copy at first use? `box doctor --fix`? project-creation hook?). Decide the owner and the convergence story. - **`boxnet` network + `box-isolate` ACL** — networks and ACLs are daemon-global (visible across projects) but restricted users may lack rights to attach or modify them. Verify a restricted user can launch onto `boxnet` with the profile; setup (create/modify) stays admin-only via `setup-host`. - **Ownership tags** — `user.box=1` has no owner identity; under projects that's fine (the project *is* the owner boundary), but `box list` / `resolve_box` must scope to the caller's project and not error on cross-project name collisions (two users can both have a box named `work`). - **`box expose`** — binds host loopback and edits ACL ingress + static `ipv4.address` pins; restricted users may lack ACL/network edit rights. Decide: expose becomes admin-assisted, or the ACL carve-out mechanism is rethought for projects. - **`setup-host` / `doctor` / `migrate-host`** — admin-tier commands; they should detect and say which tier the caller is in (`incus-admin` vs restricted) instead of failing opaquely. - **Storage pool** — daemon-global; restricted projects can use it, verify quota/limits story (per-project limits are available and may later serve per-user quotas — out of scope, note only). ## What changes (shape, refined by the audit) 1. box detects its access tier and behaves correctly in both: full (`incus-admin`, today's behavior unchanged) and restricted (per-user project). 2. Per-project bring-up of the `box-net` profile (the one resource each project genuinely needs locally), owned by a convergent path (`doctor --fix` or first `box new`). 3. `box list`/`info`/lifecycle verbs work identically inside a restricted project. 4. Docs: multi-user model section — `incus` group = normal operators (via heavy-duty/rig#24's `box` role), `incus-admin` = break-glass; what each tier can and cannot do (`expose` caveats included). ## Non-goals - No per-user quotas/limits (note the Incus project-limits mechanism for later). - No changes to the isolation stack semantics — the same profile/network/ACL contract, made project-aware. - No rig changes (group membership is rig#24's job). ## Acceptance - On a host where `setup-host` has run: a user in `incus` only can `box new/list/shell/snapshot/rm` their own boxes; a second restricted user cannot see them; name collisions across users are fine. - An `incus-admin` user sees today's behavior unchanged. - `box doctor` reports the caller's tier and the project's health honestly. --- Companion: global install (linked below) · rig#24 (`box` role definition) · rig#25 (machine classes) Companion global-install issue: https://github.com/heavy-duty/box/issues/71
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: heavy-duty/box#72
No description provided.