background

Kong is an openResty-based open source gateway that configures API information to PostgresQL or Cassandra. Through the LuA extension module, the functions of the gateway platform are extended.

This paper records the author’s specific use process of Kong gateway. Including Kong deployment, Kong component use, Kong plug-in use. Other Kong related content can be found on the official website.

Follow the official wechat account zhanzhuslag

Reply keyword “kong” to get the test code

Kong deployment

There are many ways to deploy Kong, and the deployment process adopted here is based on Docker.

Postgresql deployment

Docker deployment Postgresql9.6

  • Create a network
docker network create kong-net
Copy the code
  • Start the database
docker run -d --name kong-database \
--network=kong-net \
-p 5432:5432 \
-e "POSTGRES_USER=mykong" \
-e "POSTGRES_DB=mykong" \
-e "POSTGRES_PASSWORD=mykong" \
postgres:9.6
Copy the code

The database is highly available and can be deployed in hot standby mode. The author has no actual requirements. The following are some data collected that have not been implemented, and will be implemented when there is demand in the future

Flow replication + Dual-system hot backup

  • Configuring postgresql flow of master-slave replication www.cnblogs.com/cxy486/p/51…
  • High availability with PGPool-II middleware www.iteye.com/blog/iwin-2… www.xiaomastack.com/2019/08/16/…
  • Using keepalived + pgpoll – II complete dual machine thermal switch for www.cnblogs.com/songyuejie/…

The deployment of kong

Create kong database The user name, password, and database specified when creating the database need to use the parameter with the prefix KONG_. Description of other environment variables

docker run --rm \
--network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_USER=mykong" \
-e "KONG_PG_PASSWORD=mykong" \
-e "KONG_PG_DATABASE=mykong" \
kong:2.0.1 kong migrations bootstrap
Copy the code

Use the latest kong version 2.0.1

Node 1:17 2.17.23.14

docker run -d --name kong \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_PG_USER=mykong" \ -e "KONG_PG_PASSWORD=mykong" \ -e "KONG_PG_DATABASE=mykong" \ -e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \ -e "KONG_ADMIN_LISTEN_SSL=0.0.0.0:8444" \ -e "KONG_PROXY_ACCESS_LOG=/usr/local/kong/logs/proxy_access.log" \ -e "KONG_ADMIN_ACCESS_LOG=/usr/local/kong/logs/admin_access.log" \ -e "KONG_PROXY_ERROR_LOG=/usr/local/kong/logs/proxy_error.log" \ -e "KONG_ADMIN_ERROR_LOG = / usr/local/kong/logs/admin_error log" \ - e "KONG_TRUSTED_IPS = 0.0.0.0/0, : : / 0" \ # -e "KONG_REAL_IP_HEADER= X-Forwarded-for "\ Ensure transmission of real IP address -p 8000:8000 \ -p 8443:8443 \ -p 8001:8001 \ -p 8444:8444 \ kong:2.0.1Copy the code

Node 2:17 2.17.23.17

Docker run -d --name kong \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=172.17.23.14" \ -e "KONG_PG_USER=mykong" \ -e "KONG_PG_PASSWORD=mykong" \ -e "KONG_PG_DATABASE=mykong" \ -e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \ -e "KONG_ADMIN_LISTEN_SSL = 0.0.0.0:8444 \" e "KONG_PROXY_ACCESS_LOG = / usr/local/kong/logs/proxy_access log" \ - e "KONG_ADMIN_ACCESS_LOG=/usr/local/kong/logs/admin_access.log" \ -e "KONG_PROXY_ERROR_LOG=/usr/local/kong/logs/proxy_error.log" \ -e "KONG_ADMIN_ERROR_LOG = / usr/local/kong/logs/admin_error log" \ - e "KONG_TRUSTED_IPS = 0.0.0.0/0, : : / 0" \ # -e "KONG_REAL_IP_HEADER= X-Forwarded-for "\ Ensure transmission of real IP address -p 8000:8000 \ -p 8443:8443 \ -p 8001:8001 \ -p 8444:8444 \ kong:2.0.1Copy the code

Configure NGINX

After Kong has deployed a cluster, NGINX is used for load balancing. To improve availability and prevent a service in the cluster from going down, NGINX enables health check for the service.

NGINX itself has passive checking, which is configured as follows:

Upstream kong_cluster{server 172.17.23.14:80 max_fails=1 fail_timeout=10s; } server { listen 80; server_name example.com; location / { proxy_pass http://kong_cluster; }}Copy the code

But the active health check that I’m using here.

Active health check requires the installation of third-party plug-ins, here using a third-party module developed by Taobao, the upstream_check module, which needs to recompile NGINX.

I already have nginx1.10 on my operating system itself. So I’m going to recompile it and compile the tripartite module into resources

  • Download active check module download address
# git clone http://github.com/yaoweibin/nginx_upstream_check_module
Copy the code
  • Download NGINX1.16.1 again
#Download NGINX 1.16.1Wget HTTP: / / http://nginx.org/download/nginx-1.16.1.tar.gz## Since I already have Nginx installed on my operating system, I will reinstall it, look at the original installed commands, and compile the extended check module into nginx
#View the original installed commands
nginx -V 
#On ubuntu, install the Nginx dependency package
#Zlib depend on the package
sudo apt-get install zlib1g-dev
#Openssl depend on the package
sudo apt-get install openssl libssl-dev
#Install the PCRE dependency package
sudo apt-get install libpcre3 libpcre3-dev
#Install libxml2 / libxslt
sudo apt-get install libxslt1-dev
sudo apt-get install libxml2-dev
#Install the GD dependency package
sudo apt-get install libgd-dev
#Install the GeoIP dependency package
sudo apt-get install libgeoip-dev
#Reinstall the downloaded nginx1.16.1Tar ZXVF nginx-1.16.1.tar.gz CD nginx-1.16.1#Download tripartite modules and patch them according to the nGINx versionPatch - p1 < / root/install/nginx_upstream_check_module check_1. 16.1 +. Patch#After the patch is complete, install nginx
./configure \
--with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' \
--with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' \
--prefix=/usr/share/nginx \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--lock-path=/var/lock/nginx.lock \
--pid-path=/run/nginx.pid \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--with-debug \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_addition_module \
--with-http_dav_module \
--with-http_geoip_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_image_filter_module \
--with-http_v2_module \
--with-http_sub_module \
--with-http_xslt_module \
--with-stream \
--with-stream_ssl_module \
--with-mail \
--with-mail_ssl_module \
--with-threads \
--with-pcre \
--add-module=/root/install/nginx_upstream_check_module
#Compile the installation
make
#If it is already installed, just make
#Then copy the generated nginx to the original directory
cp objs/nginx /usr/sbin/nginx
Copy the code

Deployed nginx

#Configure HTTPSUpstream Kong_cluster {upstream 172.17.23.17:8000; Server 172.17.23.14:8000; Check TCP, as long as you ensure that the Kong service is not broken. The actual service health check Kong plug-ins check other configuration reference # http://tengine.taobao.org/document_cn/http_upstream_check_cn.html check interval = 3000 rise=2 fall=3 timeout=1000 type=tcp; } server { listen 443 ssl; server_name example.com; Ssl_certificate cert/214533299050973.pem; ssl_certificate cert/214533299050973.pem Ssl_certificate_key cert/214533299050973.key; Ssl_session_timeout 5M; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:! NULL:! aNULL:! MD5:! ADH:! RC4; Ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; For security reasons, you need to disable gzip #. However, in some scenarios, you do not need to disable # gzip off. gzip on; # set the minimum number of bytes allowed to compress pages gzip_min_length 1000; gzip_buffers 4 16k; Gzip_http_version 1.1; # 1~9, default is 1, the higher the value, the higher the compression rate, the more CPU usage, the longer the time; gzip_vary on; Gzip_disable "MSIE [1-6]\."; gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/javascript "application/javascript; charset=utf-8" application/xml application/xml+rss application/json "application/json; charset=utf-8" font/ttf font/otf image/svg+xml; [client_max_body_size] [client_max_body_size] keepalive_timeout 15; Server_tokens off; Client_header_buffer_size 32K; large_client_header_buffers 4 32k; ## Individual nginx logs access_log /var/log/nginx/kong_access.log; error_log /var/log/nginx/kong_error.log; location ^~ /robots.txt { expires 30d; # add_header Content-Type text/plain; return 200 "User-Agent: *\nDisallow: /"; } location ~ /(\w+) {# websocket supports proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; Proxy_pass http://kong_cluster; expires -1; } # return 404 location = / {return 404; } } server { listen 80; server_name example.com; # Change your domain name information   #Tell the browser to use HTTPS only for access within the validity period
   add_header Strict-Transport-Security max-age=15768000;
   #Permanently redirect to HTTPS site
   return 301 https://$server_name$request_uri;
}
Copy the code

Restart the NGINX

systemctl restart nginx

Configure the API to Kong

Kong Common components

  • Service
Service is a defined Service. After forwarding through Kong, it matches the actual Service address according to the requested protocol, host, method, and path. A Service can be associated with a Route. A Service can have many routes, which will be forwarded to the Service and processed by Plugin in the process. Add or subtract corresponding headers or other information. A Service can be an actual address, or it can be associated with an Upstream component provided by Kong that forwards requests to the actual Service.Copy the code
  • The Route:
Each Route is associated with a Service, and a Service can be associated with multiple routes. When a request from the client is matched, Each request will be proxy to its configured Service Route as the entrance of the client. Through the loose coupling of Route and Service, the request can be forwarded to different services through the configuration of rules such as hosts path. For example, if we specify that login requests from api.example.com and api.Service.com can be proxied to port 123.11.11.11:8000, we can route through hosts and PATH. First, create a Service s1, The corresponding host and port and protocol are http://123.11.11.11:8000. Then create a Route with the associated Service as s1. Its hosts are [api.service.com, api.example.com] and path is login. Finally, forward requests for the domain names api.example.com and api.service.com to our Kong cluster. So, when we request api.example.com/login and api.service.com/login, they are matched by Route and forwarded to Service, which will eventually request our own Service.Copy the code
  • Upstream
This means that your own API/service is behind Kong, to which client requests are forwarded. When we deploy a cluster and a single address is not sufficient, we can use Kong's upstream to set the host in the service. We specify the hostname for our upstream. We specify the name when we create the upstream, then specify solts. Upstream can perform health checks, etc. This is not enabled (not explored yet) and then we can create the target type and bind it to upstream, which will basically be used when we deploy the clusterCopy the code
  • Target
The target is the endpoint that you load balance with upstream. When deploying the cluster, each node should be a target and the load should be weighted. You can also use upstream to perform a health check on the target. When using upstream, the entire Route is Route >> Service >> upstream >> TargetCopy the code
  • Consumer
Consumer can represent a service, a user, or a Consumer. It can be defined according to our own needs. A Consumer can be corresponding to a user in the actual application. It can also be used as a request Consumer for a Service, which you can learn more about when using the PluginCopy the code
  • Plugin
A plug-in that performs actions within Kong before or after the request is brokered to the upstream API. For example, a pre-request Authentication or request-limiting Plugin can be bound to a Service, associated with Route and Consumer, or global. Common traffic limiting plug-ins, IP limiting plug-ins and so on.Copy the code

Kong use

Four components are used: Service, Route, Upstream, and Target

Target configures the service node but associates it with Upstream.

Upstream can perform load balancing and health checks on the Target and associate the Service with name. When the Service matches a request, it forwards it to the corresponding Upstream.

Service sets up different services according to the Service. Service and Route bind to get the actual request, match the request with protocol,host,port, and PATH, and forward the matched request to Upstream.

Route is the actual entry point in Kong. Mainly according to protocols, hosts, methods and Paths, requests are set, matched, and forwarded to the corresponding service

We create the Service, Route, Upstream, and Target in this order

Configure the Service

The Service has other parameters that can be customized. Website information

  • Add a command
curl -i -X POST \
--url http://localhost:8001/services/ \
--data 'name=example-service' \
--data 'protocol=http' \
--data 'host=api.example.service'
    
#The host attribute is used when creating upstreams
Copy the code
  • Add the results
{
    "host": "api.example.service"."created_at": 1582626079."connect_timeout": 60000."id": "71b28160-15fc-4215-a68f-d0b607e9cb9f"."protocol": "http"."name": "example-service"."read_timeout": 60000."port": 80."path": null."updated_at": 1582626079."retries": 5."write_timeout": 60000."tags": null."client_certificate": null
}
Copy the code
  • Modify command
curl -i -X PATCH \
--url http://localhost:8001/services/71b28160-15fc-4215-a68f-d0b607e9cb9f/ \
--data 'name=test-kong' \
--data 'protocol=http'  \
--data 'host=test.kong.service'
Copy the code
  • Modify the results
{
    "host": "test.kong.service"."created_at": 1582626079."connect_timeout": 60000."id": "71b28160-15fc-4215-a68f-d0b607e9cb9f"."protocol": "http"."name": "test-kong"."read_timeout": 60000."port": 80."path": null."updated_at": 1582626120."retries": 5."write_timeout": 60000."tags": null."client_certificate": null
}
Copy the code

Configure the Route

Route also has other parameters that can be customized as required. Website information

  • Add a command

In practice, change hosts to the actual domain name

curl -i -X POST \ --url http://localhost:8001/routes/ \ --data 'protocols[]=http' \ --data 'protocols[]=https' \ --data 'methods[]=GET' \ --data 'methods[]=POST' \ --data 'methods[]=DELETE' \ --data 'methods[]=PUT' \ --data 'hosts[]=api.example.com' \ --data 'paths[]=/v1/test_kong' \ --data 'strip_path=false' \ # --data 'service.id= 71b28160-15FC-4215-a68f-d0b607e9cb9f '--data 'service.id= 71b28160-15FC-4215-a68f-d0b607e9cb9fCopy the code
  • Add the results
{
    "id": "c156de0e-4b08-43a3-bc2d-3f0cf5d5d00a"."path_handling": "v0"."paths": ["\/v1\/test_kong"]."destinations": null."headers": null."protocols": ["http"."https"]."methods": ["GET"."POST"."DELETE"."PUT"]."snis": null."service": {
        "id": "71b28160-15fc-4215-a68f-d0b607e9cb9f"
    },
    "name": null."strip_path": false."preserve_host": false."regex_priority": 0."updated_at": 1582627872."sources": null."hosts": ["api.example.com"]."https_redirect_status_code": 426."tags": null."created_at": 1582627872
}
Copy the code

Configuration of Upstream

  • Add a command

Only active check is configured here

curl -i -X POST \
--url http://localhost:8001/upstreams/ \
--data 'name=test.kong.service'  \
--data 'algorithm=round-robin' \
--data 'healthchecks.active.type=http' \
--data 'healthchecks.active.http_path=/' \
--data 'healthchecks.active.timeout=2' \
--data 'healthchecks.active.healthy.successes=3' \
--data 'healthchecks.active.healthy.interval=10' \
--data 'healthchecks.active.unhealthy.interval=10' \
--data 'healthchecks.active.unhealthy.http_failures=3'
Copy the code
  • Add the results
{
    "created_at": 1582626649."hash_on": "none"."id": "1d3638c6-d5a0-4bb5-907b-015c8daf7861"."algorithm": "round-robin"."name": "test.kong.service"."tags": null."hash_fallback_header": null."hash_fallback": "none"."hash_on_cookie": null."host_header": null."hash_on_cookie_path": "/ /"."healthchecks": {
        "threshold": 0."active": {
            "unhealthy": {
                "http_statuses": [429.404.500.501.502.503.504.505]."tcp_failures": 0."timeouts": 0."http_failures": 3."interval": 10
            },
            "type": "http"."http_path": "/ /"."timeout": 2."healthy": {
                "successes": 3."interval": 10."http_statuses": [200.302]},"https_sni": null."https_verify_certificate": true."concurrency": 10
        },
        "passive": {
            "unhealthy": {
                "http_failures": 0."http_statuses": [429.500.503]."tcp_failures": 0."timeouts": 0
            },
            "healthy": {
                "http_statuses": [200.201.202.203.204.205.206.207.208.226.300.301.302.303.304.305.306.307.308]."successes": 0
            },
            "type": "http"}},"hash_on_header": null."slots": 10000
}
Copy the code

Configure the target

  • Add a command
curl -i -X POST \ --url http://localhost:8001/upstreams/1d3638c6-d5a0-4bb5-907b-015c8daf7861/targets \ --data 'target=172.17.23.14:38001' curl - i-x POST \ --url http://localhost:8001/upstreams/1d3638c6-d5a0-4bb5-907b-015c8daf7861/targets \ - data 'target = 172.17.23.14:38002'Copy the code
  • Add the results
{
    "created_at": 1582627463.954."upstream": {
        "id": "1d3638c6-d5a0-4bb5-907b-015c8daf7861"
    },
    "id": "66c83e7d-f006-43da-990b-d493a966fc66"."target": "172.17.23.14:38001"."weight": 100
}

{
    "created_at": 1582627517.872."upstream": {
        "id": "1d3638c6-d5a0-4bb5-907b-015c8daf7861"
    },
    "id": "d9940f44-30ad-437a-aaab-836dfaf27b93"."target": "172.17.23.14:38002"."weight": 100
}
Copy the code
Check whether configuring Kong is feasible
  • Check configured requests
curl -X GET https://example.com/v1/test_kong

{"code": 200, "message": "test kong get success"}

curl -X POST https://example.com/v1/test_kong

{"code": 200, "message": "test post get success"}

curl -X DELETE https://example.com/v1/test_kong

{"code": 200, "message": "test kong delete success"}

curl -X PUT https://example.com/v1/test_kong

{"code": 200, "message": "test kong put success"}

Copy the code
  • Check configuration health check

Things that see service configuration are being checked all the time

[I 200225 19:03:10 web:2246] 200 GET/(172.17.23.14) 0.88ms [I 200225 19:03:20 web:2246] 200 GET/(172.17.23.17) 0.88ms [I 200225 19:03:20 web:2246] Ms [I 200225 19:03:20 web:2246] 200 GET/(172.17.23.14) 0.67ms [I 200225 19:03:30 web:2246] 200 GET/(172.17.23.14) 0.67ms [I 200225 19:03:30 web:2246] 200 GET / (172.17.23.14) 0.88ms [I 200225 19:03:30 web:2246] 200 GET/(172.17.23.17) 1.02ms [I 200225 19:03:40 web:2246] 200 GET / (172.17.23.14) 0.88ms [I 200225 19:03:40 web:2246] 200 GET/(172.17.23.17) 1.15msCopy the code

Use the Kong plugin

The scope of the plug-in can be Route, Service, Consumer, or Global from small to large.

You can use some plug-ins as required, such as traffic limiting, IP whitelist and IP blacklist

Here are the plug-ins available for the official Kong open source version

Rate Limiting plug-in

Limit the number of times you can access a stream within a specified period of time, within seconds, minutes, hours, days, etc. Plug-ins can be set at Service, Route, or global. If Consumer is enabled, the limit time is calculated based on Consumer, otherwise based on the client IP address

Add a plug-in for a given service

curl -X POST http://localhost:8001/services/71b28160-15fc-4215-a68f-d0b607e9cb9f/plugins \ --data "name=rate-limiting" \  --data "config.second=2" \ --data "config.hour=10000" \ --data "config.policy=local" \ --data "config.limit_by=ip"Copy the code

Add the results

{
    "created_at": 1582637075."config": {
        "minute": null."policy": "local"."month": null."redis_timeout": 2000."limit_by": "consumer"."hide_client_headers": false."second": 5."day": null."redis_password": null."year": null."redis_database": 0."hour": 10000."redis_port": 6379."redis_host": null."fault_tolerant": true
    },
    "id": "9f8d08c9-4bdf-4912-b4dd-f96b32e38019"."service": {
        "id": "71b28160-15fc-4215-a68f-d0b607e9cb9f"
    },
    "enabled": true."protocols": ["grpc"."grpcs"."http"."https"]."name": "rate-limiting"."consumer": null."route": null."tags": null
}
Copy the code

The test results

def test_rate_limiting(a):
    url = "https://example.com/v1/test_kong"
    def _request(idx):
        print("request {} start by : {}".format(idx, datetime.datetime.now()))
        print("request {} result >>>".format(idx))
        resp = requests.get(url)
        print("request {} status_code {} ".format(idx, resp.status_code))
        print("request {} json {} ".format(idx, resp.json()))
        print("request {} result <<<".format(idx))
        print("request {} end by : {}".format(idx, datetime.datetime.now()))

    for i in range(0.8):
        t = threading.Thread(target=_request, args=(i, ))
        t.start()
Copy the code

The execution result

request 3 status_code 200 request 3 json {'message': 'test kong get success', 'code': 200} request 3 result <<< request 3 end by : Request 6 Status_code 429 Request 6 JSON {'message': 'API rate limit exceeded'} request 5 status_code 429Copy the code
IP Restriction

IP Restriction is implemented by using the NGINX variable binary_remote_ADDR and setting the blacklist and whitelist to block and protect some requests. If an IP address is in the blacklist and whitelist at the same time, the IP address can be accessed.

The IP Restriction plugin applies to services, routes, consumers, and globally. We now apply it to the Service

curl -X POST http://localhost:8001/services/71b28160-15fc-4215-a68f-d0b607e9cb9f/plugins \
--data "name=ip-restriction" \
--data "config.whitelist=172.17.23.14" \
--data "config.whitelist=172.17.23.17"
Copy the code

Add the results

{
    "created_at": 1582980903."config": {
        "whitelist": ["172.17.23.14"."172.17.23.17"]."blacklist": null
    },
    "id": "c0364fe4-2d43-451e-9330-b45964cf1483"."service": {
        "id": "71b28160-15fc-4215-a68f-d0b607e9cb9f"
    },
    "enabled": true."protocols": ["grpc"."grpcs"."http"."https"]."name": "ip-restriction"."consumer": null."route": null."tags": null
}
Copy the code

The test results

{"message":"Your IP address is not allowed"}
Copy the code
Zipkin

Zipkin is a distributed tracking system, and the purpose of our consumer plug-in is to monitor our API time consumption, specifically to track performance consumption based on these results.

So we first deployed the Zipkin service and installed it directly using Docker.

For more information about Zipkin, check out the zipkin website

Deploy Zipkin
docker run -d -p 9411:9411 openzipkin/zipkin
Copy the code
Add the plug-in

The Zipkin plugin works with services, routes, consumers, and globally. We now apply it to the Service

curl -X POST http://localhost:8001/services/71b28160-15fc-4215-a68f-d0b607e9cb9f/plugins \ --data "name=zipkin" \ --data Config. Http_endpoint = "http://172.17.23.14:9411/api/v2/spans" \ - data "config. Sample_ratio = 1 \" # all sampling data "config.include_credential=true"Copy the code

Add the results

{
    "created_at": 1582812902."config": {
        "sample_ratio": 1."http_endpoint": "HTTP: \ \ / 172.17.23.14: \ 9411 \ \ / API/v2 / spans." "."include_credential": true."default_service_name": null
    },
    "id": "c58654d8-2fd5-43b6-854f-0fd65a353f7e"."service": {
        "id": "71b28160-15fc-4215-a68f-d0b607e9cb9f"
    },
    "enabled": true."protocols": ["grpc"."grpcs"."http"."https"]."name": "zipkin"."consumer": null."route": null."tags": null
}
Copy the code

Http_endpoint: service address of zipkin

Sample_ratio: when the collection frequency is set to 1, all collection will be performed; when the collection frequency is set to 0, no collection will be performed; when the collection frequency is set to 0-1, random collection will be performed by the algorithm according to the set parameters

Testing plug-ins use effect: access address configuration, set up in front of the sampling frequency is 1, said all collection, visit after landing zipkin address http://172.17.23.14:9411/zipkin

HMAC Authentication

For HMAC signature authentication, only after the Kong gateway signature authentication succeeds, can the request be sent back. The actual application scenarios are as follows:

  1. Create a Consumer
  2. Create username and secret for Consumer HMAC, and the client will use them to sign
  3. Enable the HMAC plug-in in Service or Route
  4. When the client requests, according to the previously returned username and secret signatures, Kong gateway matches and performs signature verification
  • Create consumers

Create a command

curl -i http://localhost:8001/consumers/ -d "username=test_hmac&custom_id=test_hmac_id"
Copy the code

Create the results

{
    "custom_id": "test_hmac_id"."created_at": 1583071044."id": "c9a4ad0e-174f-4a7f-81b0-ce9e3261c177"."tags": null."username": "test_hmac"
}
Copy the code
  • Create consumer HMAC plug-in information
curl -X POST http://localhost:8001/consumers/test_hmac/hmac-auth \
--data "username=test_hmac" \
--data "secret=test_hmac_secret123"
Copy the code

Username: indicates the username used in HMAC signature verification. Secret: indicates the secret key used for HMAC signature verification.

Create the results

{
    "created_at": 1583071212."consumer": {
        "id": "c9a4ad0e-174f-4a7f-81b0-ce9e3261c177"
    },
    "id": "834a8f69-c63d-4183-8a50-b52ab6a6187e"."tags": null."secret": "test_hmac_secret123"."username": "test_hmac"
}
Copy the code
  • Enable the HMAC plug-in

Remove the IP Restriction plugin from the previous Service. Otherwise my local and server tests will say it can’t handle

Delete the ID generated by creating the plug-in.

curl -i -X DELETE http://localhost:8001/plugins/c0364fe4-2d43-451e-9330-b45964cf1483
Copy the code

Add the plugin to the specified Route or Service. This time, add the plugin to the Route and test again

Add a command

curl -i -X POST http://localhost:8001/routes/c156de0e-4b08-43a3-bc2d-3f0cf5d5d00a/plugins \
      -d "name=hmac-auth" \
      -d "config.enforce_headers=date" \
      -d "config.algorithms=hmac-sha1" \
      -d "config.algorithms=hmac-sha256" \
      -d "config.validate_request_body=true"
Copy the code
Enforce_headers: mandatory parameters in the Header, which are then used to enforce signature validation Algorithms: list of HMAC digest algorithms that the user wants to support. The allowed values are HMAC-sha1, HMAC-sha256, HMAC-SHA384, and hMAC-sha512. Select one of these values to validATE_request_body: Validates the request bodytrueThen, if there is a Digest in the client request header, Kong uses the HMAC algorithm to validate the request body.Copy the code

Add the results

{
    "created_at": 1583072768."config": {
        "clock_skew": 300."validate_request_body": true."enforce_headers": ["date"]."algorithms": ["hmac-sha1"."hmac-sha256"]."anonymous": null."hide_credentials": false
    },
    "id": "39188d02-5425-4f76-8795-5e028f793476"."service": null."enabled": true."protocols": ["grpc"."grpcs"."http"."https"]."name": "hmac-auth"."consumer": null."route": {
        "id": "c156de0e-4b08-43a3-bc2d-3f0cf5d5d00a"
    },
    "tags": null
}
Copy the code
  • The client requests the test
The Authorization or proxy-authorization header consists of the CREDENTIALS signature algorithm using the HMAC plug-in. The fixed value is the HMAC params parameter","Segmentation. Algorithm: headers: key included in signature calculation Signature: generated signature and rules 2. Digest: validATE_request_body is enabled and needs to be generated 3. Date: GMT formatCopy the code

Python test functions

def test_hmac_authentication(a):
    Create the user name and key for the HMAC plug-in
    hmac_username = "test_hmac"
    hmac_secret = "test_hmac_secret123"

    url = "https://example.com/v1/test_kong"

    # request header
    Note that the request header must be in GMT format
    request_headers = {
        "Authorization": ""."Digest": ""."Date": datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")}# request body
    request_body = {
        "data": {"test": "hmac"}}# generate Digest
    # body="A small body"
    # digest=SHA-256(body)
    # base64_digest=base64(digest)
    # Digest: SHA-256=
      
    base64_digest = base64.b64encode(hashlib.sha256(json.dumps(request_body).encode('utf-8')).digest()).decode('utf-8')
    request_headers['Digest'] = "SHA-256={}".format(base64_digest)

    # generate signature
    # signing_string = "date: Thu, 22 Jun 2017 17:15:21 GMT\nGET /requests HTTP/1.1"
    # digest = HMAC - SHA256( < signing_string >, "secret")
    # base64_digest = base64( < digest >)
    # signature string construction
    # if the argument is not request-line, use lower case, followed by ":" and a space.
    GET /requests HTTP/1.1
    Use the newline character "\n" in the middle to concatenate all the parameters.

    # Concatenate strings according to the above rules
    sign_string = "date: {}\ndigest: {}".format(request_headers['Date'], request_headers['Digest'])

    # Start signing
    sign_digest = hmac.new(hmac_secret.encode("utf-8"), sign_string.encode('utf-8'), digestmod='sha256').digest()
    sign_base64_digest = base64.b64encode(sign_digest).decode('utf-8')

    https://docs.konghq.com/hub/kong-inc/hmac-auth/#signature-authentication-scheme # building Authorization parameters specific information
    authorization = 'hmac username="{}", algorithm="hmac-sha256", headers="date digest", signature="{}"'.format(
        hmac_username, sign_base64_digest)

    request_headers['Authorization'] = authorization
    resp = requests.post(url, headers=request_headers, json=request_body)
    print(request_headers)
    print(resp.status_code)
    print(resp.json())
Copy the code

The test results

# failed 401 {'message': 'HMAC signature cannot be verified'} # successful 200 {'code': 200, 'message': 'test kong post success'}Copy the code