Commit Graph
107 Commits
Author SHA1 Message Date
jakman85andClaude Opus 4.8 0f12950831 Onboard arr apps (Sonarr + Radarr) via ServiceDefinition renderer
Add catalog/sonarr.yaml and catalog/radarr.yaml ServiceDefinitions and their
rendered apps/*.yaml manifests, wired into apps/kustomization.yaml.

- exposure: internal, egress: vpn (R-NET-05/06 VPN + kill-switch, ADR-0015)
- auth: forward-auth, groups: media-users (R-IDP-02/06)
- dependencies -> qbittorrent:8080, jackett:9117 as explicit east-west
  CiliumNetworkPolicy egress allows on top of default-deny (R-NET-01/02)
- config on longhorn (R-STATE-02); bulk media/downloads volume DEFERRED
  pending OQ-2 (bulk StorageClass is a non-provisioning stub)
- observability up-SLI alert (R-OBS-01), daily-offcluster backup (R-STATE-03)

Rendered with catalog/render.py --no-image-automation. Offline gates green:
schema validate, kubectl kustomize apps, render.py --selftest, make -C ci gate.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-25 08:32:39 -05:00
jakman85 87087e06c7 Merge feature/onboard-plex: onboard Plex (media, public; bulk media deferred on OQ-2)
# Conflicts:
#	apps/kustomization.yaml
2026-08-25 08:29:35 -05:00
jakman85andClaude Opus 4.8 d47c8f91cb Onboard Plex to the k3s platform via ServiceDefinition (WS-APPS)
Add catalog/plex.yaml (kind: container) and its rendered apps/plex.yaml,
and wire apps/kustomization.yaml. Plex = docs/13 row 1, the catalog's
largest service; validates the public-exposure + config-on-Longhorn path.

- image plexinc/pms-docker (pinned recent stable tag), port 32400
- exposure: public at plex.home.keithjackson.dev; egress: internet
- auth: native (Plex accounts, not Keycloak — docs/13/15 exception)
- config PVC 20Gi on longhorn; off-cluster backup (daily-offcluster) as the
  longhorn tier forbids reacquirable under L0 (R-STATE-03)
- observability up-SLI; update channel stable

Bulk media (R-STATE-04) deferred: the `bulk` StorageClass is a documented
stub (OQ-2 unresolved, NFS CSI not installed) so a bulk PVC would leave the
pod Pending. Media mount omitted; attach once bulk provisions.

Traces: R-GITOPS-02, R-NET-01/02/05, R-STATE-01/02/03, R-TLS/R-DNS,
R-OBS-01, R-UPD-01/03, R-IDP-02, R-PLAT-02.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-25 08:27:50 -05:00
jakman85andClaude Opus 4.8 b76fb7bea7 feat(apps): onboard Gitea via ServiceDefinition renderer
Author catalog/gitea.yaml (kind: container, public, DR-critical git host per
docs/13 row 12), render to apps/gitea.yaml (--no-image-automation), and wire it
into apps/kustomization.yaml.

- image gitea/gitea:1.24.3, web port 3000 at gitea.home.keithjackson.dev
- 10Gi Longhorn PVC for /data (repos + SQLite DB), daily-offcluster backup
- exposure public, egress internet, auth oidc (platform-admins), metrics on
- Traces: R-STATE-02/03, R-NET-01/02, R-DNS/R-TLS, R-IDP-02/06, R-OBS-01, R-UPD-01/03

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-25 08:23:33 -05:00
jakman85andClaude Opus 4.8 c13ef69e71 feat(net): renderer emits gateway-ingress allow for exposed services (R-NET-01/02)
Exposed apps got a default-deny NetworkPolicy with ingress: [] (deny all), so the
Cilium Gateway (Envoy, reserved identity `ingress`) could not reach the backend — an
Accepted HTTPRoute was still unreachable. render.py now emits an ADDITIVE, least-
privilege CiliumNetworkPolicy for any ServiceDefinition that renders an HTTPRoute:

  ingress:
    - fromEntities: [ingress]        # the shared Cilium Gateway/Envoy proxy identity
      toPorts: [<exposed service port(s)> TCP]

Verified against the live cluster (Cilium 1.16.5): with default-deny in place, Hubble
shows the Gateway proxy reaching pihole as source identity `(ingress)` and the flow
`Policy denied DROPPED` on :80 — so `fromEntities: [ingress]` is exactly the source the
Gateway uses, scoped to the service targetPort. Default-deny stays intact (ingress: []
unchanged); the allow only opens the north-south path (docs/09), east-west stays denied.

- render.py: add r_gateway_ingress_policy(); emit it after dependency policies; selftest
  asserts the allow is additive (default-deny ingress stays []), least-privilege (only the
  exposed port, only the ingress identity), and absent for non-exposed services.
- L1 goldens updated for the two exposed fixtures (container-workload, egress-class);
  default-deny-baseline golden unchanged (no exposure). --selftest + run.sh --layer l1 green.
- apps/pihole.yaml re-rendered (--no-image-automation) to carry the allow.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-24 23:40:52 -05:00
jakman85 e843db2601 feat(apps): onboard pihole via renderer + --no-image-automation flag (WS-APPS golden path)
First app onboarded through catalog/render.py -> apps/. Added --no-image-automation so apps
deploy before the Flux image controllers exist (L1 goldens keep the default, unchanged).
KNOWN GAP surfaced: exposed apps get default-deny (ingress: []) with no gateway-ingress allow,
so the HTTPRoute path is blocked — renderer/WS-NET follow-up to allow Cilium gateway ingress
to services with an exposure/HTTPRoute.
2026-08-24 23:27:22 -05:00
jakman85andClaude Opus 4.8 253b6600f4 Initial skeleton: home-network-k3s implementation repo
Phase 0 foundation shell (read-only spec at ../home-network-k3s). Top-level
tree + rules; workstream agents fill their subtrees on feature branches.

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