Docs: Explain transactional SSH hardening
This commit is contained in:
@@ -92,4 +92,17 @@ it against the real system.
|
|||||||
|
|
||||||
## Root work
|
## Root work
|
||||||
|
|
||||||
Never bare `sudo` — load the `panama-sudo` skill. Migrations already follow the rule.
|
Never bare `sudo`. Load the `panama-sudo` skill first. Migrations already follow the rule.
|
||||||
|
|
||||||
|
`boot --server` is the one exception where a new Fedora VPS may begin as root.
|
||||||
|
Before it offers SSH hardening, it copies a safe root key when possible or
|
||||||
|
verifies the target key. The target user's `.ssh` must be owned by that user at
|
||||||
|
`0700`, and `authorized_keys` must be owned by that user at `0600`. Without a
|
||||||
|
verified target key, SSH hardening is unavailable and the bootstrap continues.
|
||||||
|
|
||||||
|
Accepted hardening uses an atomic same-directory `sshd_config.d` drop-in,
|
||||||
|
runs `sshd -t`, then reloads the detected SSH unit. Validation or reload
|
||||||
|
failure restores the previous drop-in before it retries validation and reload;
|
||||||
|
failed recovery stops the handoff with manual recovery instructions. The
|
||||||
|
fixture contracts exercise those branches. `panama test --safe` never reloads
|
||||||
|
a live daemon, so it is not live-host proof.
|
||||||
|
|||||||
@@ -41,9 +41,22 @@ question entirely:
|
|||||||
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) --server
|
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) --server
|
||||||
```
|
```
|
||||||
|
|
||||||
That command also works from a brand-new VPS's **root** login: it creates
|
That command also works from a brand-new VPS's **root** login. It creates or
|
||||||
your user with sudo, moves the SSH key over, offers to harden sshd, and hands
|
reuses your sudo-enabled user, then copies a safe root key when it can or
|
||||||
off to a normal install as that user.
|
verifies the target key before offering SSH hardening. A verified target key
|
||||||
|
means the target user owns `.ssh` with mode `0700` and `authorized_keys` with
|
||||||
|
mode `0600`. SSH hardening is unavailable without a verified target key, and
|
||||||
|
the install continues without it.
|
||||||
|
|
||||||
|
When you accept hardening, Panama makes an atomic same-directory drop-in,
|
||||||
|
validates the complete SSH configuration with `sshd -t`, then reloads the
|
||||||
|
detected SSH unit. If validation or reload fails, it restores the previous
|
||||||
|
drop-in and validates and reloads that restored configuration; recovery that
|
||||||
|
cannot complete stops the handoff and prints the manual recovery command. The
|
||||||
|
fixture contracts exercise these branches. No real daemon reload runs under
|
||||||
|
`panama test --safe`, so that suite is not live-host proof.
|
||||||
|
|
||||||
|
After that, it hands off to a normal install as the new user.
|
||||||
|
|
||||||
`install` asks its questions first and then runs the stages in `setup/scripts/`
|
`install` asks its questions first and then runs the stages in `setup/scripts/`
|
||||||
in order, without stopping again:
|
in order, without stopping again:
|
||||||
@@ -198,7 +211,7 @@ docs/ Settings reference, and the design specs behind the work
|
|||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
186 of them, under `tests/`. `tests/contracts.manifest` classifies every
|
187 of them, under `tests/`. `tests/contracts.manifest` classifies every
|
||||||
contract by the capabilities it needs. Run the hermetic set, or grant a
|
contract by the capabilities it needs. Run the hermetic set, or grant a
|
||||||
specific external capability when automation needs it:
|
specific external capability when automation needs it:
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,42 @@ elif (( claimed != actual )); then
|
|||||||
note "the README says $claimed contracts; there are $actual"
|
note "the README says $claimed contracts; there are $actual"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Root server bootstrap ───────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# This path runs before the repository exists on a fresh VPS. Its safety
|
||||||
|
# properties need to be stated beside the public `boot --server` example, not
|
||||||
|
# inferred from the shell implementation or buried in a fixture.
|
||||||
|
|
||||||
|
bootstrap_doc="$(sed -n '/^That command also works from a brand-new VPS/,/^`install` asks/p' "$readme" | tr '\n' ' ')"
|
||||||
|
|
||||||
|
require_bootstrap_doc() {
|
||||||
|
local pattern="$1" explanation="$2"
|
||||||
|
grep -qiE "$pattern" <<<"$bootstrap_doc" || note "$explanation"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_bootstrap_doc 'verified target key' \
|
||||||
|
'the root bootstrap docs do not require a verified target key'
|
||||||
|
require_bootstrap_doc '700.*600|600.*700' \
|
||||||
|
'the root bootstrap docs do not state the exact SSH ownership and modes'
|
||||||
|
require_bootstrap_doc 'hardening (is )?unavailable.*(without|until).*key' \
|
||||||
|
'the root bootstrap docs do not say hardening is unavailable without a key'
|
||||||
|
require_bootstrap_doc 'sshd -t' \
|
||||||
|
'the root bootstrap docs do not name sshd -t validation'
|
||||||
|
require_bootstrap_doc 'atomic.*same.directory|same.directory.*atomic' \
|
||||||
|
'the root bootstrap docs do not describe the atomic same-directory drop-in'
|
||||||
|
require_bootstrap_doc 'detected (SSH )?unit.*reload|reload.*detected (SSH )?unit' \
|
||||||
|
'the root bootstrap docs do not describe reloading the detected SSH unit'
|
||||||
|
require_bootstrap_doc 'restores? (the )?previous drop-in.*(validation|reload)|(validation|reload).*restores? (the )?previous drop-in' \
|
||||||
|
'the root bootstrap docs do not promise rollback on validation or reload failure'
|
||||||
|
require_bootstrap_doc 'fixture contracts.*(these|this) (path|branch)|fixture contracts.*test' \
|
||||||
|
'the root bootstrap docs do not limit proof to fixture contracts'
|
||||||
|
require_bootstrap_doc 'no real daemon reload.*panama test --safe|panama test --safe.*no real daemon reload' \
|
||||||
|
'the root bootstrap docs imply a live daemon reload under the safe suite'
|
||||||
|
|
||||||
|
if grep -qiE 'merely writes? (the )?(SSH )?(drop-in|file)|reload failure.*ignored|ignores? .*reload failure' <<<"$bootstrap_doc"; then
|
||||||
|
note 'the root bootstrap docs weaken the transaction by treating the write or reload failure as harmless'
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Documented subcommands exist ─────────────────────────────────────────────
|
# ── Documented subcommands exist ─────────────────────────────────────────────
|
||||||
#
|
#
|
||||||
# A README listing a command the dispatcher does not have sends somebody to a
|
# A README listing a command the dispatcher does not have sends somebody to a
|
||||||
|
|||||||
Reference in New Issue
Block a user