Consul’s Ingress Gateway doesn’t just route external traffic; it actively terminates TLS, injects mTLS, and enforces authorization policies before traffic even hits your services.

Let’s see it in action. Imagine a simple HTTP service named frontend running in Kubernetes, exposed via a Consul service mesh. We want to expose this frontend service to the outside world through the Consul Ingress Gateway.

First, we need a Kubernetes Service for our frontend application.

apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: default
spec:
  selector:
    app: frontend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Next, we configure the Consul Ingress Gateway itself. This involves a ConfigMap that Consul reads from, and a Service of type LoadBalancer that exposes the gateway to the internet.

The ConfigMap specifies which services the gateway should expose and how.

apiVersion: v1
kind: ConfigMap
metadata:
  name: consul-ingress-gateway-config
  namespace: consul
data:
  config.json: |
    {
      "ports": {
        "grpc": 8500,
        "http": 8080,
        "https": 8443
      },
      "services": [
        {
          "name": "frontend",
          "port": 80,
          "service_subset": "v1",
          "tls_server_name": "frontend.example.com",
          "sources": [
            {
              "service": "frontend"
            }
          ]
        }
      ]
    }

Here, we’re telling the gateway to listen on port 80 for external traffic targeting frontend.example.com, and to forward that traffic to the frontend service on port 80 (which then maps to targetPort: 8080 in our Kubernetes Service). service_subset: "v1" is a concept in Consul for managing different versions of a service.

The Service for the Ingress Gateway makes it accessible.

apiVersion: v1
kind: Service
metadata:
  name: consul-ingress-gateway
  namespace: consul
spec:
  type: LoadBalancer
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: 8443
    - name: grpc
      port: 8500
      targetPort: 8500
  selector:
    app.kubernetes.io/component: ingress-gateway
    app.kubernetes.io/instance: consul

Once this is deployed, your cloud provider will provision a load balancer with an external IP address. You’d then configure your DNS to point frontend.example.com to this IP.

When a request arrives at https://frontend.example.com (assuming TLS is configured on the gateway), the Ingress Gateway terminates the TLS connection. It then performs a look-up in Consul’s catalog to find the frontend service. If mTLS is enabled for the mesh, the gateway will establish a mutual TLS connection with the frontend service’s sidecar proxy. Finally, it forwards the request.

The Ingress Gateway is a crucial component for bringing traffic into your Consul service mesh. It acts as the single, secure entry point, abstracting away the complexity of individual service discovery and network routing. It allows you to manage TLS termination, authentication, and authorization at the edge, rather than having to implement these concerns within each service.

A common point of confusion is how the tls_server_name in the ConfigMap relates to the actual TLS certificates. The Ingress Gateway needs a certificate that matches frontend.example.com (or a wildcard like *.example.com) to successfully terminate the TLS connection for incoming requests. This certificate needs to be configured within Consul itself, typically via the Consul API or by mounting it into the gateway pod. The gateway then uses this certificate to decrypt the incoming request before it proceeds with service resolution and routing.

The next logical step is to secure communication between services within the mesh using Consul’s automatic mTLS.

Want structured learning?

Take the full Consul course →