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

shreemaan-abhishek 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 473a18976 fix(security): encrypt missing secret-like plugin fields at 
rest (#13389)
473a18976 is described below

commit 473a18976a25e20ae346e3aacc4a5ab78ef023aa
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Tue Jun 2 17:03:41 2026 +0800

    fix(security): encrypt missing secret-like plugin fields at rest (#13389)
---
 apisix/plugins/ai-aws-content-moderation.lua |  1 +
 apisix/plugins/azure-functions.lua           |  9 ++-
 apisix/plugins/error-log-logger.lua          |  2 +-
 apisix/plugins/http-logger.lua               |  1 +
 apisix/plugins/kafka-logger.lua              |  3 +-
 apisix/plugins/loggly.lua                    |  1 +
 apisix/plugins/openfunction.lua              |  6 +-
 apisix/plugins/openid-connect.lua            |  3 +-
 apisix/plugins/splunk-hec-logging.lua        |  1 +
 t/plugin/error-log-logger-kafka.t            | 69 +++++++++++++++++++++++
 t/plugin/kafka-logger3.t                     | 76 +++++++++++++++++++++++++
 t/plugin/loggly.t                            | 65 ++++++++++++++++++++++
 t/plugin/openid-connect2.t                   | 83 ++++++++++++++++++++++++++++
 t/plugin/splunk-hec-logging.t                | 70 +++++++++++++++++++++++
 14 files changed, 384 insertions(+), 6 deletions(-)

diff --git a/apisix/plugins/ai-aws-content-moderation.lua 
b/apisix/plugins/ai-aws-content-moderation.lua
index bd3cbf109..0fe62e231 100644
--- a/apisix/plugins/ai-aws-content-moderation.lua
+++ b/apisix/plugins/ai-aws-content-moderation.lua
@@ -69,6 +69,7 @@ local schema = {
             default = 0.5
         }
     },
+    encrypt_fields = { "comprehend.secret_access_key" },
     required = { "comprehend" },
 }
 
diff --git a/apisix/plugins/azure-functions.lua 
b/apisix/plugins/azure-functions.lua
index 0b0e64d4f..9d723306d 100644
--- a/apisix/plugins/azure-functions.lua
+++ b/apisix/plugins/azure-functions.lua
@@ -30,7 +30,8 @@ local metadata_schema = {
     properties = {
         master_apikey = {type = "string", default = ""},
         master_clientid = {type = "string", default = ""}
-    }
+    },
+    encrypt_fields = {"master_apikey"}
 }
 
 local function request_processor(conf, ctx, params)
@@ -57,5 +58,9 @@ local function request_processor(conf, ctx, params)
 end
 
 
-return require("apisix.plugins.serverless.generic-upstream")(plugin_name,
+local plugin = 
require("apisix.plugins.serverless.generic-upstream")(plugin_name,
         plugin_version, priority, request_processor, azure_authz_schema, 
metadata_schema)
+
+plugin.schema.encrypt_fields = {"authorization.apikey"}
+
+return plugin
diff --git a/apisix/plugins/error-log-logger.lua 
b/apisix/plugins/error-log-logger.lua
index 88eca65ca..ee530e14a 100644
--- a/apisix/plugins/error-log-logger.lua
+++ b/apisix/plugins/error-log-logger.lua
@@ -146,7 +146,7 @@ local metadata_schema = {
         -- for compatible with old schema
         {required = {"host", "port"}}
     },
-    encrypt_fields = {"clickhouse.password"},
+    encrypt_fields = {"clickhouse.password", 
"kafka.brokers.sasl_config.password"},
 }
 
 
diff --git a/apisix/plugins/http-logger.lua b/apisix/plugins/http-logger.lua
index 3ee5f238a..cc8481344 100644
--- a/apisix/plugins/http-logger.lua
+++ b/apisix/plugins/http-logger.lua
@@ -56,6 +56,7 @@ local schema = {
                          enum = {"json", "new_line"}},
         ssl_verify = {type = "boolean", default = false},
     },
+    encrypt_fields = {"auth_header"},
     required = {"uri"}
 }
 
diff --git a/apisix/plugins/kafka-logger.lua b/apisix/plugins/kafka-logger.lua
index b93a60531..0a9dcdf8c 100644
--- a/apisix/plugins/kafka-logger.lua
+++ b/apisix/plugins/kafka-logger.lua
@@ -132,7 +132,8 @@ local schema = {
     oneOf = {
         { required = {"broker_list", "kafka_topic"},},
         { required = {"brokers", "kafka_topic"},},
-    }
+    },
+    encrypt_fields = {"brokers.sasl_config.password"},
 }
 
 local metadata_schema = {
diff --git a/apisix/plugins/loggly.lua b/apisix/plugins/loggly.lua
index 18cdc2297..d7d792764 100644
--- a/apisix/plugins/loggly.lua
+++ b/apisix/plugins/loggly.lua
@@ -108,6 +108,7 @@ local schema = {
             additionalProperties = false
         }
     },
+    encrypt_fields = {"customer_token"},
     required = {"customer_token"}
 }
 
diff --git a/apisix/plugins/openfunction.lua b/apisix/plugins/openfunction.lua
index 935d6ebbc..e7ef88390 100644
--- a/apisix/plugins/openfunction.lua
+++ b/apisix/plugins/openfunction.lua
@@ -31,5 +31,9 @@ local function request_processor(conf, ctx, params)
     params.headers = headers
 end
 
-return require("apisix.plugins.serverless.generic-upstream")(plugin_name,
+local plugin = 
require("apisix.plugins.serverless.generic-upstream")(plugin_name,
         plugin_version, priority, request_processor, openfunction_authz_schema)
+
+plugin.schema.encrypt_fields = {"authorization.service_token"}
+
+return plugin
diff --git a/apisix/plugins/openid-connect.lua 
b/apisix/plugins/openid-connect.lua
index 3ecf9d246..4a7bf53d4 100644
--- a/apisix/plugins/openid-connect.lua
+++ b/apisix/plugins/openid-connect.lua
@@ -401,7 +401,8 @@ local schema = {
             default = nil,
         }
     },
-    encrypt_fields = {"client_secret", "client_rsa_private_key"},
+    encrypt_fields = {"client_secret", "client_rsa_private_key",
+                      "session.secret", "session.redis.password"},
     required = {"client_id", "client_secret", "discovery"}
 }
 
diff --git a/apisix/plugins/splunk-hec-logging.lua 
b/apisix/plugins/splunk-hec-logging.lua
index 2024cc9fe..a7b9b2df0 100644
--- a/apisix/plugins/splunk-hec-logging.lua
+++ b/apisix/plugins/splunk-hec-logging.lua
@@ -68,6 +68,7 @@ local schema = {
         },
         log_format = {type = "object"},
     },
+    encrypt_fields = {"endpoint.token"},
     required = { "endpoint" },
 }
 
diff --git a/t/plugin/error-log-logger-kafka.t 
b/t/plugin/error-log-logger-kafka.t
index afae2a558..0ae6a52ac 100644
--- a/t/plugin/error-log-logger-kafka.t
+++ b/t/plugin/error-log-logger-kafka.t
@@ -201,3 +201,72 @@ qr/send data to kafka: .*test5/]
     }
 --- response_body
 passed
+
+
+
+=== TEST 7: data encryption for kafka.brokers[].sasl_config.password (metadata)
+--- yaml_config
+apisix:
+    data_encryption:
+        enable_encrypt_fields: true
+        keyring:
+            - edd1c9f0985e76a2
+--- config
+    location /t {
+        content_by_lua_block {
+            local json = require("toolkit.json")
+            local t = require("lib.test_admin").test
+            local kafka_password = "super-secret-kafka-password"
+            local code, body = 
t('/apisix/admin/plugin_metadata/error-log-logger',
+                 ngx.HTTP_PUT,
+                 json.encode({
+                     kafka = {
+                         brokers = {{
+                             host = "127.0.0.1",
+                             port = 9092,
+                             sasl_config = {
+                                 mechanism = "PLAIN",
+                                 user = "admin",
+                                 password = kafka_password,
+                             }
+                         }},
+                         kafka_topic = "test",
+                     },
+                     level = "ERROR",
+                     inactive_timeout = 1,
+                 })
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.sleep(0.1)
+
+            -- get plugin metadata from admin api, password is decrypted
+            local code, message, res = 
t('/apisix/admin/plugin_metadata/error-log-logger',
+                ngx.HTTP_GET
+            )
+            res = json.decode(res)
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(message)
+                return
+            end
+
+            local plain = res.value.kafka.brokers[1].sasl_config.password
+            ngx.say(plain == kafka_password)
+
+            -- get plugin metadata from etcd, password must be encrypted
+            local etcd = require("apisix.core.etcd")
+            local etcd_res = 
assert(etcd.get('/plugin_metadata/error-log-logger'))
+            local stored = 
etcd_res.body.node.value.kafka.brokers[1].sasl_config.password
+            ngx.say(type(stored) == "string" and stored ~= "" and stored ~= 
kafka_password)
+        }
+    }
+--- response_body
+true
+true
+--- no_error_log
+[alert]
diff --git a/t/plugin/kafka-logger3.t b/t/plugin/kafka-logger3.t
index 82c8248c6..18d02baba 100644
--- a/t/plugin/kafka-logger3.t
+++ b/t/plugin/kafka-logger3.t
@@ -118,3 +118,79 @@ location /t {
 --- error_log
 max pending entries limit exceeded. discarding entry
 --- timeout: 5
+
+
+
+=== TEST 2: data encryption for brokers[].sasl_config.password
+--- yaml_config
+apisix:
+    data_encryption:
+        enable_encrypt_fields: true
+        keyring:
+            - edd1c9f0985e76a2
+--- config
+    location /t {
+        content_by_lua_block {
+            local json = require("toolkit.json")
+            local t = require("lib.test_admin").test
+            local kafka_password = "super-secret-kafka-password"
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 json.encode({
+                     plugins = {
+                         ["kafka-logger"] = {
+                             brokers = {{
+                                 host = "127.0.0.1",
+                                 port = 9092,
+                                 sasl_config = {
+                                     mechanism = "PLAIN",
+                                     user = "admin",
+                                     password = kafka_password,
+                                 }
+                             }},
+                             kafka_topic = "test",
+                             batch_max_size = 1,
+                         }
+                     },
+                     upstream = {
+                         nodes = {["127.0.0.1:1980"] = 1},
+                         type = "roundrobin"
+                     },
+                     uri = "/hello"
+                 })
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.sleep(0.1)
+
+            -- get plugin conf from admin api, password is decrypted
+            local code, message, res = t('/apisix/admin/routes/1',
+                ngx.HTTP_GET
+            )
+            res = json.decode(res)
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(message)
+                return
+            end
+
+            local plain = 
res.value.plugins["kafka-logger"].brokers[1].sasl_config.password
+            ngx.say(plain == kafka_password)
+
+            -- get plugin conf from etcd, password must be encrypted
+            local etcd = require("apisix.core.etcd")
+            local etcd_res = assert(etcd.get('/routes/1'))
+            local stored = etcd_res.body.node.value
+                              
.plugins["kafka-logger"].brokers[1].sasl_config.password
+            ngx.say(type(stored) == "string" and stored ~= "" and stored ~= 
kafka_password)
+        }
+    }
+--- response_body
+true
+true
+--- no_error_log
+[alert]
diff --git a/t/plugin/loggly.t b/t/plugin/loggly.t
index 7c092d792..d19186445 100644
--- a/t/plugin/loggly.t
+++ b/t/plugin/loggly.t
@@ -843,3 +843,68 @@ opentracing
 qr/message received: [ -~]+/
 --- grep_error_log_out eval
 qr/message received: <14>1 [\d\-T:.]+Z \w+ apisix [\d]+ - \[tok\@41058 
tag="apisix"] \{"client":"[\d.]+","host":"\w+","route_id":"1"\}/
+
+
+
+=== TEST 21: data encryption for customer_token
+--- yaml_config
+apisix:
+    data_encryption:
+        enable_encrypt_fields: true
+        keyring:
+            - edd1c9f0985e76a2
+--- config
+    location /t {
+        content_by_lua_block {
+            local json = require("toolkit.json")
+            local t = require("lib.test_admin").test
+            local customer_token = "super-secret-loggly-token"
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 json.encode({
+                     plugins = {
+                         loggly = {
+                             customer_token = customer_token,
+                         }
+                     },
+                     upstream = {
+                         nodes = {["127.0.0.1:1980"] = 1},
+                         type = "roundrobin"
+                     },
+                     uri = "/hello"
+                 })
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.sleep(0.1)
+
+            -- get plugin conf from admin api, customer_token is decrypted
+            local code, message, res = t('/apisix/admin/routes/1',
+                ngx.HTTP_GET
+            )
+            res = json.decode(res)
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(message)
+                return
+            end
+
+            local plain = res.value.plugins.loggly.customer_token
+            ngx.say(plain == customer_token)
+
+            -- get plugin conf from etcd, customer_token must be encrypted
+            local etcd = require("apisix.core.etcd")
+            local etcd_res = assert(etcd.get('/routes/1'))
+            local stored = 
etcd_res.body.node.value.plugins.loggly.customer_token
+            ngx.say(type(stored) == "string" and stored ~= "" and stored ~= 
customer_token)
+        }
+    }
+--- response_body
+true
+true
+--- no_error_log
+[alert]
diff --git a/t/plugin/openid-connect2.t b/t/plugin/openid-connect2.t
index e4760a11d..b7877ac33 100644
--- a/t/plugin/openid-connect2.t
+++ b/t/plugin/openid-connect2.t
@@ -1081,3 +1081,86 @@ true
 true
 --- no_error_log
 [alert]
+
+
+
+=== TEST 21: data encryption for session.redis.password
+--- yaml_config
+apisix:
+    data_encryption:
+        enable_encrypt_fields: true
+        keyring:
+            - edd1c9f0985e76a2
+--- config
+    location /t {
+        content_by_lua_block {
+            local json = require("toolkit.json")
+            local t = require("lib.test_admin").test
+            local redis_password = "super-secret-redis-password"
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 json.encode({
+                     plugins = {
+                         ["openid-connect"] = {
+                             client_id = "kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
+                             client_secret = 
"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa",
+                             discovery = 
"http://127.0.0.1:1980/.well-known/openid-configuration";,
+                             redirect_uri = "https://iresty.com";,
+                             ssl_verify = false,
+                             timeout = 10,
+                             scope = "apisix",
+                             use_pkce = false,
+                             session = {
+                                 secret = "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK",
+                                 storage = "redis",
+                                 redis = {
+                                     host = "127.0.0.1",
+                                     port = 6379,
+                                     password = redis_password,
+                                 }
+                             }
+                         }
+                     },
+                     upstream = {
+                         nodes = {
+                             ["127.0.0.1:1980"] = 1
+                         },
+                         type = "roundrobin"
+                     },
+                     uri = "/hello"
+                 })
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.sleep(0.1)
+
+            -- get plugin conf from admin api, password is decrypted
+            local code, message, res = t('/apisix/admin/routes/1',
+                ngx.HTTP_GET
+            )
+            res = json.decode(res)
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(message)
+                return
+            end
+
+            local plain_password = 
res.value.plugins["openid-connect"].session.redis.password
+            ngx.say(plain_password == redis_password)
+
+            -- get plugin conf from etcd, password must be encrypted (not 
plaintext)
+            local etcd = require("apisix.core.etcd")
+            local etcd_res = assert(etcd.get('/routes/1'))
+            local stored = 
etcd_res.body.node.value.plugins["openid-connect"].session.redis.password
+            ngx.say(type(stored) == "string" and stored ~= "" and stored ~= 
redis_password)
+        }
+    }
+--- response_body
+true
+true
+--- no_error_log
+[alert]
diff --git a/t/plugin/splunk-hec-logging.t b/t/plugin/splunk-hec-logging.t
index 3d6b108f2..4610784af 100644
--- a/t/plugin/splunk-hec-logging.t
+++ b/t/plugin/splunk-hec-logging.t
@@ -463,3 +463,73 @@ qr/.*test batched data.*/
     }
 --- response_body
 passed
+
+
+
+=== TEST 14: data encryption for endpoint.token
+--- yaml_config
+apisix:
+    data_encryption:
+        enable_encrypt_fields: true
+        keyring:
+            - edd1c9f0985e76a2
+--- config
+    location /t {
+        content_by_lua_block {
+            local json = require("toolkit.json")
+            local t = require("lib.test_admin").test
+            local token = "BD274822-96AA-4DA6-90EC-18940FB2414C"
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 json.encode({
+                     plugins = {
+                         ["splunk-hec-logging"] = {
+                             endpoint = {
+                                 uri = 
"http://127.0.0.1:18088/services/collector";,
+                                 token = token,
+                             },
+                             batch_max_size = 1,
+                             inactive_timeout = 1
+                         }
+                     },
+                     upstream = {
+                         nodes = {["127.0.0.1:1980"] = 1},
+                         type = "roundrobin"
+                     },
+                     uri = "/hello"
+                 })
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.sleep(0.1)
+
+            -- get plugin conf from admin api, token is decrypted
+            local code, message, res = t('/apisix/admin/routes/1',
+                ngx.HTTP_GET
+            )
+            res = json.decode(res)
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(message)
+                return
+            end
+
+            local plain = 
res.value.plugins["splunk-hec-logging"].endpoint.token
+            ngx.say(plain == token)
+
+            -- get plugin conf from etcd, token must be encrypted
+            local etcd = require("apisix.core.etcd")
+            local etcd_res = assert(etcd.get('/routes/1'))
+            local stored = 
etcd_res.body.node.value.plugins["splunk-hec-logging"].endpoint.token
+            ngx.say(type(stored) == "string" and stored ~= "" and stored ~= 
token)
+        }
+    }
+--- response_body
+true
+true
+--- no_error_log
+[alert]

Reply via email to