Go Plugin Development on Kong

By | February 20, 2020

Earlier this year, Kong has announced brilliant features. You check it out the following.

https://konghq.com/blog/kong-gateway-2-0-0-released/

I was very interested in one of them which is we will be able to develop Go plugins on Kong. I built a plugin to test and as soon as possible I’m writing this blog post eventually. I’m going to demonstrate a plugin that checks the consumer key from query string.

I used to run DB-less Kong on Docker and I prefer that either.

FROM kong/go-plugin-tool:2.0.4-alpine-latest AS builder

RUN mkdir -p /tmp/key-checker/

COPY . /tmp/key-checker/

RUN cd /tmp/key-checker/ && \
    go get github.com/Kong/go-pdk && \
    go mod init kong-go-plugin && \
    go get -d -v github.com/Kong/go-pluginserver && \
    go build github.com/Kong/go-pluginserver && \
    go build -buildmode plugin key-checker.go

FROM kong:2.0.4-alpine

RUN mkdir /tmp/go-plugins
COPY --from=builder  /tmp/key-checker/go-pluginserver /usr/local/bin/go-pluginserver
COPY --from=builder  /tmp/key-checker/key-checker.so /tmp/go-plugins
COPY config.yml /tmp/config.yml

USER root
RUN chmod -R 777 /tmp
RUN /usr/local/bin/go-pluginserver -version && \
    cd /tmp/go-plugins && \
    /usr/local/bin/go-pluginserver -dump-plugin-info key-checker
USER kong

In this way, we copy our required files. Let’s go into details. Firstly, we create a builder image and I copy my key-checker.go file and I build it as a go plugin. After that, I get that file from the builder image and I put it in Kong image. That’s straightforward.

Let’s look over the Go file.

package main

import (
    "github.com/Kong/go-pdk"
)

// it represents to config parameters into the config.yml
type Config struct {
    Apikey string
}

func New() interface{} {
    return &Config{}
}

func (conf Config) Access(kong *pdk.PDK) {
    key, err := kong.Request.GetQueryArg("key")
    apiKey := conf.Apikey 

    if err != nil {
        kong.Log.Err(err.Error())
    }

    //it adjusts the header parameters in this way.
    x := make(map[string][]string)
    x["Content-Type"] = append(x["Content-Type"], "application/json")

    //If the key of the consumer is not equal to the claimed key, kong doesn't ensure the proxy
    if apiKey != key {
        kong.Response.Exit(403, "You have no correct consumer key.", x) 
    }
}

This file tells us that we check the key from the query string. If it is not equal to the key from the config file, we don’t provide proxy service. In another case, it will ensure the proxy well and clearly the claimed URL from the config file. This is the config file. Also, I try to show changing header parameters and I write content type as a parameter for only showing.

# go.yml
_format_version: "1.1"
services:
- url: https://reqres.in/api/users?page=2
  routes:
  - paths:
    - "/"
  plugins:
  - name: key-checker
    config:
      apikey: mysecretconsumerkey

To build the Dockerfile I run this command.

docker build -t kong-demo .

Once it built, I run the following command. I point the related directories by using environment variables.

docker run -ti --rm --name kong-go-plugins \
  -e "KONG_DATABASE=off" \
  -e "KONG_GO_PLUGINS_DIR=/tmp/go-plugins" \
  -e "KONG_DECLARATIVE_CONFIG=/tmp/config.yml" \
  -e "KONG_PLUGINS=key-checker" \
  -e "KONG_PROXY_LISTEN=0.0.0.0:8000" \
  -p 8000:8000 \
  kong-demo

Right, we’re able to check the service. As you can see, the key is not equal. Therefore the status code is 403 and proxy service is not working.

When I enter the correct consumer key, as expected Kong ensures the proxy service clearly and URL is requested.

Conclusion

This feature drastically will be useful for Go developers and you could build pretty cool plugins in this way. I also want to share some practical URLs like the following. I hope the blog post ignites the minds to build awesome Go plugins on Kong. Happy Konging!

https://docs.konghq.com/2.0.x/go

https://godoc.org/github.com/Kong/go-pdk