@@ -41,6 +41,26 @@ ffi.cdef [[
4141]]
4242
4343
44+ -- Build an exact-keyed table from the process environment (`environ`).
45+ --
46+ -- This is intentionally used instead of `os.getenv` to sidestep a bug in
47+ -- lua-resty-core's `os.getenv` shim that is active before any request is
48+ -- being served (init / init_worker phases). That shim relies on
49+ -- `ngx_http_lua_ffi_get_conf_env`, which matches an `env NAME=VALUE;`
50+ -- directive entry against the queried name with a prefix-only comparison
51+ -- (`ngx_strncmp(name, var.data, var.len)`) and does not require the queried
52+ -- name to end at `var.len`. As a result, when two `env` directives share a
53+ -- common prefix (e.g. `KUBERNETES_CLIENT_TOKEN` and
54+ -- `KUBERNETES_CLIENT_TOKEN_FILE`), the shorter declared name shadows the
55+ -- longer one. Reading `environ` directly and keying by the substring before
56+ -- the first `=` avoids the collision entirely. See apache/apisix#13055.
57+ --
58+ -- Note on phases: nginx applies `env NAME=VALUE;` directives to the real
59+ -- `environ` in `ngx_set_environment`, which runs at worker process start
60+ -- (before `init_worker_by_lua`). Therefore `init()` must be called again in
61+ -- the worker init phase so that directive-assigned values are captured; at
62+ -- the `init_by_lua` phase `environ` only contains variables inherited from
63+ -- the OS, not the directive-assigned ones.
4464function _M .init ()
4565 local e = ffi .C .environ
4666 if not e then
@@ -61,6 +81,21 @@ function _M.init()
6181end
6282
6383
84+ -- Look up an environment variable by exact name.
85+ --
86+ -- Prefer the snapshot built by `init()` (immune to the prefix-collision bug
87+ -- described above) and only fall back to `os.getenv` for variables that were
88+ -- set dynamically after startup (e.g. via `core.os.setenv`).
89+ function _M .get (name )
90+ local val = apisix_env_vars [name ]
91+ if val ~= nil then
92+ return val
93+ end
94+
95+ return os.getenv (name )
96+ end
97+
98+
6499local function parse_env_uri (env_uri )
65100 -- Avoid the error caused by has_prefix to cause a crash.
66101 if type (env_uri ) ~= " string" then
@@ -93,7 +128,7 @@ function _M.fetch_by_uri(env_uri)
93128 return nil , err
94129 end
95130
96- local main_value = apisix_env_vars [ opts . key ] or os.getenv (opts .key )
131+ local main_value = _M . get (opts .key )
97132 if main_value and opts .sub_key ~= " " then
98133 local vt , err = json .decode (main_value )
99134 if not vt then
0 commit comments