Skip to content

Instantly share code, notes, and snippets.

@akraxx
Last active August 31, 2021 14:24
Show Gist options
  • Save akraxx/51e3afb8eeac9d0ef9d79c117700e000 to your computer and use it in GitHub Desktop.
Save akraxx/51e3afb8eeac9d0ef9d79c117700e000 to your computer and use it in GitHub Desktop.

Mockbin

docker run -d --name mockbin_redis redis
docker run -d --link mockbin_redis:redis --name mockbin mashape/mockbin

Cassandra database

docker run -d --name kong-database \
              -p 9042:9042 \
              cassandra:2.2

Kong core

docker run -d --name kong \
              --link kong-database:kong-database \
              --link mockbin:mockbin \
              -e "KONG_DATABASE=cassandra" \
              -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
              -e "KONG_PG_HOST=kong-database" \
              -p 8000:8000 \
              -p 8443:8443 \
              -p 8001:8001 \
              -p 7946:7946 \
              -p 7946:7946/udp \
              kong

Create an api

curl -s -X POST \
  --url http://localhost:8001/apis/ \
  --data 'name=mockbin' \
  --data 'upstream_url=http://mockbin:8080/' \
  --data 'request_path=/mockbin' \
  --data 'strip_request_path=true' | jq .

Call api

curl -s -X GET --url http://localhost:8000/mockbin/request | jq .

First plugin : rate limiting

curl -s -X POST http://localhost:8001/apis/mockbin/plugins \
    --data "name=rate-limiting" \
    --data "config.minute=5" | jq .

Secure

curl -s -X POST http://localhost:8001/apis/mockbin/plugins \
    --data "name=key-auth" | jq .

Call api : 401

curl -s -X GET --url http://localhost:8000/mockbin/request | jq .

Create a consumer

curl -s -X POST http://localhost:8001/consumers/ \
    --data "username=mmarie" | jq .

Create an api key for the consumer

curl -s -X POST http://localhost:8001/consumers/mmarie/key-auth -d '' | jq .

Call the API with my new api key

curl -s http://localhost:8000/mockbin/request?apikey=<generated_key> | jq .

curl -s http://localhost:8000/mockbin/request \
    -H 'apikey: <generated_key>' | jq .

x-consumer-id and x-consumer-username have been filled by kong.

Is it enough to secure an api? No. We can't create api-key like that, because the user didn't authenticate himself anywhere before calling it... And what happend if the user leaves the company? You will have to check each day the entire user db (most of the case : a LDAP), to know if all the users are still there. Avoid scheduled tasks !

JWT Introduction

JWT is stateless! It can embed some data, like user profile.

Kong supports JWT, it can validate the signature and validate fields like expiration date.

  1. Delete the API key plugin
curl -s -X GET http://localhost:8001/apis/mockbin/plugins | jq .
curl -s -X DELETE http://localhost:8001/apis/mockbin/plugins/{api-auth id}
  1. Add a JWT plugin to api
curl -s -X POST http://localhost:8001/apis/mockbin/plugins \
    --data "config.key_claim_name=aud" \
    --data "name=jwt" | jq .
  1. Add a JWT plugin to consumer
RSA_PUB_KEY="-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvgKPUi8QOX7FD0328ELk7WiKc
DTwOF3NGn2lXJuUmj8p3o+yOQ2dDBnhWO+IUctTaq9YzI6QVLyRqSxBDJouRjhsz
7B9BSfnkN8fRdEqKAtgQcdjrVjNkyrGescKMDeokatwa7ZrEmQ3ubRdzMtglQ2y7
q8bGGHkaE9DJtj2xdQIDAQAB
-----END PUBLIC KEY-----"

curl -s -X POST http://localhost:8001/consumers/mmarie/jwt \
  --data "key=mmarie" \
  --data "algorithm=RS256" \
  --data-urlencode "rsa_public_key=$RSA_PUB_KEY" | jq .
  1. Craft a new token

https://jwt.io/

Algorithm : RS256

Payload

{
  "sub": "1234567890",
  "name": "Max Marie",
  "aud": "mmare"
}

Public key

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvgKPUi8QOX7FD0328ELk7WiKc
DTwOF3NGn2lXJuUmj8p3o+yOQ2dDBnhWO+IUctTaq9YzI6QVLyRqSxBDJouRjhsz
7B9BSfnkN8fRdEqKAtgQcdjrVjNkyrGescKMDeokatwa7ZrEmQ3ubRdzMtglQ2y7
q8bGGHkaE9DJtj2xdQIDAQAB
-----END PUBLIC KEY-----

Private key

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCvgKPUi8QOX7FD0328ELk7WiKcDTwOF3NGn2lXJuUmj8p3o+yO
Q2dDBnhWO+IUctTaq9YzI6QVLyRqSxBDJouRjhsz7B9BSfnkN8fRdEqKAtgQcdjr
VjNkyrGescKMDeokatwa7ZrEmQ3ubRdzMtglQ2y7q8bGGHkaE9DJtj2xdQIDAQAB
AoGAUcyxj5V9Uf3ED4r5pbhdvY4rZ3S7sw23Cwmt/ZMBZ1HJ2q2qyjwcWx8e44KR
w1oqX6mL8tX/2mfYnzpRYBsNHYrrG2U+RPWYghu5MWAkiukqawENSuE0hgYs2Bs2
Y8urbTZvpOeG9d/LcXh4VGE/uHdXc/95xsG3K0kwe7d+u5kCQQDZEptSTmNUYZen
6l4IQaL+zB68imZtTLoO9bEC6uaycz8Ko5p/68dkkY9hwqdYhIuaKV/OpjwOqeRL
BPbfTS7/AkEAzvmgFyDinsY2KqF8Qs1KEAUjNa5t/hNxkgYhNSpsTN8hCBS86Ujm
L1zMbmTdEg7dABsNfthPvucFGwwdD2fTiwJBAJ3OpRQk4JlLiZENFOczsGdDxWST
yPrUuL5/ZvwUATriBYaagYtVwVMfbvlHJZl4YnTkdz4oI6kVYV4YcdDMr8kCQQCb
WvO3aI+x7cWqqhvDaKQ28iRDnvIgzCdrG/7BEV7JNJJupmJGGNnuoxEvq7XkYBOy
iJvQojz5Zh6G9si5T42RAkAB22HzNc6RcstvTy8JIZ4jO17AJnrguEKCGdMdbziO
HGX4UZ2esZvLAYf9g2yHfGf5+5ITt8vAqvP3ghmkgw26
-----END RSA PRIVATE KEY-----
  1. Call the API
curl -s http://localhost:8000/mockbin/request \
    -H 'Authorization: Bearer {TOKEN}' | jq .

The good solution is : Kong + an SSO

  • Kong will be there to authorize the users to access any api
  • The SSO only authenticate user with his credentials

Which SSO?

Keycloak

Why?

  • Opensource
  • Owned by redhat
  • Out of the box
  • Scalable
  • Openid connect protocol, JWT implementation
docker run -d -e KEYCLOAK_USER=admin \
      -e KEYCLOAK_PASSWORD=admin \
      -p 8080:8080 \
      --name keycloak \
      jboss/keycloak

Create a new realm and a new client.

Create a consumer

curl -s -X POST http://localhost:8001/consumers/ \
    --data "username=webapp" | jq .
curl -s -X POST http://localhost:8001/consumers/webapp/jwt \
  --data "key=webapp" \
  --data "algorithm=RS256" \
  --data-urlencode "rsa_public_key=$RSA_PUB_KEY" | jq .

Add some checks on JWT token

curl -X PATCH http://kong:8001/apis/{api}/plugins/{jwt plugin id} \
    --data "config.claims_to_verify=exp,nbf"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment