How to Use KongCustomEntity CRD for JWT Signer Plugin With KIC
In my previous post, I demonstrated how to persist private keys for the JWT Signer plugin when Kong is deployed in DB-less mode by manually writing the Kong declarative config. But what if you’re using the Kong Ingress Controller (KIC) to generate Kong configurations?
There are two options:
- You can host the keys in a separate deployment within the same cluster, as I previously demonstrated.
- Alternatively, you can leverage the new
KongCustomEntity
CRD to mthe keys more seamlessly.
In today’s post, I’ll show you how to generate keys and use the KongCustomEntity
CRD to create the jwt_signer_jwks
entity, which will then be utilized by the JWT Signer plugin.
Let’s get started.
Prerequisites:
- A Kubernetes cluster (I use KinD)
- CLIs
- kubectl
- helm
- yq
- envsubst
- Python
- (optional) nix
Install Kong
Add Helm Repository
1 | helm repo add kong https://charts.konghq.com |
Deploy Kong
We will use the kong/ingress
chart to deploy Kong in DB-less mode with the Kong Ingress Controller.
1 | helm upgrade -i kong kong/ingress \ |
Apply the Kong License
If you have an enterprise license for Kong, you can apply it using the KongLicense
CRD. Assuming your license is stored in a license.json
file, you can use the following command to set it in an environment variable:
1 | export KONG_LICENSE_DATA=$(cat license.json) |
Next, apply the license by running the following command:
1 | envsubst << EOF | kubectl apply -f - |
With Kong set up, let’s proceed to generate the JWKs.
Generate keys
Here is a simple Python script to generate a YAML file (private.yaml) containing both a RS256 and an ES256 private key.
You’ll need the following Python libraries:
- joserfc
- pyyaml
1 | from joserfc.jwk import RSAKey, ECKey |
Create demo app
For this demo, I will create a deployment with go-httpbin image and expose it with an Ingress.
1 | kubectl create deployment httpbin --image=mccutchen/go-httpbin |
Apply the Kong config
Create KongCustomEntity
We’ll store the keys in a KongCustomEntity
. Let’s start by creating a template YAML file (template.yaml), and we’ll use yq to merge the keys we generated in the previous step.
1 | apiVersion: configuration.konghq.com/v1alpha1 |
Run the following command to populate the keys field with the content from private.yaml:
1 | yq eval '.spec.fields.keys = (load("private.yaml") | .keys)' template.yaml | kaf - |
In this example, we are creating a KongCustomEntity
named jwt-signer-demo-keyset in the default namespace. The type is jwt_signer_jwks, and the keyset name is demo.
Create the plugin
Now, let’s create a KongPlugin resource that will use the keyset we just created. In this case, I’m specifying ES256 as the signing algorithm.
1 | apiVersion: configuration.konghq.com/v1 |
Apply the plugin
Finally, apply the plugin to the route we created earlier:
1 | kubectl annotate ingress httpbin-route konghq.com/plugins=jwt-signer-demo |
Test the plugin
Now that the plugin is applied, when you send a request to /test/anything
, you should receive a 401 response. After making a request with a valid token from Keycloak, the upstream httpbin service should return a response that includes a token signed by the JWT Signer plugin.
You can verify the token header kid
to confirm it was signed with the key we generated earlier.
That’s all I want to show you today, see you in the next one.