Skip to content

Feat: Transparent inbound interception for the Go proxy (proxy-sidecar) — SO_ORIGINAL_DST, no Envoy #330

Description

@huang195

Summary

Implement a transparent inbound listener for the Go proxy (proxy-sidecar mode): capture iptables-REDIRECTed inbound connections, recover the app's original destination port via SO_ORIGINAL_DST, run the inbound auth pipeline (JWT validation) inline, and forward to the app on its real port — no Envoy, no ext_proc, no Service rewiring.

This is the inbound half of the original "transparent-proxy mode" idea. Since this issue was filed, the outbound transparent path has effectively landed (see Status below); the remaining gap is inbound.

Status of the original proposal (what already landed)

The Go-native transparent-interception core was built and shipped — but as the outbound enforce-redirect egress guard inside proxy-sidecar mode, not as a standalone Envoy-replacement mode:

  • SO_ORIGINAL_DST getsockopt recovery, IPv4 + IPv6 — authlib/listener/transparentproxy/origdst_linux.go
  • TLS ClientHello passthrough + SNI/Host recovery — authlib/listener/forwardproxy/sniff.go, transparent.go
  • Shares the forward proxy's CONNECT auth pipeline via HandleTransparentConn
  • Landed in bb15d20 (+ follow-ups); bound to :8082; outbound only

The broader "drop the ~87 MB Envoy binary to shrink the image" motivation is also already met: proxy-sidecar is now the default mode and bundles no Envoy, and the authbridge-lite image variant shrinks it further.

What's still missing: there is no transparent inbound listener. Valid modes are envoy-sidecar, waypoint, proxy-sidecar (config.go:453) — there is no standalone transparent-proxy mode, and proxy-sidecar's inbound is a reverse proxy, not transparent (see below).

Current inbound mechanism and its limits

proxy-sidecar inbound today is a reverse proxy to a single fixed backendhttputil.NewSingleHostReverseProxy against reverse_proxy_backend (authlib/listener/reverseproxy/server.go:95, config.go:364). Traffic hits :8080, the inbound pipeline validates the JWT, and it forwards to one known app URL.

That is fine for a single-port app behind an operator-managed Service pointed at :8080, but it has three gaps:

  1. Bypassable. Validation is only enforced for traffic that goes through :8080. Anything that reaches the app's real port directly — another pod dialing podIP:appPort, a co-located sidecar, a mis-scoped NetworkPolicy — skips validation entirely. This is the inbound twin of the problem the outbound enforce-redirect guard already solves.
  2. Single port only. reverse_proxy_backend is one URL; it can't front an app that listens on multiple ports (e.g. HTTP API + gRPC + admin/metrics).
  3. Requires Service rewiring. The operator must point targetPort at :8080; it is not a transparent drop-in for an Envoy-shaped deployment.

What the transparent inbound listener would do

  • Listen on an inbound transparent port that proxy-init PREROUTING-REDIRECTs to (Envoy uses :15124; pick the proxy-sidecar equivalent).
  • Recover the original destination (the app's port) via SO_ORIGINAL_DST — reuse the existing transparentproxy package.
  • Run the inbound pipeline (JWT validation) inline — no ext_proc gRPC indirection.
  • Forward to the app on its recovered original port over loopback, replacing the single-fixed-backend assumption.
  • TLS: terminate or passthrough per the top-level mtls config, consistent with the reverse proxy's tlssniff behavior.
  • Reuse proxy-init's existing iptables rules and UID exclusion.

Why transparent inbound (in priority order)

  1. Enforcement / no-bypass — a hard inbound boundary so JWT validation cannot be sidestepped by hitting the app port directly. Directly symmetric to the outbound enforce-redirect guard.
  2. Multi-port appsSO_ORIGINAL_DST recovers whichever port each connection targeted; no per-port listener config.
  3. Envoy drop-in parity — makes the Go proxy transparent on both directions, so migrating a deployment off envoy-sidecar needs no Service/manifest surgery.

Trade-offs / notes

  • Needs the privileged proxy-init container (NET_ADMIN) for inbound and is Linux-only — same constraints as enforce-redirect and envoy-sidecar.
  • For a standard single-port agent behind an operator-managed Service where NetworkPolicy or mesh mTLS already limits direct access to the app port, the existing reverse proxy remains simpler. This should be opt-in, not a forced replacement.
  • envoy-sidecar, waypoint, and the existing reverse-proxy inbound path remain unchanged.

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Status
New/ToDo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions