In my previous post, I talked about how to use Vault authentication plugin
. Kong has many other authentication plugins you can choose from and in this post, I want to talk about how to use JWT Plugin .
Usage example
Prerequisite :
A Kong Enterprise instance running with database.
You can find plugin documentation here .
Let’s begin:
Create a service 1 2 3 4 curl -X POST http://localhost:8001/services \ -H "Content-Type: application/json" \ -H "Accept: application/json, */*" \ -d '{"name":"jwt-service","url":"https://httpbin.org/anything"}'
Create Route 1 2 3 4 curl -X POST http://localhost:8001/services/jwt-service/routes \ -H "Content-Type: application/json" \ -H "Accept: application/json, */*" \ -d '{"name":"jwt-route","paths":["/jwt"]}'
When we visit our route at curl 'http://localhost:8000/jwt' -i
, we should get HTTP/1.1 200 OK
.
Enable JWT plugin
You can also enable this plugin on a service or globally.
1 2 3 4 curl --request POST \ --url http://localhost:8001/plugins \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data name=jwt
If we visit the route again, we will get HTTP/1.1 401 Unauthorized
Create consumer 1 2 3 4 curl --request POST \ --url http://localhost:8001/consumers \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data username=jwt-user
Create JWT credentials JWT plugin supports 5 algorithms. The main difference will be how keys are shared. If users use RS256, the keys created are asymmetric. On the other hand HS256 uses symmetric keys to sign tokens. I will demonstrate HS256
and RS256
below. For more information about algorithm difference, please check Auth0 doc .
HS256 Use Kong to generate Credential 1 curl -X POST http://localhost:8001/consumers/jwt-user/jwt
By default, Kong will use HS256
algorithm to generate key
and secret
for you.
1 2 3 4 5 6 7 8 9 10 11 12 { "algorithm" : "HS256" , "id" : "a5f72a73-daa6-440d-8257-a40c37d34ec8" , "key" : "Yb7adJK7ZTcSxEd9r7KKl8VOJ3pY44w1" , "consumer" : { "id" : "297e8e1f-1d56-4369-97f9-4765efb853fe" } , "tags" : null , "secret" : "h1Hc2orJlm8aJIefXvIYcdJ3GVfwtcu2" , "created_at" : 1607151650 , "rsa_public_key" : null }
Use your own key
and secret
Let me use pwgen
to generate two passwords
1 2 pwgen -sBv 32 2 Mt4RTRWJk9pfWJpgthP4sHhcqR4hFKzK J3NKsJgt79tcLRfLWwVMJvVnTFk7WskW
Then I will use the first one as key
and second one as secret
. You can create multiple key pairs under the same consumer.
1 2 3 4 5 curl --request POST \ --url http://localhost:8001/consumers/jwt-user/jwt \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data key=Mt4RTRWJk9pfWJpgthP4sHhcqR4hFKzK \ --data secret=J3NKsJgt79tcLRfLWwVMJvVnTFk7WskW
We should get below.
1 2 3 4 5 6 7 8 9 10 11 12 { "algorithm" : "HS256" , "id" : "711c7b54-5551-4803-abc6-cb7ff86b0858" , "key" : "Mt4RTRWJk9pfWJpgthP4sHhcqR4hFKzK" , "consumer" : { "id" : "297e8e1f-1d56-4369-97f9-4765efb853fe" } , "tags" : null , "secret" : "J3NKsJgt79tcLRfLWwVMJvVnTFk7WskW" , "created_at" : 1607152864 , "rsa_public_key" : null }
Now you can use either JWT debugger or JWT CLI to create your token. Please make sure iss: ${key}
is in your payload. Once you’ve got the token, you should be able to access your API again by passing JWT token as Authentication Bearer header.
1 2 curl http://localhost:8000/jwt \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJNdDRSVFJXSms5cGZXSnBndGhQNHNIaGNxUjRoRkt6SyJ9.pCV1wm3VixWkZ_Nh24v4RSQjvYhpb5vJp_LeTRZnF2o"
RS256 Self generated cert
Create private key and extract public key
1 2 3 openssl genrsa -out jwt-private.pem 2048 2>/dev/null &&\ openssl rsa -in jwt-private.pem -outform PEM -pubout -out jwt-public.pem 2>/dev/null &&\ echo -e 'Your private key is \033[1;4mjwt-private.pem\033[0m and public key is \033[1;4mjwt-public.pem\033[0m'
Now you should have jwt-private.pem
and jwt-public.pem
in the folder where you run this command.
Create JWT credential for our consumer jwt-user
1 2 3 4 curl -X POST http://localhost:8001/consumers/jwt-user/jwt \ -F [email protected] \ -F algorithm=RS256 \ -F key=test-key
You can use either JWT debugger or JWT CLI to create your token. Please make sure iss: ${key}
is in your payload, you should be able to access your API again.
1 2 3 curl http://localhost:8000/jwt \ "Accept: application/json, */*" \-H "Authorization:Bearer eyJhbGciOiJSUzI1NiIsInR5cGUiOiJKV1QifQ.eyJpYXQiOiIxNjA3MTc2NDM4IiwiZXhwIjoiMTYwNzE3Njk3OCIsImlzcyI6InRlc3Qta2V5In0.uLrS8T1j7nrEBYRZgZHYALDH2uhg81emRyv5K0bJi3eOwZj45I0ZXU9Lsz7MqryGwbHtP2dwyAQ9u9WXCuU-KSiwpL0L8fjBBjd339BwinQkevwjcr6QuFvch8hD0grYmS9z09jDJ7its0FrO-P0dIEvKhQ23ihADJiFMgTukgNyk3m76nNPkR22vQdJu-OATKVVp9iGpx7tRqZnPeCZAdlGrUJuiACPuqwxdrfithswnAbFg5AjzwB2K9BXiAl76PVYzo15s5KcPCQWJwJ0JY7MgMIEQ0xyifVBZLq__V3B5GgoWy-HEr9Bkd8Dc7ZkImxmJacpLUveWbuqXZ9JFg"
Authentication with Auth0 Authentication with Auth0 is similar to RS256 procedure above except the key
value must set to your Auth0 url and access_token will be generated by Auth0.
Download your Auth0 account certificate 1 curl -o auth0.pem https://{COMPANYNAME}.{REGION-ID}.auth0.com/pem
Some users like myself do not need to use {REGION-ID}
in our base url. You should know your own auth0 base url, if you don’t, you can download Auth0 certificate here .
Please note, you must log in to your account before you can download.
1 openssl x509 -pubkey -noout -in auth0.pem > auth0-pub.pem
Now you should have auth0-pub.pem
in current folder.
Create credential for consumer jwt-user
1 2 3 4 curl -X POST http://localhost:8001/consumers/jwt-user/jwt \ -F [email protected] \ -F algorithm=RS256 \ -F key=https://{COMPANYNAME}.auth0.com/
Get access_token
from Auth0 1 2 3 4 5 6 7 curl --request POST \ --url https://{YOUR_AUTH0_URL}/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data grant_type=client_credentials \ --data client_id=<APP_CLIENT_ID> \ --data client_secret=<APP_CLIENT_SECRET> \ --data audience=https://{YOUR_AUTH0_URL}/api/v2/
You should get your response similar as below.
1 2 3 4 5 6 { "access_token" : "<YOUR_TOKEN>" , "expires_in" : 86400 , "scope" : "<SCOPES>" , "token_type" : "Bearer" }
You should be able to access your api resources by passing the token to Kong.
1 2 3 curl http://localhost:8000/jwt \ "Accept: application/json, */*" \-H "Authorization: Bearer <YOUR_TOKEN>"
Other deployments methods DBless deployment Please save below content to kong.yaml
and load it to your DBless deployment configuration. Below example creates 3 type of JWT credentials for consumer jwt-user
. Please change this section to suit your needs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 _format_version: "2.1" _transform: true services: - name: jwt-service url: https://httpbin.org/anything routes: - name: jwt-route paths: - /jwt consumers: - username: jwt-user jwt_secrets: - algorithm: RS256 key: test-key rsa_public_key: | -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY----- secret: Qrrg5r3pXyTrEmli67PiUiAheT9S4Fem - algorithm: HS256 key: <YOUR_HS256_KEY> secret: <YOUR_HS256_SECRET> - algorithm: RS256 key: https://{COMPANY}.auth0.com/ rsa_public_key: | -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY----- secret: 9VRPEid3GiK5rflY8Cf4wYwJAqyLth7U plugins: - name: jwt route: jwt-route
Kubernetes Ingress Controller
Please change key
and secret
value, put in your public key to use below.
Below example will deploy:
Echo deployment
Echo Service
JWT Plugin
Consumer jwt-user
Ingress rule to use jwt
plugin
3 JWT credentials for HS256, RS256, Auth0.
Please save below to jwt.yaml
and use kubectl apply -f jwt.yaml
to apply it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 apiVersion: apps/v1 kind: Deployment metadata: name: echo-deployment spec: replicas: 1 selector: matchLabels: app: echo-pod template: metadata: labels: app: echo-pod spec: containers: - name: echoheaders image: k8s.gcr.io/echoserver:1.10 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: echo-service spec: selector: app: echo-pod ports: - name: http protocol: TCP port: 80 targetPort: 8080 type: LoadBalancer --- apiVersion: configuration.konghq.com/v1 kind: KongConsumer metadata: name: jwt-user annotations: kubernetes.io/ingress.class: "kong" username: jwt-user credentials: - jwt-key-rs256 - jwt-key-auth0 - jwt-key-hs256 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: proxy-to-echo annotations: konghq.com/plugins: jwt-auth konghq.com/strip-path: "true" spec: ingressClassName: kong rules: - http: paths: - backend: service: name: echo-service port: number: 80 path: /jwt pathType: Prefix --- apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: jwt-auth plugin: jwt --- apiVersion: v1 kind: Secret metadata: name: jwt-key-rs256 type: Opaque stringData: kongCredType: jwt key: test-issuer algorithm: RS256 rsa_public_key: | -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY----- --- apiVersion: v1 kind: Secret metadata: name: jwt-key-auth0 type: Opaque stringData: kongCredType: jwt key: https://{COMPANY}.auth0.com/ algorithm: RS256 rsa_public_key: | -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY----- --- apiVersion: v1 kind: Secret metadata: name: jwt-key-hs256 type: Opaque stringData: kongCredType: jwt algorithm: HS256 key: <YOUR_HS256_KEY> secret: <YOUR_HS256_SECRET>
That’s all I want to share today. Thanks for reading, see you next time.