前言
当我们应用的接口不需要密钥既可访问时,我们的接口容易被人抓包,数据容易被人爬取. 当我们应用的接口没有限制访问频率,手机短信验证码等成本较高的服务容易被人恶意攻击.Kong是一款开源的云原生架构下的分布式 API 网关,其性能和可扩展性在同类组件中,表现都很优异.Kong 官方提供了很多直接可用的插件,本文详细记录了kong的部署搭建过程以及使用官方插件实现api权限控制,接口访问频率限制的功能.
以下主要介绍kong的基本概念,部署配置,权限控制和限流的插件使用
1 基本概念
Admin API(动态修改配置):Kong Gateway带有一个内部restfulapi,用于管理目的。API命令可以在集群中的任何节点上运行,并且配置将一致地应用于所有节点。
Consumers(用户,群组,版本): Consumer的核心原则是您可以为其添加插件,从而自定义他的请求行为. 所以,或许您会有一个手机APP应用,并为他的每个版本都定义一个consumer, 又或者您有一个应用或几个应用,并为这些应用定义统一个consumer,这些都无所谓.
Routes(相当于nginx配置中的location,url匹配): 路由是进入kong的入口,为匹配的请求定义规则,在Kong中定义细粒度的入口点,从而引导您的访问到不同接口服务.
Service (相当于nginx配置中的server):服务实体是您自己的每个上游服务的抽象。 Service 可以与下面的Route进行关联,一个Service可以有很多Route,匹配到的Route就会转发到Service中.
Plugins(相当于nginx配置中的脚本):插件提供了一个模块化的系统来修改和控制网关的功能。例如,为了保护您的API,您可能需要一个访问密钥,您可以使用keyauth插件设置该密钥。插件提供了广泛的功能,包括访问控制、缓存、速率限制、修改请求体、日志记录等等。
2 部署
初始化数据库:
sudo git clone https://github.com/mrts/docker-postgresql-multiple-databases
cd docker-postgresql-multiple-databases
sudo docker build -t="postgresql:multi" .
sudo docker run --name=pgtemp -e POSTGRES_PASSWORD=kong -e POSTGRES_MULTIPLE_DATABASES=kong,konga -v "$PWD/../data:/var/lib/postgresql/data" postgresql:multi
#可选择检查是否在初始化时成功创建两个数据库
#docker exec -it pgtemp sh
#psql kong kong
#postgres=# \l
sudo docker rm -f pgtemp
cd ../
sudo touch docker-compose.yml
配置docker-compose.yml:
version: '3.7'
volumes:
kong_data: {}
networks:
kong-net:
external: false
services:
kong-migrations:
image: "${KONG_DOCKER_TAG:-kong:latest}"
command: kong migrations bootstrap
depends_on:
- db
environment:
KONG_DATABASE: postgres
KONG_PG_DATABASE: kong
KONG_PG_HOST: db
KONG_PG_USER: postgres
KONG_PG_PASSWORD: 密码
networks:
- kong-net
restart: on-failure
deploy:
restart_policy:
condition: on-failure
kong-migrations-up:
image: "${KONG_DOCKER_TAG:-kong:latest}"
command: kong migrations up && kong migrations finish
depends_on:
- db
environment:
KONG_DATABASE: postgres
KONG_PG_DATABASE: kong
KONG_PG_HOST: db
KONG_PG_USER: postgres
KONG_PG_PASSWORD: 密码
networks:
- kong-net
restart: on-failure
deploy:
restart_policy:
condition: on-failure
kong:
image: "${KONG_DOCKER_TAG:-kong:latest}"
user: "${KONG_USER:-kong}"
depends_on:
- db
environment:
KONG_ADMIN_LISTEN: '0.0.0.0:8001'
KONG_CASSANDRA_CONTACT_POINTS: db
KONG_DATABASE: postgres
KONG_PG_DATABASE: kong
KONG_PG_HOST: db
KONG_PG_USER: postgres
KONG_PG_PASSWORD: 密码
KONG_LOG_LEVEL: debug
KONG_REAL_IP_HEADER: X-Forwarded-For
KONG_TRUSTED_IPS: 172.20.0.1
networks:
- kong-net
ports:
- "8000:8000/tcp"
- "0.0.0.1:8001:8001/tcp"
- "8443:8443/tcp"
- "0.0.0.1:8444:8444/tcp"
healthcheck:
test: ["CMD", "kong", "health"]
interval: 10s
timeout: 10s
retries: 10
restart: on-failure
deploy:
restart_policy:
condition: on-failure
volumes:
- ./logs:/usr/local/kong/logs
konga:
image: pantsel/konga
environment:
DB_ADAPTER: postgres
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: konga
DB_USER: progress
DB_PASSWORD: 密码
NODE_ENV: ${KONGA_ENV}
KONGA_HOOK_TIMEOUT: 10000
restart: on-failure
ports:
- 8080:1337
depends_on:
- db
networks:
- kong-net
db:
image: postgres:9.6
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=密码
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 30s
timeout: 30s
retries: 3
restart: on-failure
deploy:
restart_policy:
condition: on-failure
stdin_open: true
tty: true
networks:
- kong-net
ports:
- 5432:5432
volumes:
- ./postgresql/data:/var/lib/postgresql/data
启动:
sudo curl -L "https://github.com/docker/compose/releases/download/1.28.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo docker-copmose up
3 konga管理UI界面介绍
demo地址:lab.liuxuan.tech
登陆:kong kongkong
3.1 配置kong-admin url
konga管理控制台界面需要指定kong-admin url后才能正常工作,下面是配置的过程:
1 在konga管理后台的菜单列表点击CONNECTIONS
2 点击+NEW CONNECTIOIN按钮
3 填写kong-admin url信息
name可任意填写:kong
kong Admin URL填写部署应用时配置的kong-admin url:http://kong:8002
点击 UPDATE CONNECTION 按钮
再点击ACTIVE按钮
3.1.1 拓展:admin url安全性配置
Kong-admin,此API是为内部使用而设计的,并提供对kong的完全控制,因此在设置kong环境时应小心,以避免此API的不当公开暴露。以下有三种方式:
1 admin api指定特定ip访问
admin_listen = 127.0.0.1:8001
avoid binding Kong to all of your interfaces避免设置为向所有ip开放, by using values such as 0.0.0.0:8001
.
2 使用iptable指定特定ip访问
$ grep admin_listen /etc/kong/kong.conf
admin_listen 10.10.10.3:8001
# explicitly allow TCP packets on port 8001 from the Kong node itself
# this is not necessary if Admin API requests are not sent from the node
$ iptables -A INPUT -s 10.10.10.3 -m tcp -p tcp --dport 8001 -j ACCEPT
# explicitly allow TCP packets on port 8001 from the following addresses
$ iptables -A INPUT -s 10.10.10.4 -m tcp -p tcp --dport 8001 -j ACCEPT
$ iptables -A INPUT -s 10.10.10.5 -m tcp -p tcp --dport 8001 -j ACCEPT
# drop all TCP packets on port 8001 not in the above IP list
$ iptables -A INPUT -m tcp -p tcp --dport 8001 -j DROP
3 将admin-url作为服务管理权限控制
curl -X POST http://localhost:8001/services \ --data name**=**my-service \ --data url**=**http://example.com/some_api
3.2 配置services
新建services,相当于nginx中的server,主要用来区分url
3.3 配置routers
在service下配置routers,相当于nginx中的server,即配置接口或接口url前缀转发规则
至此,基本的配置已经完毕,请求curl https://www.liuxuan.tech/baike/api/healthcheck/readiness 即可转发至
http://testask.gf.com.cn/baike/api/healthcheck/readiness
4 配置插件
4.1 鉴权
4.1.1开启Hmac Auth鉴权
使用场景:
1 提供给其他服务的外部接口增加鉴权
2 包含敏感信息或重要数据的接口增加鉴权
- 参数
参数 | 描述 |
---|---|
name | 插件名称、此处为hmac-auth |
service_id | 绑定的服务Id |
route_id | 绑定的路由Id |
enabled | 是否启用该插件,默认是true |
config.hide_credentials | 是否隐藏请求中的凭证信息(如Authorization 头),默认是false |
config.clock_skew | 时间偏移量,默认是300s |
config.anonymous | 在验证失败后是否启用匿名消费者,值可以配置为消费者Id |
config.validate_request_body | 是否启用Body体校验,默认是false |
config.enforce_headers | 请求中必须包含的头部信息 |
config.algorithms | HMAC 算法支持的列表,默认值是hmac-sha1,hmac-sha256,hmac-sha384,hmac-sha512 |
lient端实例代码:
https://dzone.com/articles/protect-rest-service-using-0
4.1.2 登陆态鉴权-kong 自研插件实践,广发通 oa token 解析
http://wiki.gf.com.cn/pages/viewpage.action?pageId=89839509
4.2 开启Rate Limiting限频
4.2.1 配置插件
4.2.2 如何防欺诈
封禁用户的标记有很多种,最基本的如果用户有登录态的话,就可以直接封账号。如果没有的话,可以通过设备指纹来标识设备,根据平台的不同,设备指纹可以是 PC 端的浏览器指纹,移动端的 IMEI、MAC 地址、UUID 等,或者这些条件综合起来计算出来的 machine key,使之无法造假,然后在关键请求时校验 machine key 的合法性。下面介绍可以快速实现的根据ip地址限频:
请求中几个关于IP的http头信息
-
X-FORWARDED-FOR 并不是标准协议头。当你使用了代理时,web服务器就不知道你的真实IP了,为了避免这个情况,代理服务器通常会增加一个叫做
X_Forwarded_For
的头信息,把连接它的客户端IP(即你的上网机器IP)加到这个头信息里,这样就能保证网站的web服务器能获取到真实IP。它的格式通常是X-Forwarded-For: client1, proxy1, proxy2
。此外,请注意,它也很容易被客户端欺骗。只有当您控制设置标头的代理时,才应该使用此标头 -
RemoteAddr 代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的IP指定的,访问某个网站时,假设中间没有任何代理,那么网站的web服务器(
Nginx
,Apache
)就会把remote_addr
设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr
设为这台代理机器的IP。RemoteAddr基本上不能被伪造,因为是直接从 TCP 连接信息中获取的.关于伪造remoteAddr:https://yonghaowu.github.io/2018/11/23/get_reql_ip/
获取ip的方案:如果http请求经过代理,那么就从X-Forwarded-For
中获取,如果没有经过代理,那就从REMOTE_ADDR
中获取。由于我们部署服务所处的网络环境基本都被代理,故用X-Forwarded-For来获取客户端的ip.
在kong的配置文件or启动参数中加入:
#通过X-Forwarded-For请求头获取真实ip,默认是通过RemoteAddr
real_ip_header X-Forwarded-For;
#信任ip名单;配置后kong会把X-Forwarded-For中最后一个不是信任服务器的IP当成真实IP
real_ip_from [trusted proxy addresses or cidr blocks]
拓展:谈谈 Kong rate-limiting 插件中的缺陷-Redis 高频卡控中的 Race Conditions 问题 https://ms2008.github.io/2018/04/04/kong-rate-limiting/
refference:
[github issues] KONG如何配置X-Forwarded-For参数代替RemoteAddr
https://github.com/Kong/kong/issues/2020
https://discuss.konghq.com/t/how-to-forward-clients-request-ip/384