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.

  1. ---
  2. title: service graph of the demo app with a Kong gateway on front
  3. ---
  4. flowchart LR
  5. subgraph Kong Gateway
  6. gw0(/ :80)
  7. end
  8. demo-app(demo-app :5000)
  9. redis(redis :6379)
  10. gw0 --> demo-app
  11. demo-app --> redis

Prerequisites

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

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. One option for kind is kubernetes-sigs/cloud-provider-kind may be helpful.

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:

  1. kubectl label namespace kong kuma.io/sidecar-injection=enabled

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

  1. kubectl rollout restart -n kong deployment kong-gateway kong-controller

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

  1. kubectl get pods -n kong

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

  1. NAME READY STATUS RESTARTS AGE
  2. kong-controller-675d48d48-vqllj 2/2 Running 2 (69s ago) 72s
  3. kong-gateway-674c44c5c4-cvsr8 2/2 Running 0 72s

Retrieve the public URL for the gateway with:

  1. export PROXY_IP=$(kubectl get svc --namespace kong kong-gateway-proxy -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  2. echo $PROXY_IP

Verify the gateway still works:

  1. curl -i $PROXY_IP

which outputs that there are no routes defined:

  1. HTTP/1.1 404 Not Found
  2. Date: Fri, 09 Feb 2024 15:25:45 GMT
  3. Content-Type: application/json; charset=utf-8
  4. Connection: keep-alive
  5. Content-Length: 103
  6. X-Kong-Response-Latency: 0
  7. Server: kong/3.5.0
  8. X-Kong-Request-Id: e7dfe659c9e46639a382f82c16d9582f
  9. {
  10. "message":"no Route matched with those values",
  11. "request_id":"e7dfe659c9e46639a382f82c16d9582f"
  12. }%

Add a route to our demo-app

Patch our gateway to allow routes in any namespace:

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

This is required because in the Kong ingress controller tutorial the gateway is 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 our kuma-demo namespace which binds to the gateway kong defined in the default namespace:

  1. echo "apiVersion: gateway.networking.k8s.io/v1
  2. kind: HTTPRoute
  3. metadata:
  4. name: demo-app
  5. namespace: kuma-demo
  6. spec:
  7. parentRefs:
  8. - name: kong
  9. namespace: default
  10. rules:
  11. - matches:
  12. - path:
  13. type: PathPrefix
  14. value: /
  15. backendRefs:
  16. - name: demo-app
  17. kind: Service
  18. port: 5000 " | kubectl apply -f -

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

Now call the gateway:

  1. curl -i $PROXY_IP/

Which outputs:

  1. HTTP/1.1 403 Forbidden
  2. Content-Type: text/plain; charset=UTF-8
  3. Content-Length: 19
  4. Connection: keep-alive
  5. date: Fri, 09 Feb 2024 15:51:10 GMT
  6. server: envoy
  7. x-envoy-upstream-service-time: 0
  8. X-Kong-Upstream-Latency: 2
  9. X-Kong-Proxy-Latency: 0
  10. Via: kong/3.5.0
  11. X-Kong-Request-Id: 3b9d7d0db8c4cf25759d95682d6e3573
  12. RBAC: access denied%

Notice the forbidden error. This is because the quickstart has very restrictive permissions as defaults. Therefore, the gateway doesn’t have permissions to talk to the demo-app service.

To fix this, add a MeshTrafficPermission:

  1. echo "apiVersion: kuma.io/v1alpha1
  2. kind: MeshTrafficPermission
  3. metadata:
  4. namespace: kuma-demo
  5. name: demo-app
  6. spec:
  7. targetRef:
  8. kind: MeshSubset
  9. tags:
  10. app: demo-app
  11. from:
  12. - targetRef:
  13. kind: MeshSubset
  14. tags:
  15. app.kubernetes.io/name: gateway
  16. k8s.kuma.io/namespace: kong
  17. default:
  18. action: Allow" | kubectl apply -f -

Call the gateway again:

  1. curl -i $PROXY_IP/increment -XPOST

Notice that the call succeeds:

  1. HTTP/1.1 200 OK
  2. Content-Type: application/json; charset=utf-8
  3. Content-Length: 41
  4. Connection: keep-alive
  5. x-powered-by: Express
  6. etag: W/"29-iu9zuSv48n703xjnEeBnBQzQFgA"
  7. date: Fri, 09 Feb 2024 15:57:27 GMT
  8. x-envoy-upstream-service-time: 7
  9. server: envoy
  10. X-Kong-Upstream-Latency: 11
  11. X-Kong-Proxy-Latency: 0
  12. Via: kong/3.5.0
  13. X-Kong-Request-Id: 886cc96df034ea37cfbbb0450a987049
  14. {"counter":149,"zone":"local","err":null}%

Next steps