diff --git a/apisix/plugins/chaitin-waf.lua b/apisix/plugins/chaitin-waf.lua index 6c82c4a70f6b..f610a2c79f54 100644 --- a/apisix/plugins/chaitin-waf.lua +++ b/apisix/plugins/chaitin-waf.lua @@ -65,6 +65,10 @@ local plugin_schema = { type = "boolean", default = false }, + allow_degradation = { + type = "boolean", + default = false + }, config = { type = "object", properties = { @@ -314,6 +318,11 @@ local function do_access(conf, ctx) extra_headers[HEADER_CHAITIN_WAF] = "unhealthy" extra_headers[HEADER_CHAITIN_WAF_ERROR] = tostring(err) + if conf.allow_degradation then + core.log.warn("chaitin-waf: no healthy nodes, degradation enabled, passing request") + return nil, nil, extra_headers + end + return 500, nil, extra_headers end @@ -361,6 +370,11 @@ local function do_access(conf, ctx) end extra_headers[HEADER_CHAITIN_WAF_ERROR] = tostring(err) + if conf.allow_degradation then + core.log.warn("chaitin-waf: WAF error (", err_msg, "), degradation enabled, passing request") + return nil, nil, extra_headers + end + if mode == "monitor" then core.log.warn("chaitin-waf monitor mode: detected waf error - ", err_msg) return nil, nil, extra_headers diff --git a/docs/en/latest/plugins/chaitin-waf.md b/docs/en/latest/plugins/chaitin-waf.md index 2f3e357dccd5..b9c6700cd151 100644 --- a/docs/en/latest/plugins/chaitin-waf.md +++ b/docs/en/latest/plugins/chaitin-waf.md @@ -57,6 +57,7 @@ The Plugin can add the following response headers, depending on the configuratio | match.vars | array[array] | false | | | An array of one or more matching conditions in the form of [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) to conditionally execute the plugin. | | append_waf_resp_header | boolean | false | true | | If true, add response headers `X-APISIX-CHAITIN-WAF`, `X-APISIX-CHAITIN-WAF-TIME`, `X-APISIX-CHAITIN-WAF-ACTION`, and `X-APISIX-CHAITIN-WAF-STATUS`. | | append_waf_debug_header | boolean | false | false | | If true, add debugging headers `X-APISIX-CHAITIN-WAF-ERROR` and `X-APISIX-CHAITIN-WAF-SERVER` to the response. Effective only when `append_waf_resp_header` is `true`. | +| allow_degradation | boolean | false | false | | If true, requests will be passed through instead of returning an error when the WAF service is unavailable (e.g., connection timeout, no healthy nodes). This prevents the WAF service from becoming a single point of failure. | | config | object | false | | | Chaitin WAF service configurations. These settings override the corresponding metadata defaults when specified. | | config.connect_timeout | integer | false | 1000 | | The connection timeout to the WAF service, in milliseconds. | | config.send_timeout | integer | false | 1000 | | The sending timeout for transmitting data to the WAF service, in milliseconds. | diff --git a/docs/zh/latest/plugins/chaitin-waf.md b/docs/zh/latest/plugins/chaitin-waf.md index a90cae2454c9..83f0c5a095e5 100644 --- a/docs/zh/latest/plugins/chaitin-waf.md +++ b/docs/zh/latest/plugins/chaitin-waf.md @@ -57,6 +57,7 @@ description: chaitin-waf 插件与长亭雷池 WAF 集成,以检测和阻止 | match.vars | array[array] | 否 | | | 一个或多个匹配条件数组,使用 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list) 表达式来有条件地执行插件。 | | append_waf_resp_header | boolean | 否 | true | | 若为 true,则在响应中添加 `X-APISIX-CHAITIN-WAF`、`X-APISIX-CHAITIN-WAF-TIME`、`X-APISIX-CHAITIN-WAF-ACTION` 和 `X-APISIX-CHAITIN-WAF-STATUS` 响应头。 | | append_waf_debug_header | boolean | 否 | false | | 若为 true,则在响应中添加调试用响应头 `X-APISIX-CHAITIN-WAF-ERROR` 和 `X-APISIX-CHAITIN-WAF-SERVER`。仅当 `append_waf_resp_header` 为 true 时生效。 | +| allow_degradation | boolean | 否 | false | | 若为 true,当 WAF 服务不可用(如连接超时、无健康节点)时,请求将被放行而不是返回错误。这可以防止 WAF 服务成为单点故障。 | | config | object | 否 | | | 长亭 WAF 服务配置。这些配置在指定时会覆盖对应的元数据默认值。 | | config.connect_timeout | integer | 否 | 1000 | | 与 WAF 服务的连接超时时间,单位为毫秒。 | | config.send_timeout | integer | 否 | 1000 | | 向 WAF 服务发送数据的超时时间,单位为毫秒。 | diff --git a/t/plugin/chaitin-waf-timeout.t b/t/plugin/chaitin-waf-timeout.t index 063f1bc4e186..8d23fe6b8a75 100644 --- a/t/plugin/chaitin-waf-timeout.t +++ b/t/plugin/chaitin-waf-timeout.t @@ -137,3 +137,98 @@ hello world X-APISIX-CHAITIN-WAF: timeout --- response_headers_like X-APISIX-CHAITIN-WAF-TIME: + + + +=== TEST 3: allow_degradation=true on timeout +--- config + location /do { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "plugins": { + "chaitin-waf": { + "mode": "block", + "allow_degradation": true + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/*" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 4: timeout with allow_degradation=true, request passed +--- request +GET /hello +--- error_code: 200 +--- response_body +hello world +--- error_log +degradation enabled, passing request +--- response_headers +X-APISIX-CHAITIN-WAF: timeout + + + +=== TEST 5: allow_degradation=false on timeout (default behavior) +--- config + location /do { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "plugins": { + "chaitin-waf": { + "mode": "block", + "allow_degradation": false + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/*" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 6: timeout with allow_degradation=false, request blocked +--- request +GET /hello +--- error_code: 500 +--- error_log +--- response_headers +X-APISIX-CHAITIN-WAF: timeout