APISIX
Introduction
APISIX is an Apache product for managing endpoint exposition with several useful features for security and traceability.
It supports few plugins (built-in) sorted in 8 categories :
- General: generics features like Redirection, Real-IP, Server-Info, or Gzip compression
- Transformation: requests and responses modification, like rewriting response, transcoding to GRPC, or Proxy Rewriting
- Authentication: features to support extra layer of authentication and authorization, like OIDC, Hmac, Key Auth etc
- Security: features for easy setup of CORS, CSRF, and other contextual restrictions (IP, User Agents, Consumers etc)
- Traffic: for all features to manage the way to handle the traffic, like Limiting, Caching, Validation, Circuit breaking...
- Observability: all features based on handeling Traces, Metrics and Logging features.
- Serverless: to hide the functions/lambda behind ApiSix
- Others: various proxy utility like Mqtt or Kafka proxy
How does it work
APISIX can work in many place, like Docker, Kubernetes or Virtual Machines.
As many load-balancer/Reverse proxy tools, the concepts are similar as Nginx.
The workflow to implement is :
- Create Routes
- Configure Load Balancing (not needed for Kubernetes, it's built-in)
- Add "plugins" to enable the features needed
Test APISIX Locally
Install APISIX quickstart mode
You need docker
and curl
to test it by yourself
curl -sL https://run.api7.ai/apisix/quickstart | sh
Destroying existing apisix-quickstart container, if any.
Installing APISIX with the quickstart options.
Creating bridge network apisix-quickstart-net.
162287ac4556b97670bd11ccbf5e6db322b0dabae21daeaaaea60df60777e7f2
✔ network apisix-quickstart-net created
Starting the container etcd-quickstart.
2dee470e9ff807aa672d46002c515dfbd4838003d3237f63bf863d1bd866ccab
✔ etcd is listening on etcd-quickstart:2379
Starting the container apisix-quickstart.
f3b03c2a3a002d87722631367b3be5532e6765d9873b26874b144556be9d4106
⚠ WARNING: The Admin API key is currently disabled. You should turn on admin_key_required and set a strong Admin API key in production for security.
✔ APISIX is ready!
If everything is good, you will have ✔ APISIX is ready!
, but to validate it is working:
curl "http://127.0.0.1:9080" --head | grep Server
Create a Route
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "getting-started-ip",
"uri": "/ip",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
HTTP/1.1 201 Created
Date: Fri, 08 Mar 2024 14:54:03 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.8.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Access-Control-Max-Age: 3600
X-API-VERSION: v3
{
"key": "/apisix/routes/getting-started-ip",
"value": {
"status": 1,
"upstream": {
"pass_host": "pass",
"nodes": { "httpbin.org:80": 1 },
"type": "roundrobin",
"hash_on": "vars",
"scheme": "http"
},
"priority": 0,
"uri": "/ip",
"id": "getting-started-ip",
"create_time": 1709909643,
"update_time": 1709909643
}
}
The route should be created, and you can test it :
curl "http://127.0.0.1:9080/ip" | jq
{
"origin": "192.168.65.1, 95.178.91.245"
}
Enable Authorizations
To enable authorization we first need to create a Consumer and enable the key-auth
plugin
curl -i "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT -d '
{
"username": "etienne",
"plugins": {
"key-auth": {
"key": "secret-key"
}
}
}'
HTTP/1.1 201 Created
Date: Fri, 08 Mar 2024 14:59:57 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.8.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Access-Control-Max-Age: 3600
X-API-VERSION: v3
{
"key": "/apisix/consumers/etienne",
"value": {
"username": "etienne",
"plugins": { "key-auth": { "key": "secret-key" } },
"create_time": 1709909997,
"update_time": 1709909997
}
}
The Api of ApiSix should answer a 201 Created
.
Now we can link the key-auth
, to the route :
curl -i "http://127.0.0.1:9180/apisix/admin/routes/getting-started-ip" -X PATCH -d '
{
"plugins": {
"key-auth": {}
}
}'
The request to the same endpoint should now be unaccessible without the API Key:
curl -i "http://127.0.0.1:9080/ip"
HTTP/1.1 401 Unauthorized
Date: Mon, 11 Mar 2024 09:02:06 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.8.0
{"message":"Missing API key found in request"}
But remain accessible with the API Key:
curl -i "http://127.0.0.1:9080/ip" -H 'apikey: secret-key'
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 46
Connection: keep-alive
Date: Mon, 11 Mar 2024 09:03:09 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.8.0
{
"origin": "192.168.65.1, 95.178.91.245"
}
All plugins for Authentification and Authorization work the same way, so you can try the others with the same methodology
Enable Request filtering
To enable the filtering based on request, we need a route
in ApiSix, then we need to activate the plugin with this command:
curl -i "http://127.0.0.1:9180/apisix/admin/routes/getting-started-ip" -X PATCH -d '
{
"plugins": {
"limit-count": {
"count": 2,
"time_window": 10,
"rejected_code": 503
}
}
}'
# if all is successful, you will have this response:
HTTP/1.1 200 OK
Date: Mon, 11 Mar 2024 09:07:39 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.8.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: *
Access-Control-Max-Age: 3600
X-API-VERSION: v3
{
"key": "/apisix/routes/getting-started-ip",
"value": {
"status": 1,
"upstream": {
"pass_host": "pass",
"nodes": { "httpbin.org:80": 1 },
"type": "roundrobin",
"hash_on": "vars",
"scheme": "http"
},
"priority": 0,
"create_time": 1709909643,
"id": "getting-started-ip",
"uri": "/ip",
"plugins": {
"limit-count": {
"count": 2,
"rejected_code": 503,
"time_window": 10,
"key_type": "var",
"allow_degradation": false,
"policy": "local",
"show_limit_quota_header": true,
"key": "remote_addr"
},
"key-auth": {
"header": "apikey",
"hide_credentials": false,
"query": "apikey"
}
},
"update_time": 1710148059
}
}
To validate the effect of the plugin, which should limit the max number of request :
count=$(seq 100 | xargs -I {} curl "http://127.0.0.1:9080/ip" -I -sL -H 'apikey: secret-key' | grep "503" | wc -l); echo \"200\": $((100 - $count)), \"503\": $count
"200": 2, "503": 98
The expected result should be 2 requests with code 200 and rest in 503.