Support explicit native mesh SSH authentication modes #73
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem and evidence
crates/ssh/src/client.rs:181authenticates only with the owning infraternal agent's Ed25519 public key. It has no network-authentication mode for native mesh SSH, so ordinary sshd reached over a mesh IP and native mesh SSH are different cases.Current vendor docs distinguish the native modes: Tailscale SSH uses SSH authentication type
nonewhen Tailscale has authorized the peer. NetBird SSH defaults to IdP JWT authentication;--disable-ssh-authselects machine-identity access governed by NetBird network ACLs.Recommendation
Detect a supported mesh-SSH banner as an untrusted compatibility hint, then use an explicit supported network-auth mode for the target. Support the owner-selected SSH
nonepath when the peer is configured for network-policy authentication; report a clear unsupported/configuration error for a JWT mode the client cannot perform. Keep the existing host-key Trust step and verify the presented key on every connection.Payoff and estimate
Lets users reach native mesh SSH hosts without weakening SSH host identity checks or silently changing auth. Estimate: 3–5 engineering days including real Tailscale and NetBird mode tests.
Priority: Next milestone.
2026-10-04 owner decisions: The owner asked to detect the SSH banner and use network auth with a Trust step. This matches the machine-policy path. A banner alone cannot prove which NetBird mode is enabled; NetBird's documented default is JWT, so the implementation must distinguish that from machine-identity mode.
Report: arch-review report
Source: arch-review 2026-10-04
Starting self-install-merge on self-install at
5b5cf987fc; merging dev87bb5bd2b7. Retain network/key SSH auth and pins with delegated infraternal agent install/uninstall. Requested checks only; no push.Conflict reconciliation: kept dev decisions §§31–43 and renumbered self-install to §44. Retained banner detection, none-auth admission, explicit trust, auth override and exact pin checks. InstallRemote now combines the fixed per-job auth with delegated install token delivery; start only confirms readiness; removal delegates uninstall using the same auth. Worker fake records auth through every remote operation. Replaced the obsolete dummy-binary linger regression with real compiled-CLI reenrollment checks in the full integration scenario, and run that scenario against both real OpenSSH key auth and a loopback russh none-auth server executing as sshtarget. The loopback server records offered methods, so the complete network installation asserts no public key was offered. Updated stale install/start documentation after the textual auto-merge. No new hot path.
Conflict reconciliation: kept dev decisions §§31–43 and renumbered self-install to §44. Retained banner detection, none-auth admission, explicit trust, auth override and exact pin checks. InstallRemote now combines the fixed per-job auth with delegated install token delivery; start only confirms readiness; removal delegates uninstall using the same auth. Worker fake records auth through every remote operation. Replaced the obsolete dummy-binary linger regression with real compiled-CLI reinstall checks in the full integration scenario, and run that scenario against both real OpenSSH key auth and a loopback russh none-auth server executing as sshtarget. The loopback server records offered methods, so the complete network installation asserts no public key was offered. Updated stale install/start documentation after the textual auto-merge. No new hot path.
Network SSH can omit pam_systemd and XDG_RUNTIME_DIR. Install, readiness and removal now preserve an existing runtime path or use /run/user/; the loopback fixture intentionally has no PAM session or runtime environment, so it tests that fallback. Source: https://www.freedesktop.org/software/systemd/man/latest/pam_systemd.html . Initial clippy found items_after_statements in the new test import; fixed by moving it to module imports. Install suite passed: cargo test: 56 passed, 4 ignored, 295 filtered out (15 suites, 8.34s).
Real network installation exposed two PAM-less startup issues in delegated self-install: show-user fails when no logind user object exists, and enable-linger starts its manager asynchronously. Self-install now confirms absent users through a successful live list-users query (malformed listing or failed bus queries fail closed), then waits up to ten seconds for a real user-manager bus reply before daemon-reload. Environment replies are discarded without logging. The same readiness helper serves server and infraternal agent installation. Sources: https://github.com/systemd/systemd/blob/main/src/login/loginctl.c and https://github.com/systemd/systemd/blob/main/man/loginctl.xml .
The expanded ignored compiled-binary test now passes both OpenSSH key mode and loopback network none mode, each with real sshtarget systemd service, enrollment, mTLS tunnel, inventory and delegated uninstall. Network mode authorizes no install key and asserts no publickey attempt. Linger ownership failure/reinstall/removal coverage was moved here from the obsolete dummy-binary bootstrap test. Latest output:
sshtarget authorized_keys restored using sudo -n cp -a; sudo -n cmp returned exit 0. Final-source clippy and verify fast are running. No merge gate or push.
Final-source fast gate failed in unchanged crates/server/src/stream.rs timing coverage; the initial run passed. The final run warned load5 above the 8 online CPUs. No test changes made. Rerunning the same required gate. Exact failure excerpt:
Merged
dev(87bb5bd2b7) intoself-install(base5b5cf987fc). Head:bc828c8b3cde57c2f7f3533131039d22f6cf1eb1. Nothing pushed.Conflict resolutions:
DECISIONS.md: retained dev §§31–43 and appended the self-install decision as §44.crates/server/src/install.rs: retained dev's connect/banner/auth/host-key flow and self-install's token mint/delivery/enrollment during Install. Start confirms service readiness. Pass job.auth through all delegated operations and retries.crates/server/src/install_bootstrap.rs: combined auth selection/error classification with delegatedagent install/agent uninstall, preserving exact pins and ownership checks. The obsolete dummy-binary linger test was moved into the compiled CLI integration scenario. Network loopback upload/refusal coverage remains.crates/server/src/install_worker_tests.rs: token-delivery/enrollment hooks remain on Install; the fake records auth on install, start, upload, observe, probe and remove. Existing network/key override, retry, authorization-loss and host-key tests retained.Fresh PAM-less network SSH needed three setup fixes: runtime-directory fallback before delegated service operations; successful live logind listing to distinguish an absent user object from bus errors; bounded user-manager readiness after enabling linger. The shared CLI readiness helper serves both server and infraternal agent installation. No new hot path. Sources: pam_systemd, loginctl source, loginctl manual source. DESIGN and contracts now describe delegated step ordering and auth behavior.
Tests:
cargo clippy --workspace --all-targets -- -D warnings: passed.cargo test -p infraternal-server install:cargo test: 56 passed, 4 ignored, 295 filtered out (15 suites, 8.34s).cargo test -p infraternal-server install -- --ignored: four real OpenSSH tests passed (trust, atomic upload, ownership fencing and convergent cleanup).cargo test -p infraternal-server real_network_auth -- --nocapture: two loopback tests passed (none-auth upload/removal, refusal and key-mode auth exclusivity).cargo test -p infraternal --test agent_install -- --ignored: passed, running the full installation scenario sequentially in both key and network modes. Both install a real sshtarget user service, enroll, establish mTLS, expose inventory, exercise linger ownership failure/reinstall and delegate uninstall. Network mode adds no install key and records no publickey attempt.sudo -n cp -aauthorized_keys backup restored withsudo -n cp -a;sudo -n cmppassed (exit 0).Gate: final-source
INFRATERNAL_VERIFY_RUN_ID=self-install-merge scripts/verify fastpassed all 19 stages in 380.861s (exit 0). No verify merge was run.Exact targeted test outputs:
install-ignored:network:real-install:clippy:An earlier final-source fast run failed in the unchanged
stream::tests::contended_native_close_fence_preserves_original_watcher_deadlinetest (native dispatch did not reach the database barrier by C+650: Elapsed(())) under a load warning. The same gate passed on rerun without changing any test or source. The existing cookie@0.6.0 low-severity advisory remains report-only. No new benchmark or performance claim: all additions are setup work.Exact final gate output:
Exact gate summary:
Final cleanup: the shared authorized_keys file changed again during the later gate run after the earlier successful restoration. No install test process remained active. Restored the job-start backup again with sudo -n cp -a and repeated sudo -n cmp successfully (exit 0). Head
bc828c8b3c; worktree clean; no push. Full report: /mnt/hdd/infraternal/jobs/self-install-merge/result.md.