ADR-0021: Host baseline and hardening¶
- Status: Accepted
- Date: 2026-08-17
- Deciders: El, Lachlan
- Supersedes: ADR-0014 §1 (in part), §2, §3
Context¶
ADR-0014 recorded nine unrelated decisions in one document, which meant no single part could be revised without reopening all of it. It is superseded by ADR-0021 through ADR-0027, one decision each. This ADR carries forward the host provider, sizing, SSH and firewall baseline substantially unchanged.
Decision¶
- Provider and region: Vultr, Melbourne (region per ADR-0008). Provider is an implementation detail chosen at provisioning time on price, specs and AU residency; region is not.
- Sizing: one host to start, resize on demand. Size for the shared core stack plus tenant stacks with Metabase overhead assumed, not discovered — roughly 2 GB per dashboard-paying tenant (ADR-0023). Dashboard clients, not automation clients, are what strain the box.
- SSH: key-only authentication, passwords disabled after keys are verified working; root SSH disabled; per-person accounts (
el,lachlan) each with their own key; non-standard port; fail2ban. - SSH private keys are never shared. Each person generates their own keypair and both public keys are deployed by the
baserole. A shared private key cannot be revoked for one person without locking out both, and destroys attribution in the logs. - Firewall: default-deny inbound. Only the SSH port, 80 and 443 open. Port 80 exists solely for the ACME challenge and the redirect to HTTPS. Everything else is internal to the host and never internet-exposed.
- Tailscale is deferred, with a trigger: adopt it when a third person needs shell access, or when the public SSH port becomes an accepted risk rather than a tolerated one. Until then the non-standard port plus fail2ban plus key-only auth is the control.
Consequences¶
The host is reproducible from Ansible with no hand-configured drift (ADR-0024). Per-person accounts preserve attribution in audit logs, which matters because the approval chain (ADR-0026) is evidence. Deferring Tailscale leaves a public SSH port open — accepted at two operators, and the deferral is written down rather than assumed.
Alternatives considered¶
- Password authentication retained as fallback — rejected: it is the fallback that gets brute-forced.
- Standard port 22 — kept as an option; the non-standard port is noise reduction, not security, and is not relied on as a control.
- Tailscale now — deferred: another dependency in the access path before it earns its place.