Browser and gateway security boundaries¶
The API is an operator tool. The optional remote submission mode uses a shared operator bearer; it does not provide tenant isolation or per-user authorization. A gateway is responsible for authenticating browser users and deciding which users may reach the console; the single sign-on gateway recipe deploys oauth2-proxy for this. Keep operator credentials out of browser storage, page bootstrap data and WebSocket URLs.
Namespace scope¶
The Spark UI proxy connects to <service>.<namespace>.svc directly, so Kubernetes
RBAC does not bound it. SPARK_ON_K8S_API_NAMESPACES does: the API serves its current
namespace by default, * for every namespace, or a comma-separated list. Requests,
proxy connections and log streams for other namespaces fail with 403 and the
namespace_forbidden code before the API contacts Kubernetes or a Spark UI. At
startup, the API also refuses a default namespace, run-history namespace or
submission-policy namespace outside the scope. Within a namespace in scope, the proxy
reaches any Service on port 4040; scope namespaces to the workloads the API should
expose. The scope limits what the API can reach, not who can use it.
Proxy request headers¶
Spark UI and History Server requests forward only the existing content-negotiation, cache-validation, range and content-type header allowlist, regardless of whether remote submission is enabled. Authorization, Cookie, Proxy-Authorization, custom identity headers and arbitrary tracing headers are not forwarded to those upstream services.
This changes the previous behavior of deployments with remote submission disabled. Deployments that relied on implicit gateway credential forwarding must arrange upstream authentication explicitly outside this proxy; there is no arbitrary-header forwarding override. These controls do not isolate untrusted Spark or History HTML from the console's browser origin. Operate those upstream services within the same trust boundary.
Mounted Spark UI paths¶
For a deployment mounted at a path such as /platform/spark, start the API with
--root-path /platform/spark or set SPARK_ON_K8S_API_ROOT_PATH=/platform/spark;
the flag takes precedence. In the Helm chart, add the variable to env:
env:
- name: SPARK_ON_K8S_API_ROOT_PATH
value: /platform/spark
The value is the server's ASGI root_path: empty, or a path that starts with /
and has no trailing slash, query or fragment. The gateway or ingress must remove
the prefix before forwarding, so a public /platform/spark/webserver/apps request
reaches the API as /webserver/apps; configure that with the controller's
prefix-stripping or rewrite feature. The API adds the prefix to console, asset and
redirect URLs. Probes that reach the pod directly keep using /health and /ready.
The proxy keeps Spark UI and History Server links under that
prefix, including links generated by upstream HTML with an unprefixed proxyBase.
It rewrites only quoted paths for the requested proxy target.
Mounted HTML responses are buffered before delivery, with an 8 MiB decoded limit.
Unencoded, identity, gzip and deflate bodies are supported. Oversized,
unsupported or malformed compressed HTML returns HTTP 502 before a partial page
is sent. Non-HTML responses and deployments without a path prefix keep their
streaming behavior.
Log WebSocket browser origins¶
SPARK_ON_K8S_API_WEBSOCKET_ALLOWED_ORIGINS is a comma-separated list of exact public HTTP(S) origins, for example:
export SPARK_ON_K8S_API_WEBSOCKET_ALLOWED_ORIGINS=https://spark.example.com,https://spark-admin.example.com:8443
Use only scheme, hostname and optional port: no path, trailing slash, query, fragment, credentials or wildcard. Default HTTP and HTTPS ports are equivalent to their explicit forms. If any configured entry is malformed, browser connections are rejected.
With an empty setting, a browser Origin must match the direct request Host and scheme (ws maps to http, wss to https). The application does not consult Forwarded or X-Forwarded-* headers for this decision. The ASGI server's trusted-proxy configuration still controls its request scope; configure that trust narrowly. For a gateway that changes Host or terminates TLS, set the explicit external origin list. A configured list replaces the direct-origin default.
A deployment prefix such as /platform/spark belongs in the server's root path (SPARK_ON_K8S_API_ROOT_PATH), never in an origin. The same origin policy applies with or without that prefix. Null, malformed and duplicate Origin headers are rejected before accepting the socket or querying Kubernetes, including when bearer authentication succeeds.
Non-browser clients may omit Origin. This preserves CLI clients and is not an authentication exemption: remote-mode bearer checks still apply. Origin is a browser request boundary, not proof of identity, and non-browser clients can supply it themselves. Gateways should also enforce the intended browser origins, restrict public access and rate-limit upgrades. This policy applies to the log WebSocket route; it does not claim general CSRF protection.