Setting up Gravitee API Management behind Istio Service Mesh

Kamiel Amadpour
graviteeio
Published in
7 min readMay 20, 2022

In this blog post we’ll show you how to combine all of the features of Gravitee’s API Management platform alongside Istio as a service mesh.

Ricardo Gomez Angel on Unsplash

Introduction

Commonly, you will want to work with East-West traffic (for example when you’re dealing with microservices) as well as North-South traffic (typically seen when dealing with API to client/server interactions).

A service mesh is a dedicated infrastructure layer for facilitating service-to-service communications between services or microservices in East-West traffic. You can achieve this using a proxy and Istio, an open source service mesh that layers transparently onto existing distributed applications. It provides a uniform and more efficient way to secure, connect, and monitor services.

In this post we will show how you how you can combine all the features of Gravitee for API Management, alongside Istio as a service mesh. To do this, we will configure Istio for a given namespace as well as installing Gravitee APIM, but this time it will be behind the Istio instance.

Installing and Configuring Istio

To install Istio, first you need to download istioctl from its release page for your specific operation system and unzip the file, and either add the folder to your path, or, for example for Linux or Mac, you can just simply copy the istioctl to your bin folder.

sudo cp ./istioctl /usr/local/bin/

Once you have istioctl installed, then you install istio in your cluster. As Gravitee is relying on Nginx, we don’t need to install the Istio ingress gateway instances, so the minimal profile which includes the Istio control plane (istiod) is sufficient in our case.

istioctl install --set profile=minimal -y

** minimal profile will not install istio-ingressgateway, istio-egressgateway components

** if you are running Kubernetes on some local cluster, for example microk8s, you can simply enable Istio with this command microk8s enable istio

Now you should see the Istio deployment running the following command:

kubectl get deploy -n istio-system

NAME     READY   UP-TO-DATE   AVAILABLE   AGE
istiod 1/1 1 1 1m

Installing Gravitee APIM using Helm

For this example we will install Gravitee APIM in the default namespace. Before installing APIMl, let’s first enable Istio on default namespace:

helm install graviteeio-apim3x graviteeio/apim3
kubectl label namespace default istio-injection=enabled

and then we install APIM as usual:

helm install graviteeio-apim3x graviteeio/apim3

Running kubectl get deploy will show us current deployments:

NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
graviteeio-apim3x-api 1/1 1 1 1m
graviteeio-apim3x-ui 1/1 1 1 1m
graviteeio-apim3x-portal 1/1 1 1 1m
graviteeio-apim3x-gateway 1/1 1 1 1m

If you look at the pods, you should see the Gravitee pods with their Istio sidecars already injected:

Kubectl get pods

NAME                                       READY STATUS RESTARTS AGE
graviteeio-apim3x-api-55994c5c6b-l94n4 2/2 Running 0 1m
graviteeio-apim3x-ui-66677875c-b9cvp 2/2 Running 0 1m
graviteeio-apim3x-portal-565b89f97b-82clk 2/2 Running 0 1m
graviteeio-apim3x-gateway-5f878756c7-4t4tf 2/2 Running 0 1m

Adding a New API

First we will create a Deployment for an existing sample Gravitee echo image in our cluster and then later on, we will define an API pointing to its service inside Gravitee console:

cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: gravitee-echo-api
spec:
replicas: 1
selector:
matchLabels:
app: gravitee-echo-api
version: v1
template:
metadata:
labels:
app: gravitee-echo-api
version: v1
spec:
containers:
- image: graviteeio/gravitee-echo-api
imagePullPolicy: IfNotPresent
name: gravitee-echo-api
ports:
- containerPort: 8080
EOF

If you look at the existing pods, there should be :

NAME                                       READY STATUS RESTARTS AGE
graviteeio-apim3x-api-55994c5c6b-l94n4 2/2 Running 0 1m
graviteeio-apim3x-ui-66677875c-b9cvp 2/2 Running 0 1m
graviteeio-apim3x-portal-565b89f97b-82clk 2/2 Running 0 1m
graviteeio-apim3x-gateway-5f878756c7-4t4tf 2/2 Running 0 1m
gravitee-echo-api-58cfc58cbb-9x9lz 2/2 Running 0 98s

Now let’s create a service to access this new pod:

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
name: gravitee-echo-api
labels:
app: gravitee-echo-api
service: gravitee-echo-api
spec:
ports:
- name: http
port: 80
targetPort: 8080
selector:
app: gravitee-echo-api
EOF

Once everything is created successfully, we will login into the Gravitee Console and define a new API pointing to our local echo service, which is running behind Istio. It is also possible to do exactly the same things using our Kubernetes CRDs that can be found in here. If you are new to setting up an API in Gravitee APIM, you can follow this guide.

We will use “http://gravitee-echo-api.default.svc.cluster.local:80" for the backend:

To keep it as simple as possible, we just enable a Keyless (public) plan which doesn’t require any authentication to call this endpoint later:

Finally, we will create and start the API:

If we make a request to this newly created API, we should get a response similar to this one :

curl --insecure https://apim.example.com/gateway/lecho (replace apim.example.com with you own host name)

{
"headers" : {
"host" : "gravitee-echo-api.default.svc.cluster.local",
"x-request-id" : "f773380c01e67d98240e55ee12fac0a6",
"x-real-ip" : "192.168.0.1",
"x-forwarded-for" : "192.168.0.1",
"x-forwarded-host" : "apim.example.com",
"x-forwarded-port" : "443",
"x-forwarded-proto" : "https",
"x-forwarded-scheme" : "https",
"x-scheme" : "https",
"user-agent" : "curl/7.68.0",
"accept" : "*/*",
"x-gravitee-transaction-id" : "504f05ff-956b-4926-8f05-ff956b492629",
"x-gravitee-request-id" : "504f05ff-956b-4926-8f05-ff956b492629",
"accept-encoding" : "deflate, gzip",
"x-envoy-attempt-count" : "1",
"x-envoy-internal" : "true",
"x-forwarded-client-cert" : "By=spiffe://cluster.local/ns/default/sa/default;Hash=f6351b3c716ccef8775e177f690ddac4969561abb08ecce27196cee0e8c31524;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/graviteeio-apim3x-apim3",
"x-b3-traceid" : "b60266875b6b61589228b8ee25f3fbcc",
"x-b3-spanid" : "2b89b363d7d82594",
"x-b3-parentspanid" : "4e92ae8e94afb3cc",
"x-b3-sampled" : "1"
}
}

So as you can see, we could successfully reach the gravitee-echo-api from the Gravitee Gateways that are both running behind Istio. The whole request-response cycle is showed below:

Enabling mTLS for Istio

In order to enable mTLS for a specific namespace, we can use Istio Peer Authentication custom resource definition. In the mTLS mode, we can specify to different values, STRICT and PERMISSIVE, and it has impact on how Istio will handle unauthorised connections coming from outside a namespace which is not using Istio.

For example, if your Nginx is running in a its own dedicated namespace and Istio is not enabled for that namespace, if you use “STRICT” mode, then Istio will reject the traffic from Nginx to the Gravitee Gateway, which is behind Istio and protected with mTLS authentication. However, if you use “PERMISSIVE” mode, then the request will be forwarded to Gravitee Gateway and this is what we are going to use in here:

cat <<EOF | kubectl apply -f -
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "default"
namespace: "default"
spec:
mtls:
mode: PERMISSIVE
EOF

If we now make a new call to our gravitee-echo-api, we should get exactly the same result as before:

{
"headers" : {
"host" : "gravitee-echo-api.default.svc.cluster.local",
"x-request-id" : "59a88f9bf30b7266db7a661322136911",
"x-real-ip" : "192.168.0.1",
"x-forwarded-for" : "192.168.0.1",
"x-forwarded-host" : "apim.example.com",
"x-forwarded-port" : "80",
"x-forwarded-proto" : "http",
"x-forwarded-scheme" : "http",
"x-scheme" : "http",
"user-agent" : "curl/7.68.0",
"accept" : "*/*",
"x-gravitee-transaction-id" : "a850fb59-f560-4dd2-90fb-59f5600dd274",
"x-gravitee-request-id" : "a850fb59-f560-4dd2-90fb-59f5600dd274",
"accept-encoding" : "deflate, gzip",
"x-envoy-attempt-count" : "1",
"x-envoy-internal" : "true",
"x-forwarded-client-cert" : "By=spiffe://cluster.local/ns/default/sa/default;Hash=f6351b3c716ccef8775e177f690ddac4969561abb08ecce27196cee0e8c31524;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/graviteeio-apim3x-apim3",
"x-b3-traceid" : "e27b29b5e1ececff658a582b5a60f6a6",
"x-b3-spanid" : "fcfb6f836c28e098",
"x-b3-parentspanid" : "5a297a497fc2b9ba",
"x-b3-sampled" : "1"
}
}

If you set the mTLS mode to “STRICT”, you will get a 502 error that shows Istio is rejecting the trafic coming from an unauthorised connection:

<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx</center>
</body>
</html>

Wrapping up

We have shown you how to combine all of the features of Gravitee’s API Management platform alongside Istio as a service mesh. We’ve shown you how to install and configure Istio alongside API Management for a given name space, as well as enabling mTLS for Istio. If you’ve got any questions, or to let us know how you get on, join us on the community forum.

--

--