Skip to content

Reach cluster dependencies

Interception moves an inbound request to your laptop. Egress handles the other half of the debug loop: your local service calling its normal in-cluster dependencies.

Instead of one kubectl port-forward per dependency, outprobe opens local listeners over the same control port-forward it already maintains. The relay resolves cluster DNS, dials the target, and splices raw TCP in both directions.

.outprobe.yaml
egress:
services:
- name: pricing
to: pricing.my-namespace.svc.cluster.local:8080
- name: postgres
to: pg.my-namespace.svc.cluster.local:5432
listen: 127.0.0.1:15432

For each entry:

  • to is required and must be host:port;
  • name is a log label and defaults to the host from to;
  • listen defaults to 127.0.0.1:<port from to>.

In this example, configure the local app to call:

pricing → 127.0.0.1:8080
postgres → 127.0.0.1:15432

On startup, outprobe binds every listener before reporting success. Invalid targets, duplicate listen addresses, or unavailable local ports make up fail loudly before routing goes live.

Egress is raw TCP, so it works for:

HTTP & HTTPS

Point the local client’s host and port at the listener. TLS still runs end-to-end at the application layer.

gRPC

HTTP/2 bytes pass through unchanged.

Databases

Postgres and other TCP database protocols work without HTTP framing.

Long-lived streams

After the dial handshake, outprobe clears deadlines and splices until either side closes.

UDP is not supported.

By default the relay accepts any host reachable from its pod. Its control port is bound to pod loopback and reached only through your Kubernetes port-forward, but an allow-list provides defense in depth:

.outprobe.yaml
egress:
allow:
- .svc.cluster.local
services:
- name: pricing
to: pricing.my-namespace.svc.cluster.local:8080

allow entries are host suffixes. The CLI joins them into the relay’s EGRESS_ALLOW environment variable.

local app → local listener → CLI → port-forward → relay → cluster DNS target

For each accepted local connection, the CLI opens a control connection and sends:

OUTPROBE-DIAL <host:port>

The relay validates the target against allow, dials it with a timeout, replies OK, and then switches both ends to raw byte streaming.

Egress connections originate from the relay pod, not the original caller or your laptop. Therefore:

  • an Istio AuthorizationPolicy sees the relay’s service account identity;
  • reaching a STRICT mTLS service depends on whether the relay pod participates in the mesh;
  • this is useful connectivity for debugging, not a faithful recreation of the original caller identity.

The default loopback listener is reachable only on your machine. You can explicitly bind another interface, for example when container networking requires it, but outprobe warns because the raw bridge may then be reachable from your network.

listen: 0.0.0.0:8080

Use non-loopback listeners only when necessary and protect the host network accordingly.

Every listener closes when outprobe up receives Ctrl-C or exits. Egress is entirely opt-in; omitting egress.services creates no local listeners and changes no relay behavior beyond the default image.