How to secure Kong Admin API

business code coding computer
Reading Time: 3 minutes

Kong is an open source API Gateway and microservice management layer based on Nginx and the lua-nginx-module. It has two versions: the OSS version and the Enterprise mode. The OSS mode provides the admin API and the Kong Manager while the enterprise mode adds on Dev Portal, Vitals and RBAC to these OSS functionalities. The Kong gateway has several plugins and uses them to achieve several added functionalities.

In this blog, we will be using the basic-authentication plugin to secure the Kong admin API. We will up set a API key. We will need to pass this API key with the request header or as query string to authenticate to the admin API server. I will be deploying the Kong gateway on the Kubernetes cluster and expose the admin API with ingress.

Prerequisites
  • Kubernetes Cluster(I will be using GKE)
  • Helm 3 or higher

Deploying the Kong API gateway using Helm chart

I have provided a minimal values.yaml file for the Kong helm chart. This values.yaml file will deploy the Kong ingress controller along with the admin API.

# Create a file values-admin-api.yaml
image:
  repository: kong/kong-gateway
  tag: "2.7.0.0-alpine"

admin:
  enabled: true
  type: ClusterIP
  http:
    enabled: true
  tls:
    enabled: false
  ingress:
    enabled: true
    ingressClassName: kong
    hostname: admin-api.kong.link

To deploy the Kong, execute the following commands:

# To add the Kong helm chart repository
helm repo add kong https://charts.konghq.com
helm repo update

# To install the kong helm chart
helm install kong kong/kong -f values-blog.yaml --namespace kong --create-namespace

# Store the IP and Port for the Kong proxy service, the service for the Kong ingress controller.

HOST=$(kubectl get svc --namespace kong kong-kong-proxy -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

PORT=$(kubectl get svc --namespace kong kong-kong-proxy -o jsonpath='{.spec.ports[0].port}')

export PROXY_IP=${HOST}:${PORT}

Store the PROXY_IP variable as we will be needing it later.

Securing the admin API

We can check if we can access the admin API using the command:

curl $PROXY_IP/status -H "host: admin-api.kong.link" -I

The request will start with something like:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 2136
Connection: keep-alive

The response status code shows 200. This means we have access to the admin API. But this is a security vulnerability as it is publicly accessible. So anyone will be able to modify the routes by accessing the API.

So now we will create a Kong Plugin, Kong Consumer to link the plugin to the ingress resource to implement the basic authentication. We will be using Kong Plugin and Kong Consumer CRDs to implement this.

First, we need to delete the ingress that was already deployed with the helm chart for the API.

helm upgrade kong kong/kong -f values-blog.yaml --namespace kong --set admin.ingress.enabled=false

Next, lets create a Kong Plugin, an Ingress and a Kong Consumer to link Plugin and the Ingress.

Creating a secret to store the admin API secrets.

kubectl create secret generic -n kong adminapi-consumer-secret --from-literal=key=admin123 --from-literal=kongCredType=key-auth
Creating the Kong Plugin Manifest

Create a file `KongPluing.yaml` with the following content:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: admin-api-auth
  namespace: kong
config:
  key_names:
    - apikey
  key_in_header: true
  key_in_query: true
  hide_credentials: true
plugin: key-auth
disabled: false

To apply the yaml manifest, execute:

kubectl apply -f KongPlugin.yaml

Kong Consumer Manifest

We will create a manifest kongConsumer.yaml with the following content:

apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: adminapi-consumer
  namespace: kong
  annotations:
    kubernetes.io/ingress.class: kong
username: Knoldus
credentials:
  - adminapi-consumer-secret

Apply the above manifest using command, kubectl apply -f kongConsumer.yaml

Ingress Resource for Kong Admin API

We will create a ingress.yaml to store the following content:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kong-admin-api
  namespace: kong
  annotations:
    konghq.com/plugins: admin-api-auth
spec:
  ingressClassName: kong
  rules:
  - host: admin-api.kong.link
    http:
      paths:
      - backend:
          service:
            name: kong-kong-admin
            port:
              number: 8001
        path: /
        pathType: ImplementationSpecific

Apply the ingress Manifest using the command, kubectl apply -f ingress.yaml

Checking the deployment

We will again curl the admin api using the command:

curl $PROXY_IP/status -H "host: admin-api.kong.link" -I

This time we will notice, the response status code will be 401 unauthorized.

HTTP/1.1 401 Unauthorized
Date: Tue, 15 Feb 2022 07:22:42 GMT

So we can say that the admin API is now not accessible publicly. Let’s pass the api key we set as the header and query string.

# To pass the api key as query string
curl "$PROXY_IP/status?apikey=admin123" -H "host: admin-api.kong.link" -I

# To pass the API key as Header
curl $PROXY_IP/status -H "host: admin-api.kong.link" -H "apikey: admin123" -I

Both of the above command will have an output starting like:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 2133

For the final checking lets pass an incorrect API key.

curl $PROXY_IP/status -H "host: admin-api.kong.link" -H "apikey: randomkey" -I

# This will generate an output
HTTP/1.1 401 Unauthorized
Date: Tue, 15 Feb 2022 07:30:52 GMT
Content-Type: application/json; charset=utf-8

So the admin api is secured from any unauthorized access.

Conclusion

In this blog, we will deploy Kong admin API using helm chart and explore how to implement authentication and limited access to admin api using Kong’s basic authentication plugin. The documentation for Kong and KongHub are provided in the link.

Reference

knoldus

Written by 

Dipayan Pramanik is a DevOps Software Consultant at Knoldus Inc. He is passionate about coding, DevOps tools, automating tasks and is always ready to take up challenges. His hobbies include music and gaming.