api 统一注册模块

🙈 By 陈潞波 2024-03-29

api 统一注册模块

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

img

5.2.2 健康检查: /api/v1/hc

img

5.2.3 动态range: /api/v1/range

img

5.2.4 cache 加速: /api/v1/cache

img

5.2.5 kv: /api/v1/kv

img

5.2.6 Config API: /api/v1/config

img

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 测试: 直接返回结果

img

5.3.3.1.2 PUT测试:需要输入密码, 密码正确后返回结果

img

输入密码正确,进入内容处理阶段

img

5.3.3.2 range校验测试

针对range, PUT方法不校验,其他方法校验,所以调用put接口不会让输入密码,调用get接口,会让输入密码,密码输入正确的test/123456才会通过

5.3.3.2.1 GET 测试: 需要输入密码

GET 需要输入密码 test/123456

img

输入正确密码,返回结果

img

5.3.3.2.2 PUT测试: 不用输入密码,直接到内容处理阶段

img