See what makes Kong the fastest, most-adopted API gateway
Check out the latest Kong feature releases and updates
Single platform for SaaS end-to-end connectivity
Enterprise service mesh based on Kuma and Envoy
Collaborative API design platform
How to Scale High-Performance APIs and Microservices
Call for speakers & sponsors, Kong API Summit 2023!
4 MIN READ
This tutorial shows you how to create a custom Kong Gateway plugin with Go programming language. The sample plugin I created adds an extra layer for security between consumers and producers. The way it works is it identifies consumers through a consumer-key from a query string. Without this parameter, they’ll get an error message.
At Kong Summit 2019, Kong announced that users could develop plugins for Kong Gateway with Go programming language.
To dive deeper into how Kong supports Go programming, visit the Kong Gateway documentation.
Blog Post: Creating Your First Custom Lua Plugin for Kong Gateway >>
I used declarative configuration (decK) to create my custom Go plugin for Kong Gateway.
In my file, I have services with routes and paths. It will redirect the https://reqres.in/api/users?page=2 URL.
_format_version: "1.1" services: - url: https://reqres.in/api/users?page=2 routes: - paths: - "" plugins: - name: key-checker config: apikey: mysecretconsumerkey
At the same time, I have a custom plugin that will check the API key before the redirect occurs. It will run like a proxy service.
I’ll start writing the plugin from my empty Go file called key-checker.go. I’ll import the Go PDK file, which allows my Go plugin to access functionality provided by the Kong PDK. To use it, I’ll add github.com/kong/go-pdk to the list of packages imported by my plugin.
package main import ( "github.com/Kong/go-pdk" )
Next, I’ll create a struct for configuration to represent the config parameters in the config.yaml config file.
type Config struct { Apikey string }
I need to add a function called “New.” Doing this returns an interface.
func New() interface{} { return &Config{} }
After that, I’ll create a func. In Go programming language, figure out the request and response handlers for the processing lifecycle. I’ll make a func called “Access,” which gets the requests and responds.
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()) }
With Func (conf Config) Access(kong *pdk.PDK) type, I’m getting the key parameter from the URL, and I need the parameter in the config file. For example, apiKey := conf.Apikey. If there’s an error, the system will log it.
x := make(map[string][]string) x["Content-Type"] = append(x["Content-Type"], "application/json") if apiKey != key { kong.Response.Exit(403, "Youu have no correct key", x) } }
In the Docker file, I created a builder image and copied my local files into it.
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
After that, I got the files to build an image into the Kong image.
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
The Go plugin server’s role is to dynamically load the Go plugins and execute their code on demand. Kong handles the go-pluginserver lifecycle. All it needs to know is where to find the go-pluginserver’s executable.
In this case, I’ll do this by running Docker images using the default path. Therefore, I don’t need an extra parameter. When you build a Kong plugin, you should use the same compiler version, configuration, environment variables, etc., with the Go plugin server. To guarantee consistency, I’ve built my custom Go plugin server in the same Docker image.
After that, copy the built files into the Kong image.
My plugin is ready to run as a container.
docker build -t kong-demo .
After that, I’m going to run the image as a container.
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
I’m defining some paths, such as plugins directory or configuration files directory. Now we can call our service, and we’ll get a response. It’s running as a container.
I’ll call my proxy service. You should see that the proxy service didn’t work because there was an incorrect API key.
localhost:8000/?key=test
I’ll try it with the actual API key.
localhost:8000/?key=mysecretconsumerkey | json_pp
Now you should have reached the correct JSON form of data.
This plugin works like middleware and tries to find the correct key for each request.
Kong Go plugins help enhance your API gateway. In my example, I’ve just begun to explore how plugins can allow Kong Gateway to gain expanded capabilities. If you’d like a more in-depth look at some of the things you can build, check out the following resources.
Once you’ve successfully set up Kong Gateway plugins with Go, you may find these other tutorials helpful:
Have questions or want to stay in touch with the Kong community? Join us wherever you hang out:
⭐ Star us on GitHub
🐦 Follow us on Twitter
🌎 Join the Kong Community
🍻 Join our Meetups
❓ ️Ask and answer questions on Kong Nation
💯 Apply to become a Kong Champion
Share Post