Use Kong as a delegated Gateway

Uses: Kong Mesh

To get traffic from outside your mesh inside it (North/South) with Kong Mesh you can use a delegated gateway.

In the quickstart, traffic was only able to get in the mesh by port-forwarding to an instance of an app inside the mesh. In production, you typically set up a gateway to receive traffic external to the mesh. In this guide you will add Kong as a delegated gateway in front of the demo-app service and expose it publicly.

Prerequisites

  • Completed quickstart to set up a zone control plane with demo application

If you are already familiar with quickstart you can set up required environment by running:

sh helm upgrade \ --install \ --create-namespace \ --namespace kong-mesh-system \ kong-mesh kong-mesh/kong-mesh kubectl wait -n kong-mesh-system --for=condition=ready pod --selector=app=kong-mesh-control-plane --timeout=90s kubectl apply -f https://raw.githubusercontent.com/kumahq/kuma-counter-demo/refs/heads/main/k8s/001-with-mtls.yaml

Install Kong ingress controller

Follow the steps on the Kong docs website to install the ingress controller.

The Kubernetes cluster needs to support LoadBalancer for this to work.

If you are running minikube you will want to open a tunnel with minikube tunnel -p mesh-zone.

You may not have support for LoadBalancer if you are running locally with kind or k3d. When running kind cluster you can try kubernetes-sigs/cloud-provider-kind.

Enable sidecar injection on the kong namespace

The Kong Ingress controller was installed outside the mesh. For it to work as a delegated gateway restart it with sidecar injection enabled:

Add the label:

kubectl label namespace kong kuma.io/sidecar-injection=enabled
Copied to clipboard!

Restart both the controller and the gateway to leverage sidecar injection:

kubectl rollout restart -n kong deployment kong-gateway kong-controller
Copied to clipboard!

Wait until pods are fully rolled out and look at them:

kubectl get pods -n kong
Copied to clipboard!

It is now visible that both pods have 2 containers, one for the application and one for the sidecar.

NAME                              READY   STATUS    RESTARTS      AGE
kong-controller-675d48d48-vqllj   2/2     Running   2 (69s ago)   72s
kong-gateway-674c44c5c4-cvsr8     2/2     Running   0             72s
Copied to clipboard!

Retrieve the public url for the gateway with:

export PROXY_IP=$(kubectl get svc -n kong kong-gateway-proxy -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $PROXY_IP
Copied to clipboard!

Verify the gateway still works:

curl -i $PROXY_IP
Copied to clipboard!

which outputs that there are no routes defined:

HTTP/1.1 404 Not Found
Date: Fri, 09 Feb 2024 15:25:45 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Content-Length: 103
X-Kong-Response-Latency: 0
Server: kong/3.5.0
X-Kong-Request-Id: e7dfe659c9e46639a382f82c16d9582f

{
  "message":"no Route matched with those values",
  "request_id":"e7dfe659c9e46639a382f82c16d9582f"
}%
Copied to clipboard!

Add a route to our demo-app

Patch gateway to allow routes in any namespace:

kubectl patch --type=json gateways.gateway.networking.k8s.io kong --patch='[{"op":"replace","path": "/spec/listeners/0/allowedRoutes/namespaces/from","value":"All"}]'
Copied to clipboard!

This is required because Kong ingress controller was created in the default namespace. To do this the Gateway API spec requires to explicitly allow routes from different namespaces.

Now add the gateway route in kuma-demo namespace which binds to the gateway kong defined in the default namespace:

echo "apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: demo-app
  namespace: kuma-demo
spec:
  parentRefs:
  - name: kong
    namespace: default
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: demo-app
      namespace: kuma-demo
      kind: Service
      port: 5050 " | kubectl apply -f -
Copied to clipboard!

This route is managed by the Kong ingress controller and not by Kong Mesh.

Now call the gateway:

curl -i $PROXY_IP/
Copied to clipboard!

Which outputs:

HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=UTF-8
Content-Length: 19
Connection: keep-alive
date: Fri, 09 Feb 2024 15:51:10 GMT
server: envoy
x-envoy-upstream-service-time: 0
X-Kong-Upstream-Latency: 2
X-Kong-Proxy-Latency: 0
Via: kong/3.5.0
X-Kong-Request-Id: 3b9d7d0db8c4cf25759d95682d6e3573

RBAC: access denied%
Copied to clipboard!

Notice the “forbidden” error. The quickstart applies restrictive default permissions, so the gateway can’t access the demo-app service.

To fix this, add a MeshTrafficPermission:

echo "apiVersion: kuma.io/v1alpha1
kind: MeshTrafficPermission
metadata:
  namespace: kuma-demo 
  name: demo-app
spec:
  targetRef:
    kind: Dataplane
    labels:
      app: demo-app
  from:
    - targetRef:
        kind: MeshSubset
        tags:
          app.kubernetes.io/name: gateway
          k8s.kuma.io/namespace: kong
      default:
        action: Allow" | kubectl apply -f -
Copied to clipboard!

Now, call the gateway again:

curl -i $PROXY_IP/api/counter -XPOST
Copied to clipboard!

Notice that the call succeeds:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 24
Connection: keep-alive
x-demo-app-version: v1
date: Thu, 29 May 2025 11:07:03 GMT
x-envoy-upstream-service-time: 59
server: envoy
X-Kong-Upstream-Latency: 81
X-Kong-Proxy-Latency: 1
Via: 1.1 kong/3.9.0
X-Kong-Request-Id: c63c57656349780c6b63191f80c85541

{"counter":1,"zone":""}
Copied to clipboard!

Next steps

Did this doc help?

Something wrong?

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!