Careful!
You are browsing documentation for the next version of Kuma. Use this version at your own risk.
Use Kong as a delegated Gateway
To get traffic from outside your mesh inside it (North/South) with Kuma 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.
--- title: Service graph of the demo app with a Kong gateway on front --- flowchart LR subgraph Kong Gateway gw0(/ :80) end demo-app(demo-app :5050) kv(kv :5050) gw0 --> demo-app demo-app --> kv
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:
helm upgrade \
--install \
--create-namespace \
--namespace kuma-system \
kuma kuma/kuma
kubectl wait -n kuma-system --for=condition=ready pod --selector=app=kuma-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.
You only need to install the controller (helm install kong kong/ingress -n kong --create-namespace
) and enable the Gateway API.
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
Restart both the controller and the gateway to leverage sidecar injection:
kubectl rollout restart -n kong deployment kong-gateway kong-controller
Wait until pods are fully rolled out and look at them:
kubectl get pods -n kong
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
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
Verify the gateway still works:
curl -i $PROXY_IP
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"
}%
Add a route to our demo-app
Now add the gateway route in kuma-demo
namespace which binds to the gateway kong
defined in the kong
namespace:
echo "apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-app
namespace: kuma-demo
spec:
parentRefs:
- name: kong
namespace: kong
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: demo-app
namespace: kuma-demo
kind: Service
port: 5050 " | kubectl apply -f -
This route is managed by the Kong ingress controller and not by Kuma.
Now call the gateway:
curl -i $PROXY_IP/
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%
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 -
Now, call the gateway again:
curl -i $PROXY_IP/api/counter -XPOST
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":""}
Next steps
- Read more about the different types of gateways in the managing ingress traffic docs.
- Learn about setting up observability to get full end to end visibility of your mesh.