feat(tf-incus): deploy via incus exec, drop deployment SSH #1112

Merged
kiara merged 1 commit from kiara/fediversity:incus-exec into main 2026-06-21 10:22:47 +02:00
Owner

Paves the way for #24, as suggested at #295 (comment).

The tf-incus path provisioned Incus containers with the lxc/incus
provider, then deployed NixOS onto them over SSH: nix-copy-closure
plus switch-to-configuration through ProxyJump=incushost, gated on
await-ssh.sh. To make that channel reachable each container baked the
deployer's pubkey into root's authorized_keys and carried SSH-survival
scaffolding to keep sshd alive across the switch.

The deployer already holds an Incus mTLS client cert and the container
instance name is plumbed through the data model, so the container is
reachable with incus exec against incus:<name> without any SSH into
it. Switch the deployment transport to incus exec:

  • New src/effects/incus/run.sh: streams the closure with
    nix-store --export | incus exec -T -- nix-store --import (no
    nix-copy-closure), runs every remote step via incus exec, and
    registers the provider's mTLS remote at runtime (the provider keeps
    remotes in TF state only, so the CLI config dir has none). The
    transport-agnostic nspawn D-Bus-recovery logic is preserved.
  • New src/effects/tf/incus/host/ module + await-incus.sh readiness
    gate; hosts/main.tf addresses containers by name, dropping the
    cached-IP dance and await-ssh.sh.
  • The deploy/await scripts are writeShellApplication-wrapped so
    pkgs.incus is pinned on PATH.

Containers keep sshd for operator login (the shared
setups/nixos/networking.nix + procolix keys); only the deployer's
baked key and the deploy-SSH scaffolding are removed. The now-dead SSH
key wiring in the api/panel/tf-incus tests is dropped accordingly.

incusModel is also the deployed-config generator for the SSH-transport
tests (apps-tf, deployment-tf-hosts), whose test scripts still SSH
root@<container> after the deploy, so the sshd-survival block stays in
incusModel (inert for the incus path); only extraRootKeys is removed.

Verified on fediversity-ci: deployment-tf-incus-hosts, apps-tf-incus,
apps-api, apps-tf, deployment-tf-hosts all green.

Note that this may remove some ssh bits from api/panel that may turn out useful for say #723.

Paves the way for #24, as suggested at https://git.fediversity.eu/fediversity/fediversity/issues/295#issuecomment-14806. The `tf-incus` path provisioned Incus containers with the `lxc/incus` provider, then deployed NixOS onto them over SSH: `nix-copy-closure` plus `switch-to-configuration` through `ProxyJump=incushost`, gated on `await-ssh.sh`. To make that channel reachable each container baked the deployer's pubkey into root's `authorized_keys` and carried SSH-survival scaffolding to keep sshd alive across the switch. The deployer already holds an Incus mTLS client cert and the container instance name is plumbed through the data model, so the container is reachable with `incus exec` against `incus:<name>` without any SSH into it. Switch the deployment transport to `incus exec`: - New `src/effects/incus/run.sh`: streams the closure with `nix-store --export | incus exec -T -- nix-store --import` (no `nix-copy-closure`), runs every remote step via `incus exec`, and registers the provider's mTLS remote at runtime (the provider keeps remotes in TF state only, so the CLI config dir has none). The transport-agnostic nspawn D-Bus-recovery logic is preserved. - New `src/effects/tf/incus/host/` module + `await-incus.sh` readiness gate; `hosts/main.tf` addresses containers by name, dropping the cached-IP dance and `await-ssh.sh`. - The deploy/await scripts are `writeShellApplication`-wrapped so `pkgs.incus` is pinned on PATH. Containers keep sshd for operator login (the shared `setups/nixos/networking.nix` + procolix keys); only the deployer's baked key and the deploy-SSH scaffolding are removed. The now-dead SSH key wiring in the api/panel/tf-incus tests is dropped accordingly. `incusModel` is also the deployed-config generator for the SSH-transport tests (`apps-tf`, `deployment-tf-hosts`), whose test scripts still SSH `root@<container>` after the deploy, so the sshd-survival block stays in `incusModel` (inert for the incus path); only `extraRootKeys` is removed. Verified on fediversity-ci: deployment-tf-incus-hosts, apps-tf-incus, apps-api, apps-tf, deployment-tf-hosts all green. Note that this may remove some ssh bits from api/panel that may turn out useful for say #723.
feat(tf-incus): deploy via incus exec, drop deployment SSH
All checks were successful
checks-api-assets-fresh / api-assets-fresh (pull_request) Successful in 5s
checks-panel-forms-island-dom / panel-forms-island-dom (pull_request) Successful in 6s
checks-api-python-tests / api-python-tests (pull_request) Successful in 7s
checks-panel-forms-island / panel-forms-island (pull_request) Successful in 5s
checks-api-asyncapi-validate / api-asyncapi-validate (pull_request) Successful in 8s
nixosConfigurations-dev-forgejo-runner / dev-forgejo-runner (pull_request) Successful in 12s
devShells-default / default (pull_request) Successful in 18s
nixosConfigurations-dev-forgejo / dev-forgejo (pull_request) Successful in 18s
nixosConfigurations-hosting-provider-incus / hosting-provider-incus (pull_request) Successful in 19s
nixosConfigurations-hosting-provider-api / hosting-provider-api (pull_request) Successful in 19s
nix-unit-contracts-lib / contracts-lib (pull_request) Successful in 23s
checks-api-docs / api-docs (pull_request) Successful in 15s
nix-unit-effects-common-lib / effects-common-lib (pull_request) Successful in 24s
nixosConfigurations-hosting-provider-netbox / hosting-provider-netbox (pull_request) Successful in 16s
nix-unit-effects-tf-common-conversion / effects-tf-common-conversion (pull_request) Successful in 11s
checks-api-openapi-validate / api-openapi-validate (pull_request) Successful in 8s
nixosConfigurations-hosting-provider-openbao / hosting-provider-openbao (pull_request) Successful in 15s
nixosConfigurations-hosting-provider-panel / hosting-provider-panel (pull_request) Successful in 14s
checks-test-mastodon-service / test-mastodon-service (pull_request) Successful in 40s
nixosConfigurations-hosting-provider-otel-collector / hosting-provider-otel-collector (pull_request) Successful in 15s
checks-test-peertube-service / test-peertube-service (pull_request) Successful in 42s
checks-test-pixelfed-service / test-pixelfed-service (pull_request) Successful in 40s
nixosConfigurations-hosting-provider-spire / hosting-provider-spire (pull_request) Successful in 12s
checks-asyncapi-docs / asyncapi-docs (pull_request) Successful in 7s
nix-unit-lib-data-model / lib-data-model (pull_request) Successful in 21s
checks-api-http / api-http (pull_request) Successful in 54s
nix-unit-lib-function / lib-function (pull_request) Successful in 21s
nixosConfigurations-hosting-provider-terraform-backend / hosting-provider-terraform-backend (pull_request) Successful in 11s
nixosConfigurations-hosting-provider-windmill / hosting-provider-windmill (pull_request) Successful in 12s
nixosConfigurations-operator-authelia / operator-authelia (pull_request) Successful in 12s
nix-unit-lib-lib / lib-lib (pull_request) Successful in 21s
nix-unit-lib-renames-for-source / lib-renames-for-source (pull_request) Successful in 7s
checks-contracts-chaining / contracts-chaining (pull_request) Successful in 13s
nixosConfigurations-operator-combined / operator-combined (pull_request) Successful in 17s
nixosConfigurations-operator-lldap / operator-lldap (pull_request) Successful in 15s
nixosConfigurations-operator-garage / operator-garage (pull_request) Successful in 17s
nixosConfigurations-operator-mastodon / operator-mastodon (pull_request) Successful in 15s
nixosConfigurations-operator-peertube / operator-peertube (pull_request) Successful in 15s
nix-unit-resources-generateFiles / resources-generateFiles (pull_request) Successful in 22s
checks-contracts-cross-node / contracts-cross-node (pull_request) Successful in 15s
nix-unit-resources-secrets / resources-secrets (pull_request) Successful in 18s
nixosConfigurations-operator-pixelfed / operator-pixelfed (pull_request) Successful in 14s
nix-unit-resources-otel / resources-otel (pull_request) Successful in 23s
nixosConfigurations-operator-smtp / operator-smtp (pull_request) Successful in 12s
checks-contracts-filebackup-hardcoded-file-backup / contracts-filebackup-hardcoded-file-backup (pull_request) Successful in 14s
checks-panel-basic / panel-basic (pull_request) Successful in 1m31s
checks-contracts-filesecrets-hardcoded-secret / contracts-filesecrets-hardcoded-secret (pull_request) Successful in 11s
Nix flake completeness check / _complete (pull_request) Successful in 1m45s
checks-contracts-generatefiles-vars-openbao / contracts-generatefiles-vars-openbao (pull_request) Successful in 10s
checks-contracts-generatefiles-vars / contracts-generatefiles-vars (pull_request) Successful in 10s
checks-contracts-ldap-hardcoded / contracts-ldap-hardcoded (pull_request) Successful in 9s
checks-contracts-ldap-lldap / contracts-ldap-lldap (pull_request) Successful in 10s
checks-contracts-s3-hardcoded / contracts-s3-hardcoded (pull_request) Successful in 9s
checks-contracts-smtp-hardcoded / contracts-smtp-hardcoded (pull_request) Successful in 10s
checks-contracts-ssl-self-signed / contracts-ssl-self-signed (pull_request) Successful in 9s
checks-contracts-smtp-maddy / contracts-smtp-maddy (pull_request) Successful in 11s
checks-deployment-nixos-hosts / deployment-nixos-hosts (pull_request) Successful in 2m29s
checks-contracts-streamingbackup-hardcoded / contracts-streamingbackup-hardcoded (pull_request) Successful in 9s
checks-contracts-sso-hardcoded / contracts-sso-hardcoded (pull_request) Successful in 10s
checks-contracts-systemd-openbaod / contracts-systemd-openbaod (pull_request) Successful in 10s
flake-show / apps-ssh (pull_request) Successful in 2m47s
checks-integrations-spire-openbao / integrations-spire-openbao (pull_request) Successful in 13s
checks-panel-docs / panel-docs (pull_request) Successful in 7s
checks-resources-secrets-agenix / resources-secrets-agenix (pull_request) Successful in 9s
checks-test-otel-wiring / test-otel-wiring (pull_request) Successful in 11s
checks-treefmt / treefmt (pull_request) Successful in 10s
checks-integrations-octodns / integrations-octodns (pull_request) Successful in 3m46s
checks-deployment-tf-hosts / deployment-tf-hosts (pull_request) Successful in 4m22s
checks-core-docs / core-docs (pull_request) Successful in 4m52s
checks-deployment-ssh-hosts / deployment-ssh-hosts (pull_request) Successful in 5m6s
checks-deployment-tf-incus-hosts / deployment-tf-incus-hosts (pull_request) Successful in 6m0s
checks-apps-api / apps-api (pull_request) Successful in 44m50s
checks-apps-panel / apps-panel (pull_request) Successful in 50m4s
checks-apps-tf / apps-tf (pull_request) Successful in 51m48s
checks-apps-tf-incus / apps-tf-incus (pull_request) Successful in 46m2s
dd6ba18ec3
The `tf-incus` path provisioned Incus containers with the `lxc/incus`
provider, then deployed NixOS onto them over SSH: `nix-copy-closure`
plus `switch-to-configuration` through `ProxyJump=incushost`, gated on
`await-ssh.sh`. To make that channel reachable each container baked the
deployer's pubkey into root's `authorized_keys` and carried SSH-survival
scaffolding to keep sshd alive across the switch.

The deployer already holds an Incus mTLS client cert and the container
instance name is plumbed through the data model, so the container is
reachable with `incus exec` against `incus:<name>` without any SSH into
it. Switch the deployment transport to `incus exec`:

- New `src/effects/incus/run.sh`: streams the closure with
  `nix-store --export | incus exec -T -- nix-store --import` (no
  `nix-copy-closure`), runs every remote step via `incus exec`, and
  registers the provider's mTLS remote at runtime (the provider keeps
  remotes in TF state only, so the CLI config dir has none). The
  transport-agnostic nspawn D-Bus-recovery logic is preserved.
- New `src/effects/tf/incus/host/` module + `await-incus.sh` readiness
  gate; `hosts/main.tf` addresses containers by name, dropping the
  cached-IP dance and `await-ssh.sh`.
- The deploy/await scripts are `writeShellApplication`-wrapped so
  `pkgs.incus` is pinned on PATH.

Containers keep sshd for operator login (the shared
`setups/nixos/networking.nix` + procolix keys); only the deployer's
baked key and the deploy-SSH scaffolding are removed. The now-dead SSH
key wiring in the api/panel/tf-incus tests is dropped accordingly.

`incusModel` is also the deployed-config generator for the SSH-transport
tests (`apps-tf`, `deployment-tf-hosts`), whose test scripts still SSH
`root@<container>` after the deploy, so the sshd-survival block stays in
`incusModel` (inert for the incus path); only `extraRootKeys` is removed.

Verified on fediversity-ci: deployment-tf-incus-hosts, apps-tf-incus,
apps-api, apps-tf, deployment-tf-hosts all green.

Assisted-by: Claude:claude-opus-4-8
kiara changed title from WIP: feat(tf-incus): deploy via incus exec, drop deployment SSH to feat(tf-incus): deploy via incus exec, drop deployment SSH 2026-06-21 10:22:33 +02:00
kiara merged commit 46350fed2c into main 2026-06-21 10:22:47 +02:00
kiara deleted branch incus-exec 2026-06-21 10:22:47 +02:00
Sign in to join this conversation.
No reviewers
fediversity/developers
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
fediversity/fediversity!1112
No description provided.