Consul API Gateway doesn’t actually route traffic; it’s the piece that declares the intent for traffic to be routed, and the underlying Envoy proxies are the ones doing the heavy lifting.

Let’s see this in action. Imagine you have a service named frontend running in your Kubernetes cluster, exposed internally via a Kubernetes Service frontend-svc. You want to make this service accessible from the outside world via api.example.com.

Here’s a Gateway resource defining that intent:

apiVersion: gateway.consul.io/v1alpha1
kind: Gateway
metadata:
  name: frontend-gateway
  namespace: consul
spec:
  servers:
    - name: http
      port:
        number: 80
      listeners:
        - protocol: http
  routes:
    - name: frontend-route
      servers:
        - http
      expose:
        - name: frontend-svc
          namespace: default # Namespace of the Kubernetes Service
      methods: ["GET", "POST"] # Allow GET and POST requests
      path:
        type: PathPrefix
        value: /api/v1/ # Match requests starting with /api/v1/

When you apply this Gateway resource, Consul’s control plane watches it. It then configures the Envoy proxies that are running as part of the Consul integration (often as a sidecar or a dedicated ingress gateway deployment). These Envoy proxies are now listening on port 80. When a request comes in for api.example.com with a path starting with /api/v1/, Envoy will:

  1. Match the incoming request to the frontend-route defined in the Gateway resource.
  2. See that this route is configured to expose the frontend-svc in the default namespace.
  3. Consult its internal service discovery information (populated by Consul) to find the current IP addresses and ports for the pods backing frontend-svc.
  4. Forward the request to one of those backend pods.

The Gateway resource is essentially a declarative API that tells Consul’s control plane what traffic to allow and how it should be mapped to internal services. Consul then translates this declaration into specific configurations for the data plane (Envoy).

This approach decouples the definition of your API surface from the underlying infrastructure. You can manage your API routes and expose them through Consul API Gateway without needing to directly manage Ingress controllers or complex LoadBalancer configurations for every service. Consul handles the dynamic provisioning of Envoy configurations based on these Gateway resources.

The expose field is crucial here. It’s a direct link from the external-facing route to an internal Kubernetes Service. Consul uses this to program Envoy to route traffic not just to the service name, but to the actual IP addresses and ports of the pods backing that service.

What most people don’t realize is that the Gateway resource itself doesn’t perform any network I/O. It’s a purely declarative object that influences the configuration of the Envoy proxies managed by Consul. The actual routing, load balancing, and TLS termination happen within those Envoy instances, which are dynamically configured by Consul’s control plane based on your Gateway and Service resources.

The next step in managing external traffic is understanding how to configure TLS termination for your API Gateway.

Want structured learning?

Take the full Consul course →