How to Use Istio With Kong Ingress Controller
Transforming software from monolith to micro services is becoming a trend in the past few years. Covid-19 has undoubtedly pushed this transformation further. Previously I had talked a lot about using Kong as the API gateway to secure, transform and monitor client requests to upstream services. What about traffics between internal services? The answer is using Service Mesh.
According to this article on solo.io, Istio has the most market share at the moment. In today’s post, I would show you how to use Kong Ingress Controller with Istio including demos of enabling mTLS, adding AuthorizationPolicy, change traffic distribution using VirtualService and DestinationRule.
Let’s get started.
Prerequisites:
- Istioctl: If you haven’t installed it, you can follow the official doc.
- Helm: I need to use helm to install Kong. Helm version is 3.7.1.
- Your cluster need to be able to provision
LoadBalancer. I am using metalLB locally.
Install Istio
As suggested by official documentation, I am going to install istio with minimal configuration profile first. Then I will install Kong Ingress Controller or Istio Ingress Gateway to allow requests entering the mesh.
1 | istioctl install --set profile=minimal \ |
Install BookInfo
We will use istio’s bookinfo in our demo.
1 | # Create namespace bookinfo |
Next I will show you some basic usage of Istio Ingress Gateway so we can compare it with Kong Ingress Controller. If you are only interested in testing Kong Ingress controller, you can go to the next section.
(Optional) Istio Ingress Gateway
Installation
Add helm chart
1
2helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo updateInstall Istio Ingress Gateway
1
2kubectl create namespace istio-ingress
helm install istio-ingress istio/gateway -n istio-ingress --waitOnce the pod is ready, let’s save load balancer IP to
ISTIO_INGRESS_GATEWAY.1
export ISTIO_INGRESS_GATEWAY=$(kubectl -n istio-ingress get svc istio-ingress -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
Let’s curl $ISTIO_INGRESS_GATEWAY
1 | curl -s http://$ISTIO_INGRESS_GATEWAY -iv |
We would get Connection refused error because istio ingress gateway requires Gateway resource to receive incoming HTTP/TCP connections.
1 | * Trying 172.18.18.150:80... |
Create Gateway
Let’s create a Gateway resource.
1 | kubectl apply -f - << EOF |
Then we can try sending the request again and we should be able to connect
1 | curl http://$ISTIO_INGRESS_GATEWAY -iv |
Create VirtualService
Next step we will use VirtualService to route requests to service productpage at port 9080.
1 | kubectl apply -f - << EOF |
Now we can access the product page.
1 | curl http://$ISTIO_INGRESS_GATEWAY/productpage |
Enable JWT auth
We can also enable JWT authentication on ingress gateway by applying below RequestAuthentication and AuthorizationPolicy.
1 | kubectl apply -f - << EOF |
If we access curl http://$ISTIO_INGRESS_GATEWAY/productpage -i again, we will get 403 Forbidden.
1 | HTTP/1.1 403 Forbidden |
To access productpage again we need to pass a JWT token with authorization bearer header in our request.
1 | curl http://$ISTIO_INGRESS_GATEWAY/productpage -H "Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3Rpby10ZXN0aW5nQGF1Zm9tbSIsInN1YiI6ImlzdGlvLXRlc3RpbmdAYXVmb21tIiwidGVzdCI6ImlzdGlvIn0.bkWG-fESbgVUcWBSfa-i4q7ZNY_gk3LO18CDcjz07w74JaoDvSIn347LQrm5pF8r6Hb1lmhlC6p7y4iCDNeWPZ6azqpql4MPEAdM2sZvZphriJFj8XCuKsW4Qn2yOohsPm4QsRDUKxME8wMswPqfQo__0DSUgo7bv56HsBTrb7mAKoLw4qiv_MRjU9X_FwP75JgNh64rGUfKnSU1jWLgwlQH7_jcxHdSK57QvvFcjxgfSBAJ62vOmQld9goVQn8Q7M-cQmrgs3SDeuV0XhNjY3Ifp-jjx4PBphu5UPIZNyHWZ3nLM4GN518-DUbsYGYs1KbrLQZmlMk6oDSAyIdszQ" |
Let’s move on and try Kong Ingress Controller.
Install Kong
I will install Kong in dbless mode in namespace kong and auto inject istio sidecar proxy.
1 | # Add kong helm chart repo |
Once the Pod is running, we can save kong proxy ip to KONG_PROXY_IP.
1 | export KONG_PROXY_IP=$(kubectl -n kong get svc my-kong-kong-proxy -o=jsonpath='{.status.loadBalancer.ingress[0].ip}') |
Use Kong Ingress Controller
As I mentioned in my previous post, Kong ingress controller use CRDs and annotations to extend native kubernetes objects.
Create Ingress
Let’s start by creating an Ingress object. This ingress object has the same routes as the VirtualSerivce above.
1 | kubectl apply -f - << EOF |
Now we can access /productpage via Kong.
1 | curl $KONG_PROXY_IP/productpage |
Enable JWT plugin
We will then use JWT plugin to restrict access. I am applying the plugin globally.
1 | kubectl apply -f - << EOF |
Now when we access /productpage route again,
1 | curl $KONG_PROXY_IP/productpage -i |
we should get 401 Unauthorized error.
1 | HTTP/1.1 401 Unauthorized |
If we pass in an authorization bearer header, we are allowed to access the service again.
1 | curl -s http://$KONG_PROXY_IP/productpage -H "Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3Rpby10ZXN0aW5nQGF1Zm9tbSIsInN1YiI6ImlzdGlvLXRlc3RpbmdAYXVmb21tIiwidGVzdCI6ImlzdGlvIn0.bkWG-fESbgVUcWBSfa-i4q7ZNY_gk3LO18CDcjz07w74JaoDvSIn347LQrm5pF8r6Hb1lmhlC6p7y4iCDNeWPZ6azqpql4MPEAdM2sZvZphriJFj8XCuKsW4Qn2yOohsPm4QsRDUKxME8wMswPqfQo__0DSUgo7bv56HsBTrb7mAKoLw4qiv_MRjU9X_FwP75JgNh64rGUfKnSU1jWLgwlQH7_jcxHdSK57QvvFcjxgfSBAJ62vOmQld9goVQn8Q7M-cQmrgs3SDeuV0XhNjY3Ifp-jjx4PBphu5UPIZNyHWZ3nLM4GN518-DUbsYGYs1KbrLQZmlMk6oDSAyIdszQ" |
Next we will explore some istio features and see how it works with Kong ingress controller.
Use Istio features
Monitor Mesh
Monitoring might be one of the most important features that you use service mesh for. I will use official sample yaml file to install kiali dashboard and prometheus and jaeger will be used to get some data from mesh
1 | kubectl apply -f https://raw.githubusercontent.com/istio/istio/master/samples/addons/prometheus.yaml |
Once pods is ready, we can access dashboard with istioctl dashboard kiali.
Let’s go to Graph and then let’s tick Security in the Display dropdown. Please make sure we are checking Namespace bookinfo. After that, let’s send some requests.
1 | while true |
We should see below traffic flow.

As we can see not all traffics are encrypted.
Enable mTLS
Zero Trust architecture requires ALL traffics to be encrypted and verified. We can enable mTLS easily with istio to achieve this goal. What we need to do is to apply below PeerAuthentication in root namespace istio-system. This will enable strict mTLS in the mesh.
1 | kubectl apply -f - <<EOF |
If we visit curl $KONG_PROXY_IP/productpage now we will get curl: (56) Recv failure: Connection reset by peer error because the sidecar in Kong pod is expecting a client certificate to be passed in with the request. As Kong ingress controller is our entry point, we want to allow requests coming in. What we need to do is to disable PeerAuthentication in kong namespace so the traffic between Kong and Bookinfo remains encrypted and the client requests enter the mesh via Kong.
1 | kubectl apply -f - <<EOF |
Once that’s added, let’s try curl $KONG_PROXY_IP/productpage again. This time you would get upstream connect error or disconnect/reset before headers. reset reason: connection termination error. To fix this issue we need to annotate productpage service and our ingress.
1 | kubectl -n bookinfo annotate service productpage ingress.kubernetes.io/service-upstream=true |
The first annotation ingress.kubernetes.io/service-upstream=true allows Kong to send request to this service ip address instead of the pod IP.
The second annotation konghq.com/preserve-host=false helps us to NOT preserve request host header. The reason is that we want productpage to get the request from sidecar.
After applying annotations we can send our request again and we should see below in graph. As we can see ALL traffic are secured now.

Split Traffics
Kong can be used to load balance client requests to different backends. However when the backend services are not directly connected to Kong, there is not much Kong can do. For example, in our demo Kong has no control over which review pod productpage send requests to. In order to route requests as we want them to, we can use VirtualService and DistinationRule to fine tune traffic inside mesh.
Let me give you an example. Let’s continue sending our request to /productpage.
1 | while true |
Then go to Kiali Dashboard -> Graph and then select Traffic Distribution under Display dropdown. Because the default load balancing algorithm is ROUND_ROBIN, we can see requests are almost equally distributed amoung 3 subsets.

Let’s apply below VirtualService and DestinationRule. These two objects split the traffic to different review subsets based on its assigned weight. In the example I want 10% of traffic goes to v1, 60% goes to v2 and 30% goes to v3.
1 | kubectl apply -f - <<EOF |
After a while we should see the traffic distrubution changes.

That’s all I want to show you today. This is just the tip of the iceberg, istio have a ton of more features that you can explore.
Thank you for reading, see you next time.