This is an automated email from the ASF dual-hosted git repository.
nic-6443 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 59ab7ef8bf fix(admin): encrypt the inline upstream client key of a
stream route (#13833)
59ab7ef8bf is described below
commit 59ab7ef8bfebc3ccb2a2acd97874498724a563c8
Author: Nic <[email protected]>
AuthorDate: Tue Aug 18 11:44:44 2026 +0800
fix(admin): encrypt the inline upstream client key of a stream route
(#13833)
---
apisix/admin/stream_routes.lua | 7 ++++++
t/admin/stream-routes.t | 50 ++++++++++++++++++++++++++++++++++++++++++
t/stream-node/upstream-mtls.t | 47 +++++++++++++++++++++++++++++++++++++++
3 files changed, 104 insertions(+)
diff --git a/apisix/admin/stream_routes.lua b/apisix/admin/stream_routes.lua
index d4a79ac889..9bd94906b2 100644
--- a/apisix/admin/stream_routes.lua
+++ b/apisix/admin/stream_routes.lua
@@ -16,6 +16,7 @@
--
local core = require("apisix.core")
local resource = require("apisix.admin.resource")
+local apisix_upstream = require("apisix.upstream")
local stream_route_checker =
require("apisix.stream.router.ip_port").stream_route_checker
local tostring = tostring
local ipairs = ipairs
@@ -151,12 +152,18 @@ local function delete_checker(id)
end
+local function encrypt_conf(id, conf)
+ apisix_upstream.encrypt_conf(conf.upstream)
+end
+
+
return resource.new({
name = "stream_routes",
kind = "stream route",
schema = core.schema.stream_route,
checker = check_conf,
delete_checker = delete_checker,
+ encrypt_conf = encrypt_conf,
unsupported_methods = { "patch" },
list_filter_fields = {
service_id = true,
diff --git a/t/admin/stream-routes.t b/t/admin/stream-routes.t
index 7ce694ccd3..8efc3da31a 100644
--- a/t/admin/stream-routes.t
+++ b/t/admin/stream-routes.t
@@ -654,3 +654,53 @@ passed
GET /t
--- response_body
passed
+
+
+
+=== TEST 18: an inline upstream client key is encrypted at rest
+--- config
+ location /t {
+ content_by_lua_block {
+ local core = require("apisix.core")
+ local etcd = require("apisix.core.etcd")
+ local t = require("lib.test_admin")
+
+ local ssl_cert = t.read_file("t/certs/apisix.crt")
+ local ssl_key = t.read_file("t/certs/apisix.key")
+ local code, body = t.test('/apisix/admin/stream_routes/enc',
+ ngx.HTTP_PUT,
+ core.json.encode({
+ remote_addr = "127.0.0.1",
+ upstream = {
+ nodes = { ["127.0.0.1:8080"] = 1 },
+ type = "roundrobin",
+ scheme = "tls",
+ tls = {
+ client_cert = ssl_cert,
+ client_key = ssl_key,
+ },
+ },
+ })
+ )
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(body)
+ return
+ end
+
+ local res = assert(etcd.get('/stream_routes/enc'))
+ local stored = res.body.node.value.upstream.tls.client_key
+ assert(not core.string.find(stored, "PRIVATE KEY"),
+ "the client key must be encrypted at rest")
+
+ code, body = t.test('/apisix/admin/stream_routes/enc',
ngx.HTTP_GET)
+ assert(code == 200, "the admin API must return the stream route")
+ assert(not core.string.find(body, "PRIVATE KEY"),
+ "the admin API must not return the plaintext client key")
+ ngx.say("encrypted")
+ }
+ }
+--- request
+GET /t
+--- response_body
+encrypted
diff --git a/t/stream-node/upstream-mtls.t b/t/stream-node/upstream-mtls.t
index fd4c753f84..186ea86f7a 100644
--- a/t/stream-node/upstream-mtls.t
+++ b/t/stream-node/upstream-mtls.t
@@ -218,3 +218,50 @@ mmm
hello mtls upstream
--- no_error_log
[error]
+
+
+
+=== TEST 7: set stream_route with an inline upstream carrying the client cert
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin")
+ local json = require("toolkit.json")
+ local ssl_cert = t.read_file("t/certs/mtls_client.crt")
+ local ssl_key = t.read_file("t/certs/mtls_client.key")
+
+ local code, body = t.test('/apisix/admin/stream_routes/1',
+ ngx.HTTP_PUT,
+ json.encode({
+ remote_addr = "127.0.0.1",
+ upstream = {
+ scheme = "tls",
+ type = "roundrobin",
+ nodes = { ["127.0.0.1:8765"] = 1 },
+ tls = {
+ client_cert = ssl_cert,
+ client_key = ssl_key,
+ },
+ },
+ })
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 8: hit route, the encrypted inline client key still completes the
handshake
+--- stream_request
+mmm
+--- stream_response
+hello mtls upstream
+--- no_error_log
+[error]