MARS does not implement authentication. It must be deployed behind a reverse proxy or ingress that terminates TLS and enforces request authentication. Exposing the MARS HTTP listener directly to a public network is unsafe.
This document describes what MARS provides, what it explicitly does not provide, and the deployment patterns that close the gap.
- Authentication. MARS accepts every well-formed HTTP request. There is no API key check, no session validation, no OAuth/OIDC integration, no mTLS verification at the application layer.
- TLS termination. The MARS HTTP listener binds plaintext. There is no configuration option to load a certificate; this is intentional. TLS belongs at the ingress so certificate rotation, OCSP stapling, ciphersuite policy, and ALPN are all owned by the platform layer.
- Authorisation per user. MARS has no concept of an authenticated principal. It cannot make a "user X is allowed layer Y" decision because it never sees user identity.
- Rate limiting per user / per tenant. MARS has no user identity, so any rate limit must be applied upstream.
- Per-layer service-operation gating. Each layer's
ows.request_gatingcan disable specific service operations (e.g. forbidWmsGetFeatureInfofor a given layer). This is access control, not authentication: it restricts which surface MARS will serve for that layer to any caller that reaches it. If the listener is reachable, the gated subset is reachable. - CIDR-based trust for forwarded headers.
service.forwarded_headers_trustdecides which TCP peers MARS believes when they assertForwarded/X-Forwarded-*. This is integrity for capabilities-URL synthesis, not authentication of end users. - Health and metrics endpoints.
/healthz,/readyz, and/metricsare unauthenticated by design (kubelet, Prometheus, etc.). The pprof debug listener, when enabled, refuses non-loopback binds unless an explicit opt-in is set (seeobservability.debug_pprof_listenandobservability.debug_pprof_allow_non_loopback).
The distinction is load-bearing: ServiceOp gating decides which
operations a layer exposes; it does not decide who may invoke them.
All of the following sit in front of MARS and own TLS termination, authentication, and per-request authorisation. Pick one based on the rest of your platform.
A typical pattern for Kubernetes:
- Ingress controller (Traefik, Nginx, Envoy/Istio, HAProxy, ...) terminates TLS.
oauth2-proxysits between the ingress and the MARS Service, exchanging the upstream cookie / bearer token for a verified upstream identity.- The ingress only forwards requests to MARS after
oauth2-proxyhas authenticated the caller.
The MARS layer continues to honour forwarded headers from the trusted ingress
peer for capabilities-URL synthesis. See ingress.md for the
forwarded-headers trust policy.
Some ingress controllers (Traefik with the OIDC middleware plugin, Envoy /
Istio with the JWT authentication filter, Nginx with auth_request) can
validate OIDC tokens directly without an intermediate sidecar. Same shape
as above, fewer moving parts.
If clients are machine-to-machine (sister services, harvesters, parity
suites), mutual TLS at the ingress provides identity without the OIDC flow.
The ingress terminates client TLS, verifies the client certificate against
a trusted CA, and forwards the plaintext request to MARS. The downstream
identity (client CN, SAN) can be passed via X-Forwarded-Client-Cert or
similar for audit logging.
Any API gateway (Kong, Ambassador, AWS API Gateway, Azure APIM, GCP API Gateway) that can terminate TLS, validate credentials, and forward an authenticated request fits the same pattern. MARS is the upstream service; the gateway is the auth boundary.
For internal-only deployments (compiler-side, batch consumers, intra-cluster service mesh), network policy can be the auth boundary. MARS still must not listen on a publicly routable address; the cluster network policy must ensure only authorised peers can reach the listener.
After deploying behind an ingress, confirm:
- MARS is not reachable directly. A request to the MARS pod IP or the cluster-internal Service from outside the cluster should fail or never arrive. If MARS is reachable, the ingress is being bypassed.
- TLS is enforced at the ingress. A plaintext request to the public hostname should redirect to HTTPS or refuse.
- Unauthenticated requests are refused. A
curl https://maps.example/wmswithout credentials should be denied by the ingress before reaching MARS. - MARS sees the correct public URL.
GET /status(returned through the ingress) reports the public hostname and scheme. Seeingress.mdfor the forwarded-headers configuration.
Auth is a deployment concern, not a rendering concern. Embedding it in MARS would require:
- Choosing one (or a small set) of identity providers and token formats, forcing operators to use them or work around them.
- Implementing session management, token validation, and credential storage - all areas where industry-standard tooling (oauth2-proxy, ingress filters, API gateways) is more mature and audited.
- Coupling MARS releases to security advisories in those tools.
By delegating auth to the platform, MARS stays a rendering service and the platform owns the security boundary it is already configured to own.