Deploy Homepage (gethomepage) as the apex landing dashboard aggregating links to cluster services, in its OWN non-gating post-platform Flux Kustomization (clusters/base/homepage.yaml, dependsOn platform-config, wait:false) — mirrors headlamp/oauth2-proxy so a leaf UI can never gate the platform chain. - platform/homepage/: plain manifests (ns, config ConfigMap, Deployment, Service, default-deny+Cilium ingress NP, apex HTTPRoute). Non-root pod, HOMEPAGE_ALLOWED_HOSTS, bundled mdi-* icons (DNS-only egress). - gateway.yaml: add https-apex + http-apex-redirect listeners for the bare apex (the *.home wildcard listener does NOT match it). Apex is already a SAN on the wildcard cert — no new Certificate. - Forward-auth annotated (auth-mode=forward-auth) but NOT enforced: the Gateway ext-authz mechanism is an unbuilt Phase-6 WS-NET TODO (same status as all other forward-auth apps). Flagged as PM follow-up. Gate: lint/l0/render-golden(10/10)/l1 green; conformance skipped (no cluster). Co-Authored-By: Claude Opus 4.8 <[email protected]>
56 lines
3.3 KiB
Markdown
56 lines
3.3 KiB
Markdown
# 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`](../../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.
|