Files
home-network-k3s/docs/00-vision-and-scope.md
T
jakman85andClaude Opus 5.5 18f7ba8d0f docs: apply the operator's rulings on Kasm, revocation and fault injection
Retire Kasm from the catalog. Drop ACME revocation from R-TLS-02. Make L3
fault injection operator-run and exclude it from the merge gate (R-TEST-03,
ADR-0026). Update the gap register to match; Homepage authentication is now
ruled must-enforce and stays a gap until the implementation lands.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 23:06:26 -06:00

15 KiB
Raw Blame History

00 — Vision & Scope

Vision

Build a home platform that behaves like a small private cloud. An operator declares a service — a container app or a virtual machine — in git, and the platform provisions it, secures it, exposes it under a trusted TLS URL, routes its traffic on the correct WAN, protects its data, updates it automatically, and reports on its health. Onboarding a new service is a pull request against a catalog, not a weekend of manual work.

The platform runs as one live environment: prod, on 3 bare-metal mini-PCs (ADR-0017). The dev/test cluster that proved its viability was decommissioned in 2026-09; every change reaches prod through the PR gate and Flux.

Personas

  • Operator (primary user): runs the home network; wants to onboard/offboard services with minimal ceremony and zero data loss.
  • Platform (the system): reconciles declared state, enforces isolation and egress policy, renews certificates, updates workloads, and raises alerts.
  • Implementation agents: the AI teams building the platform from this spec.

In scope

  • A k3s-based platform with distributed storage (Longhorn) across 3 nodes.
  • Container workloads (PaaS) and VM workloads (IaaS) through one Kubernetes surface.
  • GitOps delivery, automated updates, trusted TLS, DNS, ingress.
  • Network isolation (default-deny east-west) and declared egress classes, including VPN routing.
  • Observability with email + dashboard alerting.
  • A command-and-control web UI at the root of home.keithjackson.dev.
  • The service catalog (see 13-service-catalog.md).

Out of scope (for now)

  • Multi-tenant / multi-operator RBAC beyond a single operator + platform automation.
  • Public multi-user SaaS concerns (billing, per-tenant isolation beyond network policy).
  • Non-keithjackson.dev domains.

The domain & DNS model

  • Public apex *.keithjackson.dev is available in Cloudflare DNS. public services (catalog exposure: public or a registered platform route) under *.home.keithjackson.dev are published through a Cloudflare Tunnel (proxied records, no inbound 80/443 at the edge — ADR-0016); the network's public IP stays in use for WireGuard and Plex only.
  • All platform services live under *.home.keithjackson.dev.
  • Each service is reachable at <service>.home.keithjackson.dev (e.g. plex.home.keithjackson.dev).
  • The root home.keithjackson.dev serves the Command & Control (C2) center UI.

Requirements (stable IDs)

Requirement IDs are stable references used across ADRs, specs, the task board, and PRs. MUST is mandatory; SHOULD is strongly preferred and requires an ADR to deviate.

Platform & API surface — R-PLAT-*

  • R-PLAT-01 — The platform MUST run on k3s across 3 nodes with production-grade HA control plane in prod.
  • R-PLAT-02 — Container workloads MUST be onboarded and managed declaratively via the Kubernetes API, kubectl-class CLI, and YAML.
  • R-PLAT-03 — Virtual-machine workloads MUST be created, managed, and destroyed through the same Kubernetes API/CLI/YAML surface as containers (no separate hypervisor management plane for application VMs).
  • R-PLAT-04 — The platform MUST support create / destroy / rebuild of any workload on demand.

GitOps & delivery — R-GITOPS-*

  • R-GITOPS-01 — All application and platform desired state MUST be defined in git and reconciled automatically (pull-based GitOps).
  • R-GITOPS-02 — Onboarding a new service MUST be expressible as a change to a versioned catalog in git.
  • R-GITOPS-03 — The system MUST detect and correct drift between git and cluster state.

Networking, isolation & egress — R-NET-*

  • R-NET-01 — East-west traffic between services MUST be denied by default; communication is allowed only by explicit, port-level configuration (firewall-like).
  • R-NET-02 — Allow rules MUST be declarative, reviewable in git, and scoped per source → destination → port/protocol.
  • R-NET-03 — Networks MUST be configurable and isolatable (segments/namespaces with enforced boundaries).
  • R-NET-04 — The platform MUST support multiple egress paths selected by routing rules. Per OQ-1 the environment has one physical commercial WAN and no multi-ISP plans, so this is realized as two paths — the local internet path and the in-cluster vpn path — not multi-ISP routing. Physical multi-WAN (multiple ISP uplinks) is out of scope unless a future ADR reopens it.
  • R-NET-05 — A service MUST be able to declare its egress class: internet (standard local network/internet) or vpn (routed through a custom VPN connection). VPN routing MUST be enforced by a single shared node-level gateway outside the service (ADR-0015, ADR-0020), so a service cannot leak by misconfiguration (OQ-3).
  • R-NET-06 — VPN-class egress MUST enforce a kill-switch: if the VPN tunnel is down, the service MUST NOT leak traffic to the standard internet.
  • R-NET-07 — Egress class MUST be a declarative property of the service, changeable via GitOps without re-architecting the workload.

Storage & state — R-STATE-*

  • R-STATE-01 — Stateful data MUST survive destroy/rebuild of the workload (PaaS and IaaS).
  • R-STATE-02 — Persistent storage MUST be distributed/replicated across the 3 nodes (Longhorn) so a single node loss does not lose data.
  • R-STATE-03 — The platform MUST provide scheduled backups to an off-cluster target and a tested restore path (disaster recovery).
  • R-STATE-04 — Bulk media storage (Plex library) MUST have a capacity strategy distinct from replicated app-config storage (replicating multi-TB media 3× is out of scope; see ADR-0003).

Automated updates — R-UPD-*

  • R-UPD-01 — Services MUST update to the latest stable versions on a schedule.
  • R-UPD-02 — Updates in the allowed classes MUST occur with no human, no AI, and no hand-authored GitOps change; automation acting on declarative policy opens machine-authored changes through the merge gate. Major versions and operator-designated blast-radius components MAY wait for human review of the machine-authored change.
  • R-UPD-03 — Update policy MUST be per-service configurable (cadence, stability channel, pin/hold, auto-rollback on failed health).

TLS & certificates — R-TLS-*

  • R-TLS-01 — Every externally reachable service MUST present TLS from a credible, trusted, non-self-signed authority.
  • R-TLS-02 — Certificates MUST be automatically issued and renewed without manual steps.
  • R-TLS-03 — Certificate issuance MUST work for internal-only services (no requirement to expose a service publicly just to validate a certificate).

DNS & ingress — R-DNS-*

  • R-DNS-01 — Services MUST be reachable at <service>.home.keithjackson.dev.
  • R-DNS-02 — DNS records MUST be managed automatically from declared service intent.
  • R-DNS-03 — Internal clients MUST resolve service names correctly (split-horizon where public and internal answers differ).
  • R-DNS-04 — public HTTP(S) services MUST be reachable from the internet without inbound 80/443 port-forwarding at the edge, and LAN clients MUST reach them correctly whichever resolver answers (public or internal) — no dependency on NAT hairpin (ADR-0016).
  • R-DNS-05 — Only services declared public (catalog exposure: public or a registered platform route) MAY be reachable through the public ingress path. A request for a LAN/VPN-only hostname at that path MUST be refused (HTTP 404). internal services MUST have no public record, except non-HTTP L4 names, which MAY hold DNS-only records at LAN addresses (ADR-0016).

Observability & alerting — R-OBS-*

  • R-OBS-01 — Services MUST be monitored (metrics, logs, health).
  • R-OBS-02 — Issues MUST be reported by email.
  • R-OBS-03 — Issues and health MUST be visible on dashboards.
  • R-OBS-04 — The platform MUST alert on its own health (nodes, storage, GitOps reconciliation, certificate expiry, VPN tunnel state, backup success).

Command & control — R-C2-*

  • R-C2-01 — The root home.keithjackson.dev MUST serve a UI that surfaces the services running in the cluster and links to them.
  • R-C2-02 — The C2 UI MUST surface platform health (cluster, storage, GitOps, alerts) and provide controlled operational actions where safe.

Security & secrets — R-SEC-*

  • R-SEC-01 — Secrets MUST NOT be stored in plaintext in git; they MUST be encrypted at rest in the repo and decrypted only in-cluster.
  • R-SEC-02 — The platform MUST follow least-privilege for workload identities and network reach.
  • R-SEC-03 — All the above properties MUST be demonstrable/auditable (an operator can prove isolation, egress path, cert validity, and backup integrity).
  • R-SEC-04 — The Kubernetes API MUST NOT be reachable from the public internet by any path (no tunnel route, no edge forward, no public DNS record); it is LAN/VPN-only (ADR-0016).

Identity & access (SSO) — R-IDP-*

  • R-IDP-01 — The platform MUST provide a central Identity Provider (SSO) as the single user directory and login for platform services.
  • R-IDP-02 — Services MUST authenticate against the IdP — natively via OIDC where supported, or behind an identity-aware (forward-auth) proxy otherwise. No management UI may be exposed unauthenticated on the network. (Documented exceptions: Plex/Seerr use Plex auth; Minecraft uses Mojang/Microsoft; UniFi uses its native login on its own L4 VIP; the read-only runbooks at /runbooks carry no login; Crafty web uses forward-auth plus its own local login, no OIDC.)
  • R-IDP-03 — Identity configuration (realms, clients, groups, roles) MUST be declarative and GitOps-managed, not console-only.
  • R-IDP-04 — IdP secrets (admin credential, OIDC client secrets) MUST be SOPS-encrypted; MFA MUST be available to all users and required for privileged access.
  • R-IDP-05 — The IdP MUST be treated as DR-critical (replicated + off-cluster-backed datastore) with a documented break-glass path so an IdP outage does not lock the operator out of recovery tools.
  • R-IDP-06 — Access MUST be least-privilege via groups/roles; sensitive surfaces (C2, cluster console, alerting) require an authenticated user in an authorized group, not merely "logged in."

Environments — R-ENV-*

  • R-ENV-01 — Nodes MUST be baselined, cluster-joined and managed as code; machine creation on bare metal is an imaged, checklist-driven step.
  • R-ENV-02 — GitOps configuration MUST be authored once as a base plus environment-scoped overlay; any future environment MUST need overrides only.
  • R-ENV-03 — Production runs on 3× mini-PC bare metal. Changes MUST reach it only through the PR gate and Flux.

Conformance testing & governance — R-TEST-*

  • R-TEST-01 — Every requirement MUST be verified by automated, behavior-based tests (Given/When/Then style) that assert observable system behavior, not implementation internals.
  • R-TEST-02 — Tests MUST be reproducible: deterministic, hermetic (create and tear down their own fixtures), version-pinned, and runnable by a single command locally and in CI against any conforming cluster, producing machine-readable, requirement-tagged results.
  • R-TEST-03 — A conformance suite MUST gate delivery: merges are blocked unless the tests for the touched requirements pass, and phase exits are blocked unless the phase's full suite passes. "Demonstrated" means "the automated test passes," never a manual one-off. Fault-injection tests (R-TEST-05) are not automated: the operator runs them deliberately and records the result, and they do not gate individual merges (ADR-0026).
  • R-TEST-04 — Tests MUST be traceable: each test declares the requirement ID(s) it verifies, and a coverage report maps every R-* requirement to its verifying test(s). Uncovered requirements are a gap to close, not an acceptable state.
  • R-TEST-05 — Safety-critical behaviors (default-deny, VPN kill-switch, data-survival on rebuild, DR restore, auto-rollback) MUST be verified by fault-injection behavior tests that prove fail-closed / no-data-loss outcomes, not merely happy-path checks.
  • R-TEST-06 (governance) — AI agents MUST NOT modify the specifications (this docs/ tree, the requirements, or accepted ADRs). Specs are changed only by the human operator/architect. Agents that find a spec wrong, blocking, ambiguous, or missing MUST stop and escalate and MAY draft a proposal, but MUST NOT self-approve or merge a spec/ADR change (see AGENTS.md §2 and §11).

Acceptance philosophy

Each requirement class maps to an automated, reproducible, behavior-based conformance test (R-TEST-*). "Done" means the conformance test for the touched requirements passes — a green, reproducible result traced to requirement IDs — never "manifest merged" and never a manual demonstration. The testing approach is specified in docs/14-testing-and-conformance.md and ADR-0010; the gate checklist lives in agents/definition-of-done.md.

Governance: the specifications are human-owned and immutable to agents (R-TEST-06). Agents implement against the spec and prove conformance with tests; they never edit the spec to fit the implementation.

Open questions

Resolved

  • OQ-1 (WAN / edge) — RESOLVED: one commercial WAN, no multi-ISP plans; dumb SOHO edge (no VLAN/VPN/services). All segmentation + VPN in-cluster; edge does NAT + port-forward only. Physical multi-WAN out of scope. See 03, 09. Amended 2026-11-08 (ADR-0016): public web ingress moved to an outbound-only Cloudflare Tunnel; the edge no longer forwards 80/443. Its remaining forwards are WireGuard udp/51820 and Plex tcp/32400.

  • OQ-2 (bulk media) — RESOLVED (ADR-0018): Plex bulk media lives outside the cluster on a standalone TrueNAS NFS server on the production LAN, and sits outside platform backup. Plex's metadata DB still lives on replicated Longhorn. See 04.

  • OQ-3 (VPN) — RESOLVED: PIA over OpenVPN-UDP (non-TCP; ADR-0013). Egress is a node-level host tunnel steered by Cilium Egress Gateway, failing closed under Cilium's own enforcement (ADR-0015, ADR-0020) — vpn-class pods routed through it, rules enforced outside the service. See 03.

  • OQ-4 (TLS/DNS challenge access) — RESOLVED: a scoped Cloudflare API token (Zone·DNS·Edit, keithjackson.dev), SOPS-encrypted, drives cert-manager DNS-01 and ExternalDNS. The static *.keithjackson.dev wildcard covers reachability but not TXT-challenge writes; the token handles issuance + record automation. Operator provides the token once. See 08.

  • OQ-BKP (off-cluster DR backup target) — RESOLVED (ADR-0018): Cloudflare R2 stores Velero backups (kopia file-system volume data) and CNPG Barman archives of the irreplaceable tier; Longhorn has no backup target of its own. See 04.

Still open

None tracked here. Unmet requirements are recorded in known gaps.