This is an automated email from the ASF dual-hosted git repository.

AlinsRan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new b87b54d5a fix(stream): initialize env and secret for TLS cert 
resolution (#12935)
b87b54d5a is described below

commit b87b54d5a7811b0d0db1b236d916f40dd6da8e4f
Author: Surya Parua <[email protected]>
AuthorDate: Wed Aug 5 04:04:14 2026 +0530

    fix(stream): initialize env and secret for TLS cert resolution (#12935)
---
 apisix/constants.lua                 |   1 +
 apisix/init.lua                      |   2 +
 docs/en/latest/terminology/secret.md |   2 +-
 t/stream-node/tls.t                  | 183 +++++++++++++++++++++++++++++++++++
 4 files changed, 187 insertions(+), 1 deletion(-)

diff --git a/apisix/constants.lua b/apisix/constants.lua
index 0b3ec160b..0124c5ee5 100644
--- a/apisix/constants.lua
+++ b/apisix/constants.lua
@@ -42,5 +42,6 @@ return {
         ["/ssls"] = true,
         ["/stream_routes"] = true,
         ["/plugin_metadata"] = true,
+        ["/secrets"] = true,
     },
 }
diff --git a/apisix/init.lua b/apisix/init.lua
index 801944c36..fe1f2f688 100644
--- a/apisix/init.lua
+++ b/apisix/init.lua
@@ -1332,6 +1332,7 @@ function _M.stream_init(args)
     core.log.info("enter stream_init")
 
     core.resolver.init_resolver(args)
+    core.env.init()
 
     if core.config.init then
         local ok, err = core.config.init()
@@ -1373,6 +1374,7 @@ function _M.stream_init_worker()
 
     plugin.init_worker()
     xrpc.init_worker()
+    apisix_secret.init_worker()
     router.stream_init_worker()
     require("apisix.http.service").init_worker()
     apisix_upstream.init_worker()
diff --git a/docs/en/latest/terminology/secret.md 
b/docs/en/latest/terminology/secret.md
index 304856fb0..347bcf7cb 100644
--- a/docs/en/latest/terminology/secret.md
+++ b/docs/en/latest/terminology/secret.md
@@ -49,7 +49,7 @@ You can use APISIX Secret functions by specifying format 
variables in the consum
 Secret references (`$secret://...`, `$env://...`, `$ENV://...`) can be used in 
the following contexts:
 
 - **Plugin configurations**: Any string field in any plugin configuration. 
Secret references are automatically resolved at runtime in `plugin.filter()` 
before the plugin executes.
-- **SSL certificates**: The `cert`, `key`, `certs`, and `keys` fields in SSL 
resources. Secret references are resolved during TLS handshake.
+- **SSL certificates**: The `cert`, `key`, `certs`, and `keys` fields in SSL 
resources. Secret references are resolved during TLS handshake, including 
stream (L4) TLS mode.
 - **Consumer auth configurations**: Any string field in consumer 
authentication plugin configurations (e.g., `key-auth`, `jwt-auth`). Secret 
references are resolved when consumer configuration is loaded.
 
 :::tip
diff --git a/t/stream-node/tls.t b/t/stream-node/tls.t
index 13bdcba0f..90a932290 100644
--- a/t/stream-node/tls.t
+++ b/t/stream-node/tls.t
@@ -14,6 +14,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+BEGIN {
+    sub set_env_from_file {
+        my ($env_name, $file_path) = @_;
+
+        open my $fh, '<', $file_path or die $!;
+        my $content = do { local $/; <$fh> };
+        close $fh;
+
+        $ENV{$env_name} = $content;
+    }
+    set_env_from_file('APISIX_STREAM_ENV_CERT', 't/certs/apisix.crt');
+    set_env_from_file('APISIX_STREAM_ENV_KEY',  't/certs/apisix.key');
+}
+
 use t::APISIX 'no_plan';
 
 log_level('info');
@@ -133,3 +147,172 @@ fetch table plugins
 release table ctx_var
 release table plugins
 release table api_ctx
+
+
+
+=== TEST 6: stream tls supports $ENV certificate reference
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin")
+
+            local data = {
+                cert = "$ENV://APISIX_STREAM_ENV_CERT",
+                key  = "$ENV://APISIX_STREAM_ENV_KEY",
+                sni  = "test.com",
+            }
+
+            local code, body = t.test('/apisix/admin/ssls/1',
+                ngx.HTTP_PUT,
+                core.json.encode(data)
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            local code, body = t.test('/apisix/admin/stream_routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1995": 1
+                        },
+                        "type": "roundrobin"
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say("passed")
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 7: hit stream route with $ENV cert reference
+--- stream_tls_request
+mmm
+--- stream_sni: test.com
+--- response_body
+hello world
+
+
+
+=== TEST 8: store cert and key in vault for stream tls
+--- exec
+VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/ssl 
\
+    test.com.crt=@t/certs/apisix.crt \
+    test.com.key=@t/certs/apisix.key
+--- response_body
+Success! Data written to: kv/apisix/ssl
+
+
+
+=== TEST 9: set secret provider (vault) for stream tls
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+
+            local code, body = t('/apisix/admin/secrets/vault/stream-test',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "http://0.0.0.0:8200";,
+                    "prefix": "kv/apisix",
+                    "token": "root"
+                }]],
+                [[{
+                    "key": "/apisix/secrets/vault/stream-test",
+                    "value": {
+                        "uri": "http://0.0.0.0:8200";,
+                        "prefix": "kv/apisix",
+                        "token": "root"
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 10: stream tls supports $secret certificate reference
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin")
+
+            local data = {
+                cert = "$secret://vault/stream-test/ssl/test.com.crt",
+                key  = "$secret://vault/stream-test/ssl/test.com.key",
+                sni  = "secret.test.com",
+            }
+
+            local code, body = t.test('/apisix/admin/ssls/3',
+                ngx.HTTP_PUT,
+                core.json.encode(data)
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            local code, body = t.test('/apisix/admin/stream_routes/3',
+                ngx.HTTP_PUT,
+                [[{
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1995": 1
+                        },
+                        "type": "roundrobin"
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say("passed")
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 11: hit stream route with secret cert
+--- stream_tls_request
+hello
+--- stream_sni: secret.test.com
+--- response_body
+hello world

Reply via email to