Skip to content

Browser & ingress traffic

Caller-side Istio routing covers east-west service-to-service traffic. A browser request that enters through a gateway can bypass that mesh route, so outprobe can also create Gateway API HTTPRoute objects.

Ingress is opt-in. With no ingress.routes, outprobe up creates no HTTPRoutes.

Start with the read-only discovery command:

Terminal window
outprobe routes

It scans cluster-wide for Gateway API HTTPRoutes, Istio VirtualServices, and classic Ingresses whose backend is your configured target. For matching HTTPRoutes it prints a ready-to-paste block:

ingress:
routes:
- cloneFrom: my-service-route

routes only runs kubectl get; it does not modify the cluster.

Cloning is recommended when an existing route has multiple rules, rewrites, canary headers, or other per-rule behavior:

.outprobe.yaml
ingress:
routes:
- cloneFrom: my-service-route

outprobe copies the existing route’s parent refs, hostnames, rules, URL rewrites, and ordinary filters. It adds the outprobe header condition to every match and changes how the relay is attached.

Redirect-only rules are dropped because Gateway API forbids a backend on a RequestRedirect rule.

Each managed object is named outprobe-ingress-<name>, or uses cloneFrom as the suffix when name is omitted.

Every generated rule gets one extra header condition. By default it is:

x-outprobe: 1

This condition serves two purposes:

  1. Scope: only requests that explicitly opt in are candidates for interception.
  2. Precedence: when two Gateway API routes have the same path, the route with more header matches wins the tie.

Inject the header with a browser extension such as Requestly or ModHeader, scoped to the internal hostname.

Customize the exact gate:

.outprobe.yaml
ingress:
header: x-debug-session
headerValue: denis
routes:
- cloneFrom: my-service-route

If you cannot inject a custom header, set header but omit headerValue:

.outprobe.yaml
ingress:
header: Authorization
routes:
- cloneFrom: my-service-route

outprobe emits a regular-expression presence match, so any non-empty Authorization header reaches the relay. The relay still performs your JWT claim match: your request goes local; other authenticated requests pass through in divert mode.

With mode: divert, the generated route points candidate traffic at the relay:

browser → gateway → header-gated HTTPRoute → relay
├─ rule match → laptop
└─ no match → real target

The local response is returned for a matching request. An unmatched request is proxied to the target with the bypass header.

With mode: mirror, the cloned route keeps the real backend and gains a Gateway API RequestMirror filter:

browser → gateway → cloned HTTPRoute → real target → real response
└─ mirror copy → relay → laptop

The local response is discarded.

.outprobe.yaml
version: "0.0.1"
namespace: my-namespace
target: my-service
mode: divert
ingress:
gateway: istio-ingressgateway-api
gatewayNamespace: gateway-system
header: x-outprobe
headerValue: "1"
routes:
- name: simple-api
hostnames: [api.internal.example.com]
path: /my-service
- cloneFrom: my-service-admin-route
rules:
- type: jwt
matchers:
- key: email
value: you@example.com
  • The original route still wins: confirm the header reaches the Gateway and is spelled exactly as configured.
  • A CDN or ALB is in front: it may strip custom headers. Test at the internal hostname or use a header it preserves.
  • cloneFrom is not found: the source HTTPRoute must be in the target namespace used by outprobe.
  • Classic Ingress or Istio gateway VirtualService: outprobe discovers these for information but does not clone them. Add an equivalent Gateway API HTTPRoute or handle routing manually.
  • Mirror apply fails: replace any from-scratch route with cloneFrom.

outprobe down and Ctrl-C delete all labeled HTTPRoutes before removing the relay.