Files
home-network-k3s-impl/platform/homepage
jakman85andClaude Opus 4.8 cde2cd138f plex: add env vars (PLEX_UID/GID, TZ, ALLOWED_NETWORKS); homepage: rename Overseerr->Seerr
Plex Deployment had no Plex env vars. Add via the ServiceDefinition env list
(rendered verbatim by catalog/render.py):
- PLEX_UID/PLEX_GID=1000 (image chowns /config to this and drops; matches the
  Longhorn ownership convention seerr/semaphore use)
- TZ=Etc/UTC (no other service sets TZ repo-wide)
- ALLOWED_NETWORKS=10.0.0.0/8,192.168.0.0/16 so in-cluster clients (Seerr ->
  plex:32400) are trusted as LAN (pod CIDR 10.0.0.0/16 + svc 10.43.0.0/16 + LAN)

PLEX_CLAIM intentionally not set (4-min TTL is unusable via git; one-time live
claim persists on /config). ADVERTISE_IP deferred: the only candidate host
resolves via split-horizon DNS to the internal Gateway VIP and its remote
reachability is unverified — a wrong value breaks remote access, so omitted
per prefer-safety, documented as a follow-up in catalog/plex.yaml.

Homepage still labeled seerr as "Overseerr"; renamed the tile to "Seerr"
(icon mdi-play-box-multiple keeps — not overseerr-specific).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-28 13:20:34 -05:00
..

platform/homepage

Homepage (gethomepage) — the apex landing dashboard at https://home.keithjackson.dev, aggregating links to the cluster's services.

  • Serves: a single pane of glass for the homelab (docs/09 apex UI).
  • Tier: non-gating post-platform Flux Kustomization (clusters/base/homepage.yaml, dependsOn: platform-config, wait: false) — mirrors headlamp / oauth2-proxy. A leaf UI must never gate the platform tier (DECISIONS-LOG "Headlamp gating stall").
  • Namespace: homepage — a PLATFORM namespace (no app-namespace=true), so the Kyverno app-scoped policies (default-deny gen, auth-mode, egress-class) do not apply; we ship an explicit default-deny + Cilium ingress policy as defense-in-depth.

What this component owns

Plain manifests (not a HelmRelease — the app is one stateless Deployment + a config ConfigMap):

File Purpose
namespace.yaml homepage ns, gateway-access=shared
configmap.yaml Homepage config (settings/services/bookmarks/widgets + empty docker/kubernetes + custom.css/js)
deployment.yaml ghcr.io/gethomepage/homepage (non-root, subPath config mounts, HOMEPAGE_ALLOWED_HOSTS)
service.yaml ClusterIP 80 -> 3000
networkpolicy.yaml default-deny (DNS-only egress) + Cilium Gateway-only ingress on 3000
httproute.yaml apex ingress on the Gateway https-apex listener

Apex nuances (why this isn't just another *.home route)

  1. TLS: the apex home.keithjackson.dev is already a SAN on the wildcard Certificate (platform/gateway/wildcard-certificate.yaml) — no new cert.
  2. Gateway listener: the wildcard listeners' hostname *.home.keithjackson.dev does not match the bare apex. This component's route binds a dedicated https-apex listener added to the shared Gateway (platform/gateway/gateway.yaml); http-apex-redirect covers :80.
  3. HOMEPAGE_ALLOWED_HOSTS: Homepage >= 1.0 returns 403 for any Host not in this list — set to home.keithjackson.dev + the pod IP (for kubelet probes).

Forward-auth — FOLLOW-UP (not yet enforced)

The HTTPRoute is annotated auth-mode: forward-auth (intended posture: oauth2-proxy -> Keycloak). The Gateway ext-authz attachment that actually enforces forward-auth does not exist yet — it is a Phase-6 WS-NET TODO (platform/oauth2-proxy is the authenticator; there is no CiliumEnvoyConfig / ext-authz wiring anywhere in the repo). Until that mechanism lands, Homepage — like every other forward-auth app (jackett, qbittorrent, pihole, radarr, sonarr) — is reachable unauthenticated. When the Gateway ext-authz pattern is built, attach it to this route (and the others) with allowed-groups: platform-admins. PM decision flagged in the deploy report.

Deliberately deferred (avoid scope creep)

  • Service-status widgets (Grafana/Plex/Sonarr/… API tiles) need per-service API-key secrets — not wired; tiles are simple links. Add as SOPS secrets + widgets.yaml later.
  • Kubernetes widget would need a read-only ServiceAccount + RBAC — skipped (kubernetes.yaml empty, automountServiceAccountToken: false).
  • Brand icons (selfh.st/dashboard-icons) need world:443 egress — we use bundled mdi-* icons so egress stays DNS-only.