Files
home-network-k3s/agents/task-board.md
T
jakman85andClaude Opus 4.8 a2cbdf656d Resolve OQ-1/2/3, refine OQ-4: single ExpressVPN gateway, single WAN, external media
Operator answers folded into the specs:
- OQ-3 VPN: ExpressVPN, cluster-controlled SINGLE shared in-cluster tunnel
  (OpenVPN UDP / non-TCP), rules enforced outside the service. New ADR-0012
  supersedes ADR-0008 (Gluetun-sidecar default dropped). Central kill-switch.
- OQ-1 WAN/edge: one commercial WAN, no multi-ISP plans; dumb SOHO edge (no
  VLAN/VPN/services). Multi-WAN out of scope; segmentation + VPN in-cluster;
  edge = NAT + manual port-forward. Gateway VIP resolved to Cilium L2
  announcement. T-3.3 marked won't-do.
- OQ-2 storage: bulk media lives outside the cluster (backing TBD, non-blocking)
  via a 'bulk' external-mount indirection; Plex metadata DB stays on Longhorn.
  Split out a separate OQ-BKP for the off-cluster DR backup target (Phase 4).
- OQ-4 refined: wildcard record covers reachability but NOT ACME DNS-01 (needs
  TXT-write access) and does not match *.home.* depth. Still OPEN: Cloudflare
  API token (Option A) vs acme-dns delegation (Option B). T-2.4/T-2.5 blocked.

Updated: docs 00,01,03,04,08,09; ADR-0008/0012 + index; task board.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-15 23:00:11 -05:00

105 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Task Board
The live who's-doing-what. Agents **claim** an item (set Owner + Status) before starting, respect
`Blocked-by`, and mark `done` only after its **automated, reproducible behavior test passes green**
([`definition-of-done.md`](definition-of-done.md), [`../docs/14-testing-and-conformance.md`](../docs/14-testing-and-conformance.md)).
Seeded from [`../roadmap/phases.md`](../roadmap/phases.md) + [`../roadmap/workstreams.md`](../roadmap/workstreams.md).
> **This board is the one working surface agents may edit** (claim items, update status, add
> items/escalations). The specs, ADRs, and roadmap are **not** editable by agents (R-TEST-06) —
> raise spec problems here as an `OQ-*` escalation for the human. Every "**Prove …**" task below is
> an automated conformance test (co-owned with **WS-TEST**), not a manual demo.
**Status values:** `todo` · `in-progress` · `blocked` · `review` · `done`
**Add new items** at the bottom of the relevant phase; keep IDs stable.
---
## Phase 0 — Foundations
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-0.1 | Create implementation repo structure (platform/apps/catalog/clusters) | WS-GITOPS | R-GITOPS-02 | — | — | todo |
| T-0.2 | CI: lint + schema validation + build/dry-run gates | WS-GITOPS | R-GITOPS-01 | T-0.1 | — | todo |
| T-0.3 | Author ServiceDefinition schema + renderer contract | WS-GITOPS | R-GITOPS-02 | T-0.1 | — | todo |
| T-0.4 | Conformance harness: **Chainsaw** runner + reproducibility contract + JUnit + coverage report + CI merge gate | WS-TEST | R-TEST-01/02/03/04 | T-0.1 | — | todo |
| T-0.5 | L0 **Kyverno** policy gate (default-deny present, no plaintext secrets, schema-valid ServiceDefinitions) | WS-TEST | R-TEST-01, R-NET-01, R-SEC-01 | T-0.4 | — | todo |
## Phase 1 — dev/test Cluster Bring-up
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-1.1 | OpenTofu libvirt module for 3 node VMs (+ Longhorn data disk) | WS-INFRA | R-ENV-01 | — | — | todo |
| T-1.2 | cloud-init baseline (users, SSH, sysctls, virt/Longhorn prereqs) | WS-INFRA | R-ENV-01 | T-1.1 | — | todo |
| T-1.3 | Ansible: k3s HA install, Cilium CNI, disable flannel/kube-proxy/Traefik | WS-INFRA | R-PLAT-01 | T-1.2 | — | todo |
| T-1.4 | Bootstrap Flux + SOPS age key | WS-GITOPS/WS-SEC | R-GITOPS-01, R-SEC-01 | T-1.3 | — | todo |
| T-1.5 | Prove node destroy/rebuild from IaC (no data loss) | WS-INFRA | R-ENV-01, R-STATE-01 | T-1.4 | — | todo |
## Phase 2 — Platform Core (net/storage/TLS/DNS/ingress)
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-2.1 | Longhorn (3-replica StorageClass) + `bulk` external-mount indirection (media lives off-cluster, backing TBD — OQ-2 resolved) | WS-STORAGE | R-STATE-02/04 | T-1.4 | — | todo |
| T-2.2 | Default-deny network baseline (per-namespace) + Hubble | WS-NET | R-NET-01/03 | T-1.3 | — | todo |
| T-2.3 | Render `dependencies` → CiliumNetworkPolicy from ServiceDefinition | WS-NET/WS-GITOPS | R-NET-02 | T-0.3, T-2.2 | — | todo |
| T-2.4 | cert-manager + Let's Encrypt DNS-01 wildcard `*.home.keithjackson.dev` (**blocked on OQ-4**: Cloudflare token vs acme-dns) | WS-SEC | R-TLS-01/02/03 | T-1.4, OQ-4 | — | blocked |
| T-2.5 | ExternalDNS + Gateway API listeners (VIP via **Cilium L2 announcement**) + split-horizon (PiHole) foundation | WS-NET | R-DNS-01/02/03 | T-2.4 | — | todo |
| T-2.6 | Prove: default-deny (DNS-only probe), PVC survives rebuild, trusted cert, auto-DNS | WS-NET/STORAGE/SEC | R-NET/STATE/TLS/DNS | T-2.1..2.5 | — | todo |
| T-2.7 | Deploy **Kyverno in-cluster as admission enforcer** (same policies as the CI L0 gate) | WS-TEST/WS-SEC | R-SEC-02, R-NET-01, R-SEC-01 | T-1.4, T-0.5 | — | todo |
## Phase 3 — Egress & VPN (single WAN; no multi-WAN — OQ-1)
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-3.0 | L3 fault-injection harness — **in-cluster Chainsaw Job** (CI-triggered, scoped test SA) using `script`/`try`/`finally` (force tunnel down, kill node, inject bad image, trigger restore) | WS-TEST | R-TEST-05, R-SEC-02 | T-0.4 | — | todo |
| T-3.1 | Egress classes; Cilium Egress Gateway wiring (steer `vpn` pods → gateway) | WS-NET | R-NET-04/05 | T-2.2 | — | todo |
| T-3.2p | **Prereq:** obtain ExpressVPN manual OpenVPN-UDP config + manual creds; store SOPS-encrypted | WS-SEC | R-NET-05 | — | — | todo |
| T-3.2 | **Single shared in-cluster ExpressVPN gateway** (OpenVPN UDP, active/standby) + centrally-enforced kill-switch (ADR-0012) | WS-NET | R-NET-05/06 | T-3.1, T-3.2p | — | todo |
| ~~T-3.3~~ | ~~Edge-router multi-WAN split~~ — **out of scope** (single WAN, dumb SOHO edge; OQ-1) | WS-NET | R-NET-04 | — | — | won't-do |
| T-3.4 | Prove: VPN IP egress, **kill-switch fail-closed (central)**, egress-class flip via git | WS-NET | R-NET-05/06/07 | T-3.0, T-3.2 | — | todo |
## Phase 4 — Observability, Backup/DR & Updates
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-4.1 | kube-prometheus-stack + Loki + Alloy + Alertmanager(email) | WS-OBS | R-OBS-01/02/03 | T-2.1 | — | todo |
| T-4.2 | Platform-health alerts (node/Longhorn/Flux/cert/VPN/backup) | WS-OBS | R-OBS-04 | T-4.1 | — | todo |
| T-4.3 | Velero + Longhorn off-cluster backup schedule (**needs backup-target choice** — S3/NFS endpoint) | WS-STORAGE | R-STATE-03 | T-2.1, OQ-BKP | — | todo |
| T-4.4 | DR drill: restore namespace + volumes from off-cluster backup | WS-STORAGE | R-STATE-03 | T-4.3 | — | todo |
| T-4.5 | Flux image-automation + Renovate + per-service update policy | WS-UPDATE | R-UPD-01/02/03 | T-0.3, T-4.1 | — | todo |
| T-4.6 | Prove: auto stable update on schedule, bad-update auto-rollback+alert, pin holds | WS-UPDATE | R-UPD-* | T-4.5 | — | todo |
## Phase 5 — IaaS Proof (KubeVirt)
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-5.1 | Install KubeVirt + CDI; Longhorn-backed VM disks | WS-VM | R-PLAT-03 | T-2.1, T-2.2 | — | todo |
| T-5.2 | `kind: vm` ServiceDefinition path; run one representative VM | WS-VM/WS-GITOPS | R-PLAT-03/04 | T-5.1, T-0.3 | — | todo |
| T-5.3 | Prove: VM lifecycle via kubectl/virtctl, rebuild w/o data loss, default-deny+egress, guest auto-update | WS-VM | R-PLAT-03, R-NET-*, R-UPD-* | T-5.2 | — | todo |
## Phase 6 — Service Onboarding + C2
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-6.1 | Onboard **pihole** (DNS underpinning) | WS-APPS | R-DNS-03 | T-2.5 | — | todo |
| T-6.1a | Onboard **gitea** early (bootstrapping-critical; self-hosts GitOps source + CI/CD) | WS-APPS | R-STATE-03 | T-4.4 | — | todo |
| T-6.1b | Migrate GitOps source local→Gitea; move CI to **Gitea Actions** (Kyverno gate + Chainsaw Job trigger; PR merge gate); off-cluster repo mirror | WS-GITOPS | R-GITOPS-01, R-TEST-03 | T-6.1a | — | todo |
| T-6.2 | Onboard **plex** (bulk tier + public exposure) | WS-APPS | R-STATE-04 | T-2.6, T-6.1 | — | todo |
| T-6.3 | Onboard **qbittorrent, jackett** (VPN + kill-switch) | WS-APPS | R-NET-05/06 | T-3.4 | — | todo |
| T-6.4 | Onboard **sonarr, radarr** (VPN + arr↔downloader allows) | WS-APPS | R-NET-02/05 | T-6.3 | — | todo |
| T-6.5 | Onboard **seerr** (allows to arr + plex) | WS-APPS | R-NET-02 | T-6.2, T-6.4 | — | todo |
| T-6.6 | Onboard **nextcloud** (DR-critical + backups) | WS-APPS | R-STATE-03 | T-4.4 | — | todo |
| T-6.7 | Onboard **minecraft, unifi, semaphore, kasm** | WS-APPS | app reqs | T-2.6 | — | todo |
| T-6.8 | C2 UI: Homepage root + Grafana + Headlamp + Flux status + auth | WS-C2 | R-C2-01/02 | T-4.2, T-6.* | — | todo |
## Phase 7 — Production Readiness (CLOSED until operator opens it)
| ID | Task | WS | Serves | Blocked-by | Owner | Status |
|---|---|---|---|---|---|---|
| T-7.1 | Bare-metal provisioning checklist (design-only) | WS-INFRA | R-ENV-03 | — | — | todo |
| T-7.2 | prod overlay (no base edits) + cutover plan | WS-INFRA/WS-GITOPS | R-ENV-02 | Phases 1–6 done | — | blocked |
| T-7.3 | Full prod DR drill | WS-STORAGE | R-STATE-03 | T-7.2 | — | blocked |
---
## Open questions
| OQ | Question | Blocks | Status |
|---|---|---|---|
| OQ-1 | WAN count + edge router | — | ✅ resolved: 1 WAN, dumb SOHO edge; multi-WAN out of scope; VPN + segmentation in-cluster |
| OQ-2 | Bulk-media home | — | ✅ resolved: media outside cluster, backing TBD later (not blocking) |
| OQ-3 | VPN provider/protocol | — | ✅ resolved: ExpressVPN, single shared in-cluster tunnel, OpenVPN UDP (ADR-0012) |
| **OQ-4** | **DNS-01 challenge access** | **T-2.4, T-2.5** | ⛔ **OPEN** — Cloudflare API token (Option A, recommended) vs acme-dns delegation (Option B) |
| **OQ-BKP** | **Off-cluster DR backup target** (S3/NFS endpoint) | T-4.3 | ⛔ **OPEN** — needed by Phase 4, not Phase 2 |