Deploy custom plugins with Kong Gateway Operator

Uses: Kong Gateway Operator
Related Documentation
TL;DR

Build and push a plugin as a container image, then use a KongPluginInstallation to register it with the operator. Reference it in your GatewayConfiguration to make it available in Data Planes and configure its behavior using a KongPlugin resource.

Prerequisites

If you don’t have a Konnect account, you can get started quickly with our onboarding wizard.

  1. The following Konnect items are required to complete this tutorial:
    • Personal access token (PAT): Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.
  2. Set the personal access token as an environment variable:

    export KONNECT_TOKEN='YOUR KONNECT TOKEN'
    
  1. Install the Gateway API CRDs before installing Kong Ingress Controller.

    kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml
    
  2. Create a Gateway and GatewayClass instance to use.

echo "
apiVersion: v1
kind: Namespace
metadata:
  name: kong
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: kong
  annotations:
    konghq.com/gatewayclass-unmanaged: 'true'
spec:
  controllerName: konghq.com/gateway-operator
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong
spec:
  gatewayClassName: kong
  listeners:
  - name: proxy
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
         from: All
" | kubectl apply -n kong -f -
  1. Add the Kong Helm charts:

    helm repo add kong https://charts.konghq.com
    helm repo update
    
  2. Create a kong namespace:

    kubectl create namespace kong --dry-run=client -o yaml | kubectl apply -f -
    
  3. Install Kong Ingress Controller using Helm:

    helm upgrade --install kgo kong/gateway-operator -n kong-system --create-namespace  \
      --set image.tag=1.5 \
      --set kubernetes-configuration-crds.enabled=true \
      --set env.ENABLE_CONTROLLER_KONNECT=true \
      --set env.ENABLE_CONTROLLER_KONGPLUGININSTALLATION=true
    

This how-to requires some Kubernetes services to be available in your cluster. These services will be used by the resources created in this how-to.

kubectl apply -f https://developer.konghq.com/manifests/kic/echo-service.yaml -n kong

This how-to also requires 1 pre-configured route:

Plugin distribution using an OCI registry

Kong Gateway Operator can install Kong custom plugins packaged as container images. This guide shows how to package, install, and use a custom plugin in Kong Gateway instances managed by the Kong Gateway Operator.

Create a custom plugin (Optional)

If you already have a real plugin, you can skip this step.

mkdir myheader
echo 'local MyHeader = {}

MyHeader.PRIORITY = 1000
MyHeader.VERSION = "1.0.0"

function MyHeader:header_filter(conf)
  -- do custom logic here
  kong.response.set_header("myheader", conf.header_value)
end

return MyHeader
' > myheader/handler.lua

echo 'return {
  name = "myheader",
  fields = {
    { config = {
        type = "record",
        fields = {
          { header_value = { type = "string", default = "roar", }, },
        },
    }, },
  }
}
' > myheader/schema.lua

The directory should now look like this:

myheader
├── handler.lua
└── schema.lua

0 directories, 2 files

Build a container image (Optional)

This section is optional. The rest of this guide uses a pre-published image, and the following information is provided if you want to package your own custom plugin.

Plugin-related files should be at the root of the image, so the Dockerfile for the plugin would look like this:

echo 'FROM scratch

COPY myheader /
' > Dockerfile

In this example, myheader is a directory that contains handler.lua and schema.lua.

Build the image:

docker build -t myheader:1.0.0 .

Next, push the image to a public or private registry available to the Kubernetes cluster where Kong Gateway Operator is running.

docker tag myheader:1.0.0 $YOUR_REGISTRY_ADDRESS/myheader:1.0.0
docker push $YOUR_REGISTRY_ADDRESS/myheader:1.0.0

In this example, the plugin is available in the public registry (Docker Hub) as kong/plugin-example:1.0.0. The following steps use the same source.

Install the plugin

  1. Install the plugin using the KongPluginInstallation resource. This resource makes the plugin available for instances of Kong Gateway resources:

    echo '
    kind: KongPluginInstallation
    apiVersion: gateway-operator.konghq.com/v1alpha1
    metadata:
      name: custom-plugin-myheader
    spec:
      image: kong/plugin-example:1.0.0
    ' | kubectl apply -f -
    

    Verify that the plugin is fetched and available by examining the status of the KongPluginInstallation resource:

    kubectl get kongplugininstallations.gateway-operator.konghq.com -o jsonpath-as-json='{.items[*].status}'
    

    The output should look like this:

    [
      {
            "conditions": [
                 {
                      "lastTransitionTime": "2024-10-09T19:39:39Z",
                      "message": "plugin successfully saved in cluster as ConfigMap",
                      "observedGeneration": 1,
                      "reason": "Ready",
                      "status": "True",
                      "type": "Accepted"
                 }
            ],
            "underlyingConfigMapName": "custom-plugin-myheader-hnzf9"
      }
    ]
    

    In case of problems, the respective conditions or respective resources will provide more information.

    The KongPluginInstallation resource creates a ConfigMap with the plugin content. Additional ConfigMaps are created when a plugin is referenced by other resources. The operator automatically manages the lifecycle of all these ConfigMaps.

  2. Make the plugin available in a Gateway resource by referencing it in the spec.dataPlaneOptions.spec.pluginsToInstall field of the GatewayConfiguration resource. Plugins can be referenced across namespaces without any additional configuration.

    echo '
    kind: GatewayConfiguration
    apiVersion: gateway-operator.konghq.com/v1beta1
    metadata:
      name: kong
      namespace: default
    spec:
      dataPlaneOptions:
         deployment:
            replicas: 2
            podTemplateSpec:
              spec:
                 containers:
                    - name: proxy
                      image: kong/kong-gateway:3.10
         pluginsToInstall:
            - name: custom-plugin-myheader
      controlPlaneOptions:
         deployment:
            podTemplateSpec:
              spec:
                 containers:
                    - name: controller
                      image: kong/kubernetes-ingress-controller:3.4
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: kong
    spec:
      controllerName: konghq.com/gateway-operator
      parametersRef:
         group: gateway-operator.konghq.com
         kind: GatewayConfiguration
         name: kong
         namespace: default
    ' | kubectl apply -f -
    
  3. Deploy an example service and expose it by configuring HTTPRoute with the custom plugin:

    kubectl apply -f https://developer.konghq.com/assets/kubernetes-ingress-controller/examples/echo-service.yaml
    

    Next, add the HTTPRoute with the custom plugin. The configuration of the plugin is provided with the KongPlugin CRD, where the field plugin is set to the name of the KongPluginInstallation resource.

     echo "
     apiVersion: configuration.konghq.com/v1
     kind: KongPlugin
     metadata:
       name: myheader
       namespace: kong
       annotations:
         kubernetes.io/ingress.class: kong
     plugin: custom-plugin-myeader
     config:
       header_value: my-first-plugin
     " | kubectl apply -f -
    

    Next, apply the KongPlugin resource by annotating the service resource:

     kubectl annotate -n kong service echo konghq.com/plugins=myheader
    

Validate your configuration

Ensure that everything is up and running and make a request to the service.

curl "$PROXY_IP/echo"

You should see the following header:

myheader: my-first-plugin
curl "$PROXY_IP/echo"

You should see the following header:

myheader: my-first-plugin
Something wrong?

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!