fix(env): fix os.getenv prefix collision bug in init_by_lua phase - #13147
fix(env): fix os.getenv prefix collision bug in init_by_lua phase#13147currenjin wants to merge 2 commits into
Conversation
In OpenResty's init_by_lua phase, os.getenv() uses nginx's internal environment mechanism which performs prefix-based matching when env NAME=VALUE directives share a common prefix. This causes os.getenv() to return the shorter-named variable's value when the longer-named one is requested (e.g., KUBERNETES_CLIENT_TOKEN_FILE returns the value of KUBERNETES_CLIENT_TOKEN). The fix overrides os.getenv in _M.init() with a wrapper that uses exact table lookup from apisix_env_vars (built correctly from ffi.C.environ). Also moves core.env.init() to be the first call in http_init() to ensure the override is applied before any other code in init_by_lua can call os.getenv. Fixes apache#13055
|
Hi @currenjin, please fix the lint error |
|
Fixed the lint error by adding |
|
This pull request has been marked as stale due to 60 days of inactivity. It will be closed in 4 weeks if no further activity occurs. If you think that's incorrect or this pull request should instead be reviewed, please simply write any comment. Even if closed, you can still revive the PR at any time or discuss it on the dev@apisix.apache.org list. Thank you for your contributions. |
|
I looked into the underlying issue (#13055) and I don't think this approach can work, unfortunately. The collision happens in init_by_lua, where lua-resty-core has replaced The real bug is in lua-nginx-module's |
Problem
In OpenResty's
init_by_luaphase,os.getenv()uses nginx's internal environment mechanism which performs prefix-based matching whenenv NAME=VALUEdirectives share a common prefix. This causesos.getenv()to return the shorter-named variable's value when the longer-named one is requested.Example: with both
KUBERNETES_CLIENT_TOKENandKUBERNETES_CLIENT_TOKEN_FILEdefined asenv NAME=VALUE;directives, callingos.getenv("KUBERNETES_CLIENT_TOKEN_FILE")returnsKUBERNETES_CLIENT_TOKEN's value when the shorter name appears first in the config.Fixes #13055
Root cause
OpenResty's
os.getenvininit_by_luadoes not perform exact-match lookup whenenv NAME=VALUE;directives have a common prefix — the shorter name is matched first. In contrast, readingffi.C.environdirectly with Lua string operations (as_M.init()already does) produces a correctly keyed table.Fix
apisix/core/env.lua: After_M.init()populatesapisix_env_varsfromffi.C.environ, overrideos.getenvwith a wrapper that does exact table lookup. Falls back to the originalos.getenvfor variables set dynamically after startup (e.g., viacore.os.setenv).apisix/init.lua: Movecore.env.init()to be the first call inhttp_init(), ensuring the override is applied before any other code ininit_by_luacan callos.getenv.Tests
os.getenvreturns correct values when shorter-prefix variable is declared first in nginx config.os.getenvcalled insideinit_by_lua(viaextra_init_by_lua) returns correct values for prefix-colliding variables.Risk / Compatibility
os.getenvis monkey-patched globally after_M.init(). Existing callers continue to work — the semantics are identical for non-colliding variable names.core.os.setenvfall back to the originalos.getenv, so those are unaffected.http_initis safe:core.env.init()has no dependencies onresolveroridinitialization.