Register a proxy transport
A proxy transport names the upstream target:Network kinds
tcp— the upstream is listening on a host and port,addressis thathost:port. Use this for an upstream that already binds a TCP port on its own.unix— the upstream is listening on a Unix domain socket,addressis the socket’s filesystem path. This avoids exposing a TCP port for traffic that only needs to reach the Kernel.inherited— only available to agrpcservice. Before the Kernel starts the service’s process, it prepares a listening socket and hands it to the service already open, so the service’s own server can start accepting connections immediately without racing the Kernel to bind a port or coordinate a port number. One inherited listener can back any number of proxy routes for that service.
unix and tcp targets point at an address that is already listening
somewhere, so they can also be declared by a static service’s
manifest.yaml — see Static services. An inherited
target only makes sense for a grpc service the Kernel is actively
starting.
Why inherited is the safer default for a grpc service
For a grpc service, prefer inherited over asking the service to bind its
own unix or tcp listener and pointing a transport at it afterward.
Because the Kernel creates the listener itself, before the service process
exists, and only then hands it to that process already open, several risks
that come with a service binding its own listener don’t apply:
- Nothing can bind ahead of the service. With a
unixortcptarget, the service has to bind the address itself after it starts, which leaves a window where another local process could bind that same path or port first and intercept traffic meant for the service. Withinherited, the Kernel holds the listener before the service process is even started, so there is no window for another process to claim it. - Restrictive permissions from the start. The listener the Kernel
prepares lives in a directory created with
0700permissions, and the listener itself is0600. Only the Kernel’s own process user can reach it before handing it off, so it is never briefly world- or group-accessible the way a self-created socket can be if a service’s own setup code creates it with looser default permissions. - The service never needs bind privileges. The service receives an
already-open listener instead of creating one, so it doesn’t need
permission to bind a port or create a socket file. This matters most when
RunAsUserruns the service as a restricted operating-system user — that user doesn’t need any special networking privilege, and a compromised service can’t abuse this mechanism to open some other, unintended listener. - Guaranteed to reach the right process. Because the Kernel created the listener and handed it directly to the specific child process it just started, traffic arriving there is guaranteed to reach that exact service instance. There’s no address to look up and no possibility of connecting to an impostor process that happened to bind the same path first.
- Cleaned up automatically. The Kernel closes its own reference once the service has started, and removes the listener when the service is unloaded, so a stopped service doesn’t leave a live or stale endpoint behind for another process to find or reuse.
unix and tcp, that same trust has to come from how you deploy the
upstream: keep a unix socket path in a directory only the intended user can
write to, and keep a tcp target bound to localhost or a private network
rather than a publicly reachable interface. Those are still reasonable
choices — for a static service’s fixed upstream, they’re the only choice —
but for a grpc service the Kernel is starting itself, inherited removes
the need to get that deployment detail right.
Bind a route to it
A route bound to a proxy transport carries the same kind of HTTP declaration as any other HTTP route —pattern and access — described in Routes and
transports. A proxy route commonly covers a whole subtree with a
trailing-slash pattern, so that every path under it reaches the upstream. The
root pattern / is always treated as a subtree for a proxy route, matching
every absolute path, so a service can proxy its entire application through
one route if it owns the root.
What the Kernel preserves and injects
The proxy forwards end-to-end request headers, includingCookie and
Authorization, and preserves the original request path, query string, and
Host header. Hop-by-hop headers are managed the normal way a reverse proxy
handles them.
Before forwarding, the Kernel always removes any identity headers the caller
supplied and injects its own, verified ones:
X-Arupa-AuthenticatedX-Arupa-User- one
X-Arupa-Groupheader per group the user belongs to
Access control
Access is evaluated the same way as any HTTP route: the service-wide policy first, then the route’s ownaccess policy. See Access
control for the policy model. The Kernel checks
access before proxying the request, so a denied request never reaches the
upstream.
Conflicts
A proxy route follows the normal HTTP route conflict rules described in Routes and transports: the same path cannot be owned by two services, and an any-method route conflicts with every method-specific route at the same path. A proxy route is notstatic, so it does not trigger the
static-versus-non-static conflict rule — it can share a path space with an
HTTP-transport route the same way two dynamically-handled routes would,
subject to the normal method rules.