chrome-service: open NP for Traefik → noVNC sidecar (port 6080)

Existing NetworkPolicy only admitted port 3000 (Playwright WS) from
labelled client namespaces, blocking Traefik's traffic to the noVNC
sidecar on port 6080. The chrome.viktorbarzin.me ingress would hang
forever — page never loads, eventually times out.

Adds a second ingress rule allowing TCP/6080 from the traefik
namespace only. Authentik forward-auth still gates external access
at the Traefik layer.

Also reconciles the noVNC image to the new Forgejo registry path
(:v4 unchanged) — already declared in TF, just live-state drift from
the Phase 3 registry consolidation.

Updates the architecture doc; the previous text still described the
old nginx static health stub that noVNC replaced.
This commit is contained in:
Viktor Barzin 2026-05-07 18:40:11 +00:00
parent 56fbd281c9
commit 3f3e5fc954
2 changed files with 40 additions and 13 deletions

View file

@ -89,14 +89,24 @@ PVC) and reuses it on subsequent restarts.
## Network controls ## Network controls
- **`kubernetes_network_policy_v1.ws_ingress`** — only namespaces labelled - **`kubernetes_network_policy_v1.ws_ingress`** — two separate ingress
`chrome-service.viktorbarzin.me/client = "true"` (plus an explicit rules on the same policy:
fallback for `f1-stream` by `kubernetes.io/metadata.name`) can reach - **TCP/3000** (Playwright WS): only namespaces labelled
TCP/3000. `chrome-service.viktorbarzin.me/client = "true"` (plus an explicit
fallback for `f1-stream` by `kubernetes.io/metadata.name`).
- **TCP/6080** (noVNC HTTP+WS): only the `traefik` namespace, since
the public-facing path is `chrome.viktorbarzin.me` ingress →
Traefik → sidecar. Authentik forward-auth still gates external
access at the Traefik layer.
- **WS port 3000** is internal-only (no ingress, no Cloudflare DNS). - **WS port 3000** is internal-only (no ingress, no Cloudflare DNS).
- **HTTP port 80** (sidecar `nginxinc/nginx-unprivileged:alpine`) serves - **noVNC sidecar** (`forgejo.viktorbarzin.me/viktor/chrome-service-novnc`)
a static health stub at `chrome.viktorbarzin.me`, Authentik-gated. exposes a live HTML5 view of the headed Chromium session via
Lets a human confirm pod liveness without spinning a browser. `x11vnc` (connected to Xvfb on `localhost:6099`) bridged to
`websockify` on port 6080. Service `chrome` maps :80 → :6080 and is
exposed via `ingress_factory` at `chrome.viktorbarzin.me`,
Authentik-gated. Both static page and WebSocket upgrade share the
same path — Cloudflare proxy, Cloudflared tunnel, Traefik, and
Authentik forward-auth all preserve `Upgrade: websocket`.
## Adding a new caller ## Adding a new caller

View file

@ -21,9 +21,9 @@ resource "kubernetes_namespace" "chrome_service" {
metadata { metadata {
name = local.namespace name = local.namespace
labels = { labels = {
"istio-injection" = "disabled" "istio-injection" = "disabled"
tier = local.tiers.aux tier = local.tiers.aux
"chrome-service.viktorbarzin.me/server" = "true" "chrome-service.viktorbarzin.me/server" = "true"
} }
} }
lifecycle { lifecycle {
@ -366,10 +366,14 @@ module "ingress" {
} }
} }
# --- NetworkPolicy: TCP/3000 ingress only from labelled client namespaces. # --- NetworkPolicy: scoped ingress.
# - TCP/3000 (Playwright WS): only from labelled client namespaces.
# - TCP/6080 (noVNC HTTP+WS): only from the traefik namespace, since the
# public-facing path is `chrome.viktorbarzin.me` ingress Traefik
# sidecar. Authentik forward-auth still gates external access at the
# Traefik layer.
# The cluster has no default-deny, so this NP only takes effect inside # The cluster has no default-deny, so this NP only takes effect inside
# chrome-service ns pods elsewhere remain unaffected. Callers opt in by # chrome-service ns pods elsewhere remain unaffected.
# labelling their namespace `chrome-service.viktorbarzin.me/client = "true"`.
resource "kubernetes_network_policy_v1" "ws_ingress" { resource "kubernetes_network_policy_v1" "ws_ingress" {
metadata { metadata {
name = "chrome-service-ws-ingress" name = "chrome-service-ws-ingress"
@ -402,6 +406,19 @@ resource "kubernetes_network_policy_v1" "ws_ingress" {
protocol = "TCP" protocol = "TCP"
} }
} }
ingress {
from {
namespace_selector {
match_labels = {
"kubernetes.io/metadata.name" = "traefik"
}
}
}
ports {
port = "6080"
protocol = "TCP"
}
}
} }
} }