Linkerd’s egress gateway is how you let services inside the mesh talk to services outside the mesh, without those outside services needing to know about Linkerd at all.

Here’s a real-world example. Imagine you have a frontend service in your Linkerd-enabled Kubernetes cluster that needs to call an external, non-Kubernetes API, like https://api.example.com. Without an egress gateway, Linkerd’s proxy sidecar on the frontend pod would try to route that traffic through the mesh, which isn’t designed for external destinations. It would likely fail.

To make this work, you deploy a dedicated egress-gateway deployment and service in your cluster. This gateway is also running a Linkerd proxy, but it’s configured differently. When the frontend service makes the call to https://api.example.com, Linkerd’s policy on the frontend proxy intercepts this. Instead of trying to resolve api.example.com directly (which it can’t do properly through the mesh), it’s configured to redirect that traffic to the egress-gateway service. The egress-gateway proxy then makes the actual outbound connection to api.example.com.

This setup provides several benefits:

  • Security: You can enforce granular policies on which external services your internal services are allowed to reach. This is done using Linkerd’s Server and ServiceProfile resources, but applied to the egress gateway.
  • Observability: All traffic leaving the mesh via the gateway is automatically instrumented by Linkerd. You get metrics (success rates, latency, request volume) and distributed tracing for these outbound calls, just like you do for in-mesh traffic.
  • Simplicity for External Services: The external services (api.example.com in our example) don’t need to be Linkerd-aware. They just see a standard TCP connection from the egress gateway’s IP address.

Let’s look at the core components.

First, you need to enable the egress gateway feature in your Linkerd installation. If you installed with linkerd install | kubectl apply -f -, you’ll need to re-run that with the --egress-gateway flag.

# Uninstall existing Linkerd components (if any)
linkerd uninstall | kubectl delete -f -

# Install Linkerd with egress gateway enabled
linkerd install --egress-gateway | kubectl apply -f -

This command deploys the linkerd-egress namespace, which contains the egress-gateway deployment and its associated ClusterIP service.

Next, you need to configure your internal services to route external traffic through this gateway. This is done via Linkerd’s HTTPRoute or TCPRoute resources (depending on whether you’re routing HTTP/S or raw TCP). The key is to match on the destination address and specify the egress-gateway as the upstream.

Consider an HTTPRoute to allow your frontend service to reach api.example.com:

apiVersion: gateway.linkerd.io/v1alpha1
kind: HTTPRoute
metadata:
  name: allow-api-example-com
  namespace: frontend-namespace # The namespace of your frontend service
spec:
  parent:
    namespace: linkerd # The namespace where the Linkerd proxy is injected
    name: frontend # The name of your frontend deployment/pod
  host:
    name: api.example.com
  filters:
    - type: RequestMirror
      # Optional: mirror requests to an internal service for debugging
      backend:
        service:
          name: api-example-com-mirror
          port:
            number: 8080
  forwardTo:
    - service:
        name: linkerd-egress # The name of the egress gateway service
        port:
          number: 80 # The standard HTTP port for the egress gateway

This HTTPRoute tells the Linkerd proxy on the frontend pod: "If you see an HTTP request destined for api.example.com, instead of trying to resolve it externally, forward it to the linkerd-egress service on port 80." The linkerd-egress service is a ClusterIP service that acts as the entry point for the egress gateway pods.

You also need to ensure that the frontend service itself has the Linkerd proxy injected. This is typically handled by Linkerd’s automatic or manual injection mechanisms.

For TLS-enabled external services, Linkerd handles this transparently. The egress gateway establishes a TLS connection to the external service. Your internal service can communicate with the gateway as if it were making a plain HTTP/TCP connection, and Linkerd’s policy layer ensures the correct TLS handshake occurs on the outbound leg.

The actual traffic flow looks like this: frontend-pod -> frontend-proxy -> linkerd-egress-service -> egress-gateway-pod -> api.example.com

A common point of confusion is understanding that the HTTPRoute or TCPRoute is applied to the source pod (e.g., frontend) and points to the egress gateway service. The egress gateway itself doesn’t need explicit HTTPRoute or TCPRoute resources in its own namespace for basic forwarding; its configuration is managed by the Linkerd control plane as part of its gateway role.

The most surprising thing about Linkerd’s egress gateway is that it doesn’t require any modification to the external service’s network configuration or DNS. The egress gateway effectively becomes a transparent proxy for outbound traffic from the mesh, allowing you to secure and observe these connections without impacting the services you’re connecting to.

Once you have the egress gateway set up and routes configured, you’ll likely want to explore how to secure these outbound connections using Linkerd’s AuthorizationPolicy resources, applied to the linkerd-egress namespace to control which internal services can reach which external destinations.

Want structured learning?

Take the full Linkerd course →