@@ -21,6 +21,7 @@ local enable_debug = require("apisix.debug").enable_debug
2121local wasm = require (" apisix.wasm" )
2222local expr = require (" resty.expr.v1" )
2323local apisix_ssl = require (" apisix.ssl" )
24+ local secret = require (" apisix.secret" )
2425
2526local ngx = ngx
2627local ngx_ok = ngx .OK
@@ -65,6 +66,56 @@ local merge_global_rule_lrucache = core.lrucache.new({
6566 ttl = 300 , count = 512
6667})
6768
69+ -- Cache for resolved plugin confs: original_conf -> {resolved, secret_vals}
70+ -- Weak keys ensure entries are GC'd when original conf is replaced (config reload)
71+ -- Weak-keyed cache: original_conf -> {resolved, secret_vals}.
72+ -- Avoids deepcopy on every request when secret values haven't changed,
73+ -- which preserves plugins' internal caches that use conf table identity
74+ -- as cache key (e.g. ai-rate-limiting's limit_conf_cache).
75+ local _resolved_cache = setmetatable ({}, {__mode = " k" })
76+ local _no_secret_ref = setmetatable ({}, {__mode = " k" })
77+
78+ local function vals_equal (a , b )
79+ if a == b then
80+ return true
81+ end
82+ if not a or not b then
83+ return false
84+ end
85+ for k , v in pairs (a ) do
86+ if b [k ] ~= v then
87+ return false
88+ end
89+ end
90+ for k in pairs (b ) do
91+ if a [k ] == nil then
92+ return false
93+ end
94+ end
95+ return true
96+ end
97+
98+ local function resolve_plugin_conf (conf )
99+ if _no_secret_ref [conf ] then
100+ return conf
101+ end
102+ if not secret .has_secret_ref (conf ) then
103+ _no_secret_ref [conf ] = true
104+ return conf
105+ end
106+
107+ local current_vals = secret .collect_secret_values (conf , true )
108+
109+ local cached = _resolved_cache [conf ]
110+ if cached and vals_equal (cached .secret_vals , current_vals ) then
111+ return cached .resolved
112+ end
113+
114+ local resolved = secret .fetch_secrets (conf , true )
115+ _resolved_cache [conf ] = {resolved = resolved , secret_vals = current_vals }
116+ return resolved
117+ end
118+
68119local local_conf
69120local check_plugin_metadata
70121
@@ -575,6 +626,14 @@ function _M.filter(ctx, conf, plugins, route_conf, phase)
575626 core .tablepool .release (" tmp_plugin_confs" , tmp_plugin_confs )
576627 end
577628
629+ -- resolve $secret:// and $env:// references in plugin confs
630+ for i = 2 , # plugins , 2 do
631+ local resolved = resolve_plugin_conf (plugins [i ])
632+ if resolved ~= plugins [i ] then
633+ plugins [i ] = resolved
634+ end
635+ end
636+
578637 return plugins
579638end
580639
@@ -600,6 +659,14 @@ function _M.stream_filter(user_route, plugins)
600659
601660 trace_plugins_info_for_debug (nil , plugins )
602661
662+ -- resolve $secret:// and $env:// references in stream plugin confs
663+ for i = 2 , # plugins , 2 do
664+ local resolved = resolve_plugin_conf (plugins [i ])
665+ if resolved ~= plugins [i ] then
666+ plugins [i ] = resolved
667+ end
668+ end
669+
603670 return plugins
604671end
605672
@@ -902,6 +969,7 @@ function _M.conf_version(conf)
902969end
903970
904971
972+
905973local function check_single_plugin_schema (name , plugin_conf , schema_type , skip_disabled_plugin )
906974 if type (plugin_conf ) ~= " table" then
907975 return false , " invalid plugin conf " ..
0 commit comments