From 7775f4de74044c17965fd9202b760bfe0ef065fa Mon Sep 17 00:00:00 2001 From: Garrett Allen <98648590+Gerrrt@users.noreply.github.com> Date: Fri, 13 Nov 2026 16:27:08 -0800 Subject: [PATCH 1/2] docs(playground): make gandalf's SSH keys-only, and check it every session MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Proxmox installer leaves sshd taking root's password, and on gandalf only the unwatched host firewall keeps that off VLAN 30. §4 gains a step that writes /etc/ssh/sshd_config.d/10-keys-only.conf and proves from Hicks that a password is refused and a key still works; §7's per-session read-back checks it. Root's password stays for 8006 and the console. Co-Authored-By: Claude Opus 5.5 --- docs/changelog.md | 10 ++++++ docs/runbooks/build-the-playground.md | 50 +++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 2f2fc079..81190483 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -19,6 +19,16 @@ docstring gives: it is a record, not a claim about now. ## 2026-11-13 +- **`gandalf`'s SSH takes keys only.** A read-only audit of `gandalf` found + `sshd` taking root's password (`permitrootlogin yes`, + `passwordauthentication yes`), which is the Proxmox installer's default. Only + the host firewall kept that off VLAN 30, and on `gandalf` nothing watches the + firewall. `build-the-playground.md` §4 gains *SSH on `gandalf`: keys only*. + That step writes `/etc/ssh/sshd_config.d/10-keys-only.conf` and proves from + Hicks that a password is refused and a key still works. §7's per-session + read-back now checks it too. Root's password stays set, for `8006` and the + console. Not yet applied on `gandalf`. + - **An audit of `golem`, read-only, found its last verify failed and a 19-day gap in the lab's backups.** It was read on the box against this repository at `2276e75`. diff --git a/docs/runbooks/build-the-playground.md b/docs/runbooks/build-the-playground.md index 2e60b9f8..59af9b22 100644 --- a/docs/runbooks/build-the-playground.md +++ b/docs/runbooks/build-the-playground.md @@ -582,6 +582,50 @@ stop`, wait for `PveFirewallDisabled` to fire (about fifteen minutes, with the five-minute timer), then `pve-firewall start` and watch it resolve. A rule that has never fired is a rule nobody knows can. +### SSH on `gandalf`: keys only + +The firewall above lets `22` in from Hicks alone. Behind it, Proxmox's +installer leaves `sshd` taking root's password: `PermitRootLogin yes` in +`/etc/ssh/sshd_config`, and Debian's `PasswordAuthentication` default of +`yes`. On `gandalf` nothing watches whether the firewall is on (§7), so if it +ever goes off, the root password is all that stands between VLAN 30, where the +attack VM is, and a root shell on the range's isolation host. Keys only takes +that away. An audit on 2026-11-13 found both still on. + +Root's password stays set. The `root@pam` login on `8006` uses it, and so does +the console on KVM port 4. Only SSH stops taking it. + +Before the change, from Hicks, confirm that a key opens a root shell +(`ssh -o PasswordAuthentication=no root@10.0.30.30 true`), and keep that +session open until the end. Then on `gandalf`, as root: + +```bash +printf '%s\n' \ + '# build-the-playground.md §4: keys only. Root logs in by key, never by password.' \ + 'PermitRootLogin prohibit-password' \ + 'PasswordAuthentication no' \ + 'KbdInteractiveAuthentication no' \ + > /etc/ssh/sshd_config.d/10-keys-only.conf +sshd -t && systemctl reload ssh +sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication) ' +``` + +**You should see** `permitrootlogin without-password` (`sshd -T`'s name for +`prohibit-password`), `passwordauthentication no` and +`kbdinteractiveauthentication no`. The drop-in wins over the main file's +`PermitRootLogin yes` because `Include` comes first in `sshd_config` and +`sshd` keeps the first value it reads. Then, from Hicks, a password login must +be refused while a key login still works: + +```bash +ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password root@10.0.30.30 true +ssh -o PasswordAuthentication=no root@10.0.30.30 true +``` + +The first should fail with `Permission denied (publickey)`, offering no +password prompt. The second should succeed. If it fails, the session you kept +open is the way back: remove the drop-in and `systemctl reload ssh`. + --- ## 5. The attack VM @@ -807,8 +851,10 @@ that keep `Saruman`'s firewall on do not reach `gandalf`, because ADR-0017 gives it no agent. So the check §4 hands to Prometheus on `Saruman` is a step here, once per session. `pve-firewall status` should read `enabled/running`, and §4's probe from `morpheus`, aimed at `10.0.30.30`, should give `8006 exit=1` and -`control exit=0`. Any other answer means the session does not start until §4 -has been rerun. +`control exit=0`. `sshd -T | grep -E '^(permitrootlogin|passwordauthentication) '` +should read `without-password` and `no`, because an upgrade that replaces +`sshd_config.d` would be as silent as one that rewrites the firewall. Any other +answer means the session does not start until §4 has been rerun. --- From 535b429097f4fa50499e3c9ff81495a9bcc9a5f3 Mon Sep 17 00:00:00 2001 From: Garrett Allen <98648590+Gerrrt@users.noreply.github.com> Date: Fri, 13 Nov 2026 22:43:02 -0800 Subject: [PATCH 2/2] docs(gandalf): keep an interactive SSH session open as the way back The step told the operator to confirm key login with `ssh ... true`, which runs and disconnects, so there was no kept session to roll back from. Open an interactive key-only shell instead, make the change in it, and run the login checks from a second terminal. Co-Authored-By: Claude Opus 5.5 --- docs/runbooks/build-the-playground.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/runbooks/build-the-playground.md b/docs/runbooks/build-the-playground.md index 4b83b217..4d76d99f 100644 --- a/docs/runbooks/build-the-playground.md +++ b/docs/runbooks/build-the-playground.md @@ -595,9 +595,17 @@ that away. An audit on 2026-11-13 found both still on. Root's password stays set. The `root@pam` login on `8006` uses it, and so does the console on KVM port 4. Only SSH stops taking it. -Before the change, from Hicks, confirm that a key opens a root shell -(`ssh -o PasswordAuthentication=no root@10.0.30.30 true`), and keep that -session open until the end. Then on `gandalf`, as root: +Before the change, open a root shell on `gandalf` from Hicks with a key alone, +and leave it open until the end: + +```bash +ssh -o PasswordAuthentication=no root@10.0.30.30 +``` + +It has no trailing command, so it stays an interactive shell. It is the way +back if the reload locks new logins out, because `sshd` keeps sessions that +are already open. Run the change below in that shell, and run the login checks +after it from a second terminal on Hicks. As root on `gandalf`: ```bash printf '%s\n' \ @@ -623,8 +631,8 @@ ssh -o PasswordAuthentication=no root@10.0.30.30 true ``` The first should fail with `Permission denied (publickey)`, offering no -password prompt. The second should succeed. If it fails, the session you kept -open is the way back: remove the drop-in and `systemctl reload ssh`. +password prompt. The second should succeed. If it fails, go back to the shell +you kept open, remove the drop-in, and run `systemctl reload ssh`. ---