🙈 By 陈潞波 2024-03-29
1.需求
控制面配置随着动态模块的增加,原先每个动态模块(声明式api统一使用/config)提供一个location配置的方式,配置项越来越多,需要提供一个统一的api 模块入口,由各动态模块向api模块进行注册,运行时根据实际的功能请求去调用注册的handler来进行处理
2. 现有动态api模块
2.1 现有的api单独模块
njet-config-api-module
njet-http-sendmsg-module
njet-http-cache-quick-module
njet-health-check-helper
njet-http-dyn-server-api-module
njet-http-location-api-module
njet-http-range-api-module
njet-http-ssl-api-module
njet-http-upstream-api-module
2.2 现有动态模块配置(声明式api以及命令式api):
server {
listen 8081;
//声明式api入口
location /config {
config_api;
}
location /hc {
health_check_api;
}
//upstream api
location /api {
api write=on;
}
location /kv {
dyn_sendmsg_kv;
}
location /ssl {
dyn_ssl_api;
}
location /range {
dyn_range_api;
}
location /cache {
cache_quick_api;
}
location /dyn_loc {
dyn_location_api;
}
location /dyn_srv {
dyn_server_api;
}
}
3. 统一注册模块方案
3.1 统一配置入口( 使用/api)
server {
listen 8081;
#api 统一入口
location /api {
dyn_module_api; #用于解析设置clcf->handler为统一入口handler
#权限校验
api_limit_except /v1/dyn_loc {method};
api_limit_except /v1/range {method};
}
location /doc {
doc_api;
}
}
3.2 api模块提供注册接口
•api module采用静态模块编译,在ctrl helper进程进行初始化
•api_module 类似kv模块提供注册接口,将各模块的key和handler进行保存
•各自模块按/v{version}/{module_name} 为key进行注册各自模块的handler,第一版version为1 各api模块注册key如下:
njet-config-api-module
/v1/config
njet-http-sendmsg-module
/v1/kv
njet-http-cache-quick-module
/v1/cache
njet-health-check-helper
/v1/hc
njet-http-dyn-server-api-module
/v1/dyn_srv
njet-http-location-api-module
/v1/dyn_loc
njet-http-range-api-module
/v1/range
njet-http-ssl-api-module
/v1/ssl
njet-http-upstream-api-module
/v1/upstream_api
3.3 api 模块内容处理阶段流程
• http请求到来时,根据url: /api/v{version}/{module_name}/{other} 来解析出key(/v{version}/{module_name})
•根据key来查找是否有注册的handler,没有直接返回404;如果找到,则调用handler进行处理
4. api_limit_except 方案
4.1 limit_except 指令介绍
Syntax: | limit_except method…{…} |
Default | - |
Context: | location |
Limits allowed HTTP methods inside a location. The method parameter can be one of the following: GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK, or PATCH. Allowing the GET method makes the HEAD method also allowed. Access to other methods can be limited using the ngx_http_access_module, ngx_http_auth_basic_module, and ngx_http_auth_jwt_module (1.13.10) modules directives:
limit_except GET {
allow 192.168.1.0/32;
deny all;
}
Please note that this will limit access to all methods except GET and HEAD.
4.2 api_limit_except 指令方案
4.2.1 需求
目标:
•针对api module, 新增api_limit_except 指令(可配置多条,针对不同的api模块做限制)
limit_except 特点:
•limit_except指令能够对配置的location 进行权限控制,每个location职能配置一个limit_except, 该指令会在access阶段注册权限验证的handler,验证通过后才可进行后续的内容处理阶段
•limit_except指令也会生成一个noname的location结构在内存中
故需要实现一个新的api_limit_except 指令,要实现两个目标:
•可配置多条,对配置不同的模块url能够配置一个limit_except
•api location要同时能够生成支持多个的noname的location结构在内存里,能够在有http请求时,根据实际的url调用正确的limit_except配置的权限访问控制
NOTES:
如果配置了limit_except, 则会进行双层验证,规则如下:
•limit_except 验证优先
•limit_except 如果需要验证,则使用limit_except的密码验证
•limit_except 如果允许,则会进入到api_limit_except 配置的权限验证
4.2.2 api_limit_except 指令介绍
Syntax: | api_limit_except module_key method…{…} |
Default | - |
Context: | location |
针对limit_except新增一个module_key参数,这个参数就是 各api 模块的url前缀格式:/api/v{version}/{module_name}开头
声明式api 模块前缀: /api/v1/config
kv模块: /api/v1/kv
cache加速:/api/v1/cache
健康检查: /api/v1/hc
动态VS: /api/v1/dyn_srv
动态location: /api/v1/dyn_loc
动态range: /api/v1/range
动态ssl: /api/v1/ssl
动态upstream: /api/v1/upstream_api
4.2.3 配置示例
•htpasswd命令使用方法:
centos:
yum install -y httpd
ubuntu:
apt install -y apache2-utils
密码文件/root/bug/njet1.0/htpasswd 新增用户test 密码是123456
htpasswd -bc /root/bug/njet1.0/htpasswd test 123456
密码文件/root/bug/njet1.0/htpasswd_ssl 新增用户test2 密码是test2
htpasswd -bc /root/bug/njet1.0/htpasswd_ssl test2 test2
server {
listen 8081;
#api 统一入口
location /api {
dyn_module_api;
#dyn_loc 权限校验, 非GET请求需要校验
api_limit_except /v1/ssl GET {
auth_basic "OpenNJet SSL API";
auth_basic_user_file /root/bug/njet1.0/htpasswd_ssl;
}
#range 权限校验, 非PUT请求需要校验
api_limit_except /v1/range PUT {
auth_basic "OpenNJet RANGE API";
auth_basic_user_file /root/bug/njet1.0/htpasswd;
}
#其他url请求,不做权限校验
}
location /doc {
doc_api;
}
location /metrics {
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
}
location /adc {
#return 200 "ok";
content_by_lua_file scripts/http_register.lua;
}
}
5. 测试
所有声明式api和命令式api 的接口前缀统一
5.1 ctrl配置文件
server {
listen 8081;
#api 统一入口
location /api {
dyn_module_api;
}
location /doc {
doc_api;
}
}
5.2 模块测试(功能不变,变化的只是所有api模块的url变动)
所有声明式api和命令式api 的接口前缀统一改为/api/v{version}/{module_name}开头
声明式api 模块前缀: /api/v1/config
kv模块: /api/v1/kv
cache加速:/api/v1/cache
健康检查: /api/v1/hc
动态VS: /api/v1/dyn_srv
动态location: /api/v1/dyn_loc
动态range: /api/v1/range
动态ssl: /api/v1/ssl
动态upstream|: /api/v1/upstream_api
5.2.1 动态ssl证书:/api/v1/ssl
5.2.2 健康检查: /api/v1/hc
5.2.3 动态range: /api/v1/range
5.2.4 cache 加速: /api/v1/cache
5.2.5 kv: /api/v1/kv
5.2.6 Config API: /api/v1/config
5.3 api_limit_except 权限校验测试
5.3.1 校验密码文件生成示例:
centos:
yum install -y httpd
ubuntu:
apt install -y apache2-utils
密码文件/root/bug/njet1.0/htpasswd 新增用户test 密码是123456
htpasswd -bc /root/bug/njet1.0/htpasswd test 123456
密码文件/root/bug/njet1.0/htpasswd_ssl 新增用户test2 密码是test2
htpasswd -bc /root/bug/njet1.0/htpasswd_ssl test2 test2
5.3.2 配置(以测试ssl和range为例):
server {
listen 8081;
location /api {
dyn_module_api;
#针对 ssl 添加校验,用户名密码使用test2/test2
api_limit_except /v1/ssl GET {
auth_basic "OpenNJet API";
auth_basic_user_file /root/bug/njet1.0/htpasswd_ssl;
}
#针对 range 添加校验,用户名密码使用test/123456
api_limit_except /v1/range PUT {
auth_basic "OpenNJet API";
auth_basic_user_file /root/bug/njet1.0/htpasswd;
}
#如果同时配置了limit_except, 则优先判断limit_except权限配置,
#如果limit_except 不检查,则会进入到api_limit_except 权限配置检查
#limit_except GET{
# auth_basic "OpenNJet API";
# auth_basic_user_file /root/bug/njet1.0/htpasswd;
#}
}
}
5.3.3 测试:
5.3.3.1 ssl校验测试
针对ssl, GET方法不校验,其他方法校验,所以调用get接口不会让输入密码,调用put接口,会让输入密码,密码输入正确的test2/test2才会通过
5.3.3.1.1 Get 测试: 直接返回结果
5.3.3.1.2 PUT测试:需要输入密码, 密码正确后返回结果
输入密码正确,进入内容处理阶段
5.3.3.2 range校验测试
针对range, PUT方法不校验,其他方法校验,所以调用put接口不会让输入密码,调用get接口,会让输入密码,密码输入正确的test/123456才会通过
5.3.3.2.1 GET 测试: 需要输入密码
GET 需要输入密码 test/123456
输入正确密码,返回结果