diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua index 52df36f1a049..3ed8d362e37f 100644 --- a/apisix/admin/init.lua +++ b/apisix/admin/init.lua @@ -204,6 +204,8 @@ local function run() if method == "get" and plugin.enable_data_encryption then if seg_res == "consumers" then utils.decrypt_params(plugin.decrypt_conf, data, core.schema.TYPE_CONSUMER) + elseif seg_res == "plugin_metadata" then + utils.decrypt_params(plugin.decrypt_conf, data, core.schema.TYPE_METADATA) else utils.decrypt_params(plugin.decrypt_conf, data) end diff --git a/apisix/admin/plugin_metadata.lua b/apisix/admin/plugin_metadata.lua index 23859c775e24..065b60c4712d 100644 --- a/apisix/admin/plugin_metadata.lua +++ b/apisix/admin/plugin_metadata.lua @@ -18,6 +18,7 @@ local pcall = pcall local require = require local core = require("apisix.core") local utils = require("apisix.admin.utils") +local encrypt_conf = require("apisix.plugin").encrypt_conf local injected_mark = "injected metadata_schema" local _M = { @@ -73,6 +74,8 @@ local function check_conf(plugin_name, conf) ok, err = plugin_object.check_schema(conf, core.schema.TYPE_METADATA) end + encrypt_conf(plugin_name, conf, core.schema.TYPE_METADATA) + if not ok then return nil, {error_msg = "invalid configuration: " .. err} end diff --git a/apisix/admin/utils.lua b/apisix/admin/utils.lua index ee396d0d3670..eee2787f0540 100644 --- a/apisix/admin/utils.lua +++ b/apisix/admin/utils.lua @@ -102,6 +102,12 @@ function _M.decrypt_params(decrypt_func, body, schema_type) decrypt_func(name, conf, schema_type) end end + + -- metadata + if schema_type == core.schema.TYPE_METADATA then + local conf = body.node and body.node.value + decrypt_func(conf.name, conf, schema_type) + end end return _M diff --git a/apisix/plugin.lua b/apisix/plugin.lua index 35169e8a86a7..3b5cecac6ded 100644 --- a/apisix/plugin.lua +++ b/apisix/plugin.lua @@ -21,6 +21,7 @@ local enable_debug = require("apisix.debug").enable_debug local wasm = require("apisix.wasm") local expr = require("resty.expr.v1") local apisix_ssl = require("apisix.ssl") +local re_split = require("ngx.re").split local ngx = ngx local crc32 = ngx.crc32_short local ngx_exit = ngx.exit @@ -844,12 +845,6 @@ local function check_single_plugin_schema(name, plugin_conf, schema_type, skip_d end -check_plugin_metadata = function(item) - return check_single_plugin_schema(item.id, item, - core.schema.TYPE_METADATA, true) -end - - local enable_data_encryption local function enable_gde() if enable_data_encryption == nil then @@ -868,9 +863,15 @@ local function get_plugin_schema_for_gde(name, schema_type) end local plugin_schema = local_plugins_hash and local_plugins_hash[name] + if not plugin_schema then + return nil + end + local schema if schema_type == core.schema.TYPE_CONSUMER then schema = plugin_schema.consumer_schema + elseif schema_type == core.schema.TYPE_METADATA then + schema = plugin_schema.metadata_schema else schema = plugin_schema.schema end @@ -882,17 +883,39 @@ end local function decrypt_conf(name, conf, schema_type) local schema = get_plugin_schema_for_gde(name, schema_type) if not schema then + core.log.warn("failed to get schema for plugin: ", name) return end - for key, props in pairs(schema.properties) do - if props.type == "string" and props.encrypted and conf[key] then - local encrypted, err = apisix_ssl.aes_decrypt_pkey(conf[key], "data_encrypt") - if not encrypted then - core.log.warn("failed to decrypt the conf of plugin [", name, - "] key [", key, "], err: ", err) - else - conf[key] = encrypted + if schema.encrypt_fields and not core.table.isempty(schema.encrypt_fields) then + for _, key in ipairs(schema.encrypt_fields) do + if conf[key] then + local decrypted, err = apisix_ssl.aes_decrypt_pkey(conf[key], "data_encrypt") + if not decrypted then + core.log.warn("failed to decrypt the conf of plugin [", name, + "] key [", key, "], err: ", err) + else + conf[key] = decrypted + end + elseif core.string.find(key, ".") then + -- decrypt fields has indents + local res, err = re_split(key, "\\.", "jo") + if not res then + core.log.warn("failed to split key [", key, "], err: ", err) + return + end + + -- we only support two levels + if conf[res[1]] and conf[res[1]][res[2]] then + local decrypted, err = apisix_ssl.aes_decrypt_pkey( + conf[res[1]][res[2]], "data_encrypt") + if not decrypted then + core.log.warn("failed to decrypt the conf of plugin [", name, + "] key [", key, "], err: ", err) + else + conf[res[1]][res[2]] = decrypted + end + end end end end @@ -903,19 +926,57 @@ _M.decrypt_conf = decrypt_conf local function encrypt_conf(name, conf, schema_type) local schema = get_plugin_schema_for_gde(name, schema_type) if not schema then + core.log.warn("failed to get schema for plugin: ", name) return end - for key, props in pairs(schema.properties) do - if props.type == "string" and props.encrypted and conf[key] then - local encrypted = apisix_ssl.aes_encrypt_pkey(conf[key], "data_encrypt") - conf[key] = encrypted + if schema.encrypt_fields and not core.table.isempty(schema.encrypt_fields) then + for _, key in ipairs(schema.encrypt_fields) do + if conf[key] then + local encrypted, err = apisix_ssl.aes_encrypt_pkey(conf[key], "data_encrypt") + if not encrypted then + core.log.warn("failed to encrypt the conf of plugin [", name, + "] key [", key, "], err: ", err) + else + conf[key] = encrypted + end + elseif core.string.find(key, ".") then + -- encrypt fields has indents + local res, err = re_split(key, "\\.", "jo") + if not res then + core.log.warn("failed to split key [", key, "], err: ", err) + return + end + + -- we only support two levels + if conf[res[1]] and conf[res[1]][res[2]] then + local encrypted, err = apisix_ssl.aes_encrypt_pkey( + conf[res[1]][res[2]], "data_encrypt") + if not encrypted then + core.log.warn("failed to encrypt the conf of plugin [", name, + "] key [", key, "], err: ", err) + else + conf[res[1]][res[2]] = encrypted + end + end + end end end end _M.encrypt_conf = encrypt_conf +check_plugin_metadata = function(item) + local ok, err = check_single_plugin_schema(item.id, item, + core.schema.TYPE_METADATA, true) + if ok and enable_gde() then + decrypt_conf(item.name, item, core.schema.TYPE_METADATA) + end + + return ok, err +end + + local function check_schema(plugins_conf, schema_type, skip_disabled_plugin) for name, plugin_conf in pairs(plugins_conf) do local ok, err = check_single_plugin_schema(name, plugin_conf, diff --git a/apisix/plugins/authz-casdoor.lua b/apisix/plugins/authz-casdoor.lua index 9fd8d8da8f1b..4ed1c92b924e 100644 --- a/apisix/plugins/authz-casdoor.lua +++ b/apisix/plugins/authz-casdoor.lua @@ -32,6 +32,7 @@ local schema = { client_secret = {type = "string"}, callback_url = {type = "string", pattern = "^[^%?]+[^/]$"} }, + encrypt_fields = {"client_secret"}, required = { "callback_url", "endpoint_addr", "client_id", "client_secret" } diff --git a/apisix/plugins/authz-keycloak.lua b/apisix/plugins/authz-keycloak.lua index 336fb69b17ea..f2c02727c0ce 100644 --- a/apisix/plugins/authz-keycloak.lua +++ b/apisix/plugins/authz-keycloak.lua @@ -71,6 +71,7 @@ local schema = { maxLength = 4096 }, }, + encrypt_fields = {"client_secret"}, required = {"client_id"}, allOf = { -- Require discovery or token endpoint. diff --git a/apisix/plugins/basic-auth.lua b/apisix/plugins/basic-auth.lua index 65d96e5c78d4..c91ddee77a44 100644 --- a/apisix/plugins/basic-auth.lua +++ b/apisix/plugins/basic-auth.lua @@ -38,8 +38,9 @@ local consumer_schema = { title = "work with consumer object", properties = { username = { type = "string" }, - password = { type = "string", encrypted = true }, + password = { type = "string" }, }, + encrypt_fields = {"password"}, required = {"username", "password"}, } diff --git a/apisix/plugins/clickhouse-logger.lua b/apisix/plugins/clickhouse-logger.lua index 28404f9ae8ad..70463a752190 100644 --- a/apisix/plugins/clickhouse-logger.lua +++ b/apisix/plugins/clickhouse-logger.lua @@ -36,7 +36,7 @@ local schema = { endpoint_addr = core.schema.uri_def, endpoint_addrs = {items = core.schema.uri_def, type = "array", minItems = 1}, user = {type = "string", default = ""}, - password = {type = "string", default = "", encrypted = true}, + password = {type = "string", default = ""}, database = {type = "string", default = ""}, logtable = {type = "string", default = ""}, timeout = {type = "integer", minimum = 1, default = 3}, @@ -47,6 +47,7 @@ local schema = { {required = {"endpoint_addr", "user", "password", "database", "logtable"}}, {required = {"endpoint_addrs", "user", "password", "database", "logtable"}} }, + encrypt_fields = {"password"}, } diff --git a/apisix/plugins/csrf.lua b/apisix/plugins/csrf.lua index 233fe1d9452c..4ed2ad624aa7 100644 --- a/apisix/plugins/csrf.lua +++ b/apisix/plugins/csrf.lua @@ -44,6 +44,7 @@ local schema = { default = "apisix-csrf-token" } }, + encrypt_fields = {"key"}, required = {"key"} } diff --git a/apisix/plugins/elasticsearch-logger.lua b/apisix/plugins/elasticsearch-logger.lua index 105cbe4d98bb..5b7341319efc 100644 --- a/apisix/plugins/elasticsearch-logger.lua +++ b/apisix/plugins/elasticsearch-logger.lua @@ -67,6 +67,7 @@ local schema = { default = true } }, + encrypt_fields = {"auth.password"}, required = { "endpoint_addr", "field" }, } diff --git a/apisix/plugins/error-log-logger.lua b/apisix/plugins/error-log-logger.lua index 5aa7a7418cfd..d847ca1ce852 100644 --- a/apisix/plugins/error-log-logger.lua +++ b/apisix/plugins/error-log-logger.lua @@ -83,7 +83,8 @@ local metadata_schema = { {required = {"clickhouse"}}, -- for compatible with old schema {required = {"host", "port"}} - } + }, + encrypt_fields = {"clickhouse.password"}, } diff --git a/apisix/plugins/google-cloud-logging.lua b/apisix/plugins/google-cloud-logging.lua index 607856759ec8..a07156716728 100644 --- a/apisix/plugins/google-cloud-logging.lua +++ b/apisix/plugins/google-cloud-logging.lua @@ -92,6 +92,7 @@ local schema = { { required = { "auth_config" } }, { required = { "auth_file" } }, }, + encrypt_fields = {"auth_config.private_key"}, } diff --git a/apisix/plugins/hmac-auth.lua b/apisix/plugins/hmac-auth.lua index c03e5ce82438..94916e975216 100644 --- a/apisix/plugins/hmac-auth.lua +++ b/apisix/plugins/hmac-auth.lua @@ -90,6 +90,7 @@ local consumer_schema = { default = MAX_REQ_BODY, }, }, + encrypt_fields = {"secret_key"}, required = {"access_key", "secret_key"}, } diff --git a/apisix/plugins/jwt-auth.lua b/apisix/plugins/jwt-auth.lua index 1215fedb9c9b..96c743e1ba07 100644 --- a/apisix/plugins/jwt-auth.lua +++ b/apisix/plugins/jwt-auth.lua @@ -118,6 +118,7 @@ local consumer_schema = { } } }, + encrypt_fields = {"secret", "private_key"}, required = {"key"}, } diff --git a/apisix/plugins/kafka-proxy.lua b/apisix/plugins/kafka-proxy.lua index b6c666a53a30..0882692dd2e5 100644 --- a/apisix/plugins/kafka-proxy.lua +++ b/apisix/plugins/kafka-proxy.lua @@ -33,6 +33,7 @@ local schema = { required = {"username", "password"}, }, }, + encrypt_fields = {"sasl.password"}, } diff --git a/apisix/plugins/key-auth.lua b/apisix/plugins/key-auth.lua index 63e41a084d34..f8cfddae0cf8 100644 --- a/apisix/plugins/key-auth.lua +++ b/apisix/plugins/key-auth.lua @@ -40,8 +40,9 @@ local schema = { local consumer_schema = { type = "object", properties = { - key = { type = "string", encrypted = true }, + key = { type = "string" }, }, + encrypt_fields = {"key"}, required = {"key"}, } diff --git a/apisix/plugins/openid-connect.lua b/apisix/plugins/openid-connect.lua index d45b4e7570d9..163707f1db6d 100644 --- a/apisix/plugins/openid-connect.lua +++ b/apisix/plugins/openid-connect.lua @@ -124,6 +124,7 @@ local schema = { default = false } }, + encrypt_fields = {"client_secret"}, required = {"client_id", "client_secret", "discovery"} } diff --git a/apisix/plugins/rocketmq-logger.lua b/apisix/plugins/rocketmq-logger.lua index 447960ba689c..7ca61390cf70 100644 --- a/apisix/plugins/rocketmq-logger.lua +++ b/apisix/plugins/rocketmq-logger.lua @@ -69,6 +69,7 @@ local schema = { } }, }, + encrypt_fields = {"secret_key"}, required = {"nameserver_list", "topic"} } diff --git a/apisix/plugins/sls-logger.lua b/apisix/plugins/sls-logger.lua index 290bf11917bb..89fc952baa56 100644 --- a/apisix/plugins/sls-logger.lua +++ b/apisix/plugins/sls-logger.lua @@ -42,6 +42,7 @@ local schema = { access_key_id = {type = "string"}, access_key_secret = {type ="string"} }, + encrypt_fields = {"access_key_secret"}, required = {"host", "port", "project", "logstore", "access_key_id", "access_key_secret"} } diff --git a/apisix/plugins/tencent-cloud-cls.lua b/apisix/plugins/tencent-cloud-cls.lua index b0726e607eae..d9b032b01b35 100644 --- a/apisix/plugins/tencent-cloud-cls.lua +++ b/apisix/plugins/tencent-cloud-cls.lua @@ -44,6 +44,7 @@ local schema = { include_resp_body = { type = "boolean", default = false }, global_tag = { type = "object" }, }, + encrypt_fields = {"secret_key"}, required = { "cls_host", "cls_topic", "secret_id", "secret_key" } } diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 33af44564590..e1923ec56ec7 100755 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -123,7 +123,7 @@ apisix: # ip: 127.0.0.1 # port: 9090 disable_sync_configuration_during_start: false # safe exit. Remove this once the feature is stable - data_encryption: # add `encrypted = true` in plugin schema to enable encryption + data_encryption: # add `encrypt_fields = { $field },` in plugin schema to enable encryption enable: false # if not set, the default value is `false`. keyring: - qeddd145sfvddff3 # If not set, will save origin value into etcd. diff --git a/docs/en/latest/plugin-develop.md b/docs/en/latest/plugin-develop.md index c55c47bf1186..a7aa4c6348bb 100644 --- a/docs/en/latest/plugin-develop.md +++ b/docs/en/latest/plugin-develop.md @@ -300,13 +300,24 @@ Specify the parameters to be stored encrypted. (Requires APISIX version >= 3.1.0 Some plugins require parameters to be stored encrypted, such as the `password` parameter of the `basic-auth` plugin. This plugin needs to specify in the `schema` which parameters need to be stored encrypted. ```lua -password = { type = "string", encrypted = true }, +encrypt_fields = {"password"} ``` -Parameters can be stored encrypted by specifying `encrypted = true` in the `schema`. APISIX will provide the following functionality. +If it is a nested parameter, such as the `clickhouse.password` parameter of the `error-log-logger` plugin, it needs to be separated by `.`: -- When adding and updating resources via the `Admin API`, APISIX automatically encrypts parameters with `encrypted = true` and stores them in etcd -- When fetching resources via the `Admin API` and when running the plugin, APISIX automatically decrypts the `encrypted = true` parameter +```lua +encrypt_fields = {"clickhouse.password"} +``` + +Currently not supported yet: + +1. more than two levels of nesting +2. fields in arrays + +Parameters can be stored encrypted by specifying `encrypt_fields = {"password"}` in the `schema`. APISIX will provide the following functionality. + +- When adding and updating resources via the `Admin API`, APISIX automatically encrypts the parameters declared in `encrypt_fields` and stores them in etcd +- When fetching resources via the `Admin API` and when running the plugin, APISIX automatically decrypts the parameters declared in `encrypt_fields` How to enable this feature? @@ -321,7 +332,7 @@ apisix: - qeddd145sfvddff4 ``` -APISIX will try to decrypt the data with keys in the order of the keys in the keyring (only for parameters declared `encrypted = true`). If the decryption fails, the next key will be tried until the decryption succeeds. +APISIX will try to decrypt the data with keys in the order of the keys in the keyring (only for parameters declared in `encrypt_fields`). If the decryption fails, the next key will be tried until the decryption succeeds. If none of the keys in `keyring` can decrypt the data, the original data is used. diff --git a/docs/en/latest/plugins/authz-casdoor.md b/docs/en/latest/plugins/authz-casdoor.md index fc8c92f09044..f1a71be9e588 100644 --- a/docs/en/latest/plugins/authz-casdoor.md +++ b/docs/en/latest/plugins/authz-casdoor.md @@ -40,6 +40,8 @@ The `authz-casdoor` Plugin can be used to add centralized authentication with [C | client_secret | string | True | Client secret in Casdoor. | | callback_url | string | True | Callback URL used to receive state and code. | +NOTE: `encrypt_fields = {"client_secret"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + :::info IMPORTANT `endpoint_addr` and `callback_url` should not end with '/'. diff --git a/docs/en/latest/plugins/authz-keycloak.md b/docs/en/latest/plugins/authz-keycloak.md index 70a149caf01b..d04196d06fc0 100644 --- a/docs/en/latest/plugins/authz-keycloak.md +++ b/docs/en/latest/plugins/authz-keycloak.md @@ -66,6 +66,8 @@ Refer to [Authorization Services Guide](https://www.keycloak.org/docs/latest/aut | access_denied_redirect_uri | string | False | | [1, 2048] | URI to redirect the user to instead of returning an error message like `"error_description":"not_authorized"`. | | password_grant_token_generation_incoming_uri | string | False | | /api/token | Set this to generate token using the password grant type. The Plugin will compare incoming request URI to this value. | +NOTE: `encrypt_fields = {"client_secret"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + ### Discovery and endpoints It is recommended to use the `discovery` attribute as the `authz-keycloak` Plugin can discover the Keycloak API endpoints from it. diff --git a/docs/en/latest/plugins/basic-auth.md b/docs/en/latest/plugins/basic-auth.md index 25c574c9c88b..8447a4fce5d4 100644 --- a/docs/en/latest/plugins/basic-auth.md +++ b/docs/en/latest/plugins/basic-auth.md @@ -42,7 +42,7 @@ For Consumer: | username | string | True | Unique username for a Consumer. If multiple Consumers use the same `username`, a request matching exception is raised. | | password | string | True | Password of the user. | -NOTE: The schema for `password` also defines `encrypted = true`, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). +NOTE: `encrypt_fields = {"password"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). For Route: diff --git a/docs/en/latest/plugins/clickhouse-logger.md b/docs/en/latest/plugins/clickhouse-logger.md index 9de95ccf1c9d..465ebb945ca2 100644 --- a/docs/en/latest/plugins/clickhouse-logger.md +++ b/docs/en/latest/plugins/clickhouse-logger.md @@ -45,9 +45,9 @@ The `clickhouse-logger` Plugin is used to push logs to [ClickHouse](https://clic | name | string | False | "clickhouse logger" | | Unique identifier for the logger. | | ssl_verify | boolean | False | true | [true,false] | When set to `true`, verifies SSL. | -This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. +NOTE: `encrypt_fields = {"password"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). -NOTE: The schema for `password` also defines `encrypted = true`, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). +This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. ## Metadata diff --git a/docs/en/latest/plugins/csrf.md b/docs/en/latest/plugins/csrf.md index b3cd5cb7a866..a5884a5bef33 100644 --- a/docs/en/latest/plugins/csrf.md +++ b/docs/en/latest/plugins/csrf.md @@ -41,6 +41,8 @@ This Plugin considers the `GET`, `HEAD` and `OPTIONS` methods to be safe operati | expires | number | False | `7200` | Expiration time in seconds of the CSRF cookie. Set to `0` to skip checking expiration time. | | key | string | True | | Secret key used to encrypt the cookie. | +NOTE: `encrypt_fields = {"key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + ## Enabling the Plugin The example below shows how you can enable the Plugin on a specific Route: diff --git a/docs/en/latest/plugins/elasticsearch-logger.md b/docs/en/latest/plugins/elasticsearch-logger.md index 51deead8649c..739641d57801 100644 --- a/docs/en/latest/plugins/elasticsearch-logger.md +++ b/docs/en/latest/plugins/elasticsearch-logger.md @@ -47,6 +47,8 @@ When the Plugin is enabled, APISIX will serialize the request context informatio | ssl_verify | boolean | False | true | When set to `true` enables SSL verification as per [OpenResty docs](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake). | | timeout | integer | False | 10 | Elasticsearch send data timeout in seconds. | +NOTE: `encrypt_fields = {"auth.password"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. ## Enabling the Plugin diff --git a/docs/en/latest/plugins/error-log-logger.md b/docs/en/latest/plugins/error-log-logger.md index a37a7a5ffbbd..63b1be1c727b 100644 --- a/docs/en/latest/plugins/error-log-logger.md +++ b/docs/en/latest/plugins/error-log-logger.md @@ -52,6 +52,8 @@ It might take some time to receive the log data. It will be automatically sent a | keepalive | integer | False | 30 | [1,...] | Time in seconds to keep the connection alive after sending data. | | level | string | False | WARN | ["STDERR", "EMERG", "ALERT", "CRIT", "ERR", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG"] | Log level to filter the error logs. `ERR` is same as `ERROR`. | +NOTE: `encrypt_fields = {"clickhouse.password"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. ## Enabling the Plugin diff --git a/docs/en/latest/plugins/google-cloud-logging.md b/docs/en/latest/plugins/google-cloud-logging.md index d243aca87987..d04d939cad07 100644 --- a/docs/en/latest/plugins/google-cloud-logging.md +++ b/docs/en/latest/plugins/google-cloud-logging.md @@ -47,6 +47,8 @@ This plugin also allows to push logs as a batch to your Google Cloud Logging Ser | resource | False | {"type": "global"} | Google monitor resource. See [MonitoredResource](https://cloud.google.com/logging/docs/reference/v2/rest/v2/MonitoredResource) for more details. | | log_id | False | apisix.apache.org%2Flogs | Google Cloud logging ID. See [LogEntry](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry) for details. | +NOTE: `encrypt_fields = {"auth_config.private_key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. ## Enabling the Plugin diff --git a/docs/en/latest/plugins/hmac-auth.md b/docs/en/latest/plugins/hmac-auth.md index c43d24a615eb..5aaef2eb3247 100644 --- a/docs/en/latest/plugins/hmac-auth.md +++ b/docs/en/latest/plugins/hmac-auth.md @@ -47,6 +47,8 @@ This Plugin works with a [Consumer](../terminology/consumer.md) object and a con | validate_request_body | boolean | False | false | [ true, false ] | When set to `true`, validates the request body. | | max_req_body | integer | False | 512 * 1024 | | Max size of the request body to allow. | +NOTE: `encrypt_fields = {"secret_key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + ## Enabling the Plugin First we enable the Plugin on a Consumer object as shown below: diff --git a/docs/en/latest/plugins/jwt-auth.md b/docs/en/latest/plugins/jwt-auth.md index fffb01846119..124ae38577d1 100644 --- a/docs/en/latest/plugins/jwt-auth.md +++ b/docs/en/latest/plugins/jwt-auth.md @@ -51,6 +51,8 @@ For Consumer: | vault | object | False | | | Set to true to use Vault for storing and retrieving secret (secret for HS256/HS512 or public_key and private_key for RS256/ES256). By default, the Vault path is `kv/apisix/consumer//jwt-auth`. | | lifetime_grace_period | integer | False | 0 | [0,...] | Define the leeway in seconds to account for clock skew between the server that generated the jwt and the server validating it. Value should be zero (0) or a positive integer. | +NOTE: `encrypt_fields = {"secret", "private_key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + :::info IMPORTANT To enable Vault integration, you have to first update your configuration file (`conf/config.yaml`) with your Vault server configuration, host address and access token. diff --git a/docs/en/latest/plugins/kafka-proxy.md b/docs/en/latest/plugins/kafka-proxy.md index d0377cd0f9fa..d7ca53ed7e11 100644 --- a/docs/en/latest/plugins/kafka-proxy.md +++ b/docs/en/latest/plugins/kafka-proxy.md @@ -38,6 +38,8 @@ The `kafka-proxy` plugin can be used to configure advanced parameters for the ka | sasl.username | string | required | | | SASL/PLAIN authentication username | | sasl.password | string | required | | | SASL/PLAIN authentication password | +NOTE: `encrypt_fields = {"sasl.password"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + :::note If SASL authentication is enabled, the `sasl.username` and `sasl.password` must be set. The current SASL authentication only supports PLAIN mode, which is the username password login method. diff --git a/docs/en/latest/plugins/key-auth.md b/docs/en/latest/plugins/key-auth.md index b188cbc27efa..ebac702bbb83 100644 --- a/docs/en/latest/plugins/key-auth.md +++ b/docs/en/latest/plugins/key-auth.md @@ -41,7 +41,7 @@ For Consumer: |------|--------|-------------|----------------------------| | key | string | required | Unique key for a Consumer. | -NOTE: The schema for `key` also defines `encrypted = true`, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). +NOTE: `encrypt_fields = {"key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). For Route: diff --git a/docs/en/latest/plugins/openid-connect.md b/docs/en/latest/plugins/openid-connect.md index 965cf7474bde..e44e0f6229e8 100644 --- a/docs/en/latest/plugins/openid-connect.md +++ b/docs/en/latest/plugins/openid-connect.md @@ -61,6 +61,8 @@ description: OpenID Connect allows the client to obtain user information from th | session | object | False | | | When bearer_only is set to false, openid-connect will use Authorization Code flow to authenticate on the IDP, so you need to set the session-related configuration. | | session.secret | string | True | Automatic generation | 16 or more characters | The key used for session encrypt and HMAC operation. | +NOTE: `encrypt_fields = {"client_secret"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + ## Scenarios :::tip diff --git a/docs/en/latest/plugins/rocketmq-logger.md b/docs/en/latest/plugins/rocketmq-logger.md index 557f8ce5572c..003724b8163e 100644 --- a/docs/en/latest/plugins/rocketmq-logger.md +++ b/docs/en/latest/plugins/rocketmq-logger.md @@ -51,6 +51,8 @@ It might take some time to receive the log data. It will be automatically sent a | include_resp_body | boolean | False | false | [false, true] | When set to `true` includes the response body in the log. | | include_resp_body_expr | array | False | | | Filter for when the `include_resp_body` attribute is set to `true`. Response body is only logged when the expression set here evaluates to `true`. See [lua-resty-expr](https://github.com/api7/lua-resty-expr) for more. | +NOTE: `encrypt_fields = {"secret_key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. :::info IMPORTANT diff --git a/docs/en/latest/plugins/sls-logger.md b/docs/en/latest/plugins/sls-logger.md index a823b60978e3..53ea083bafa9 100644 --- a/docs/en/latest/plugins/sls-logger.md +++ b/docs/en/latest/plugins/sls-logger.md @@ -47,6 +47,8 @@ It might take some time to receive the log data. It will be automatically sent a | include_req_body | True | When set to `true`, includes the request body in the log. | | name | False | Unique identifier for the batch processor. | +NOTE: `encrypt_fields = {"access_key_secret"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. ## Metadata diff --git a/docs/en/latest/plugins/tencent-cloud-cls.md b/docs/en/latest/plugins/tencent-cloud-cls.md index fcdc6d0f5f0c..fb321010004f 100644 --- a/docs/en/latest/plugins/tencent-cloud-cls.md +++ b/docs/en/latest/plugins/tencent-cloud-cls.md @@ -45,6 +45,8 @@ The `tencent-cloud-cls` Plugin uses [TencentCloud CLS](https://cloud.tencent.com | include_resp_body | boolean | No | false | [false, true] | When set to `true` includes the response body in the log. | | global_tag | object | No | | | kv pairs in JSON,send with each log. | +NOTE: `encrypt_fields = {"secret_key"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). + This Plugin supports using batch processors to aggregate and process entries (logs/data) in a batch. This avoids the need for frequently submitting the data. The batch processor submits data every `5` seconds or when the data in the queue reaches `1000`. See [Batch Processor](../batch-processor.md#configuration) for more information or setting your custom configuration. ## Metadata diff --git a/docs/zh/latest/plugin-develop.md b/docs/zh/latest/plugin-develop.md index 6012c323c954..f40363002626 100644 --- a/docs/zh/latest/plugin-develop.md +++ b/docs/zh/latest/plugin-develop.md @@ -280,13 +280,24 @@ end 有些插件需要将参数加密存储,比如 `basic-auth` 插件的 `password` 参数。这个插件需要在 `schema` 中指定哪些参数需要被加密存储。 ```lua -password = { type = "string", encrypted = true }, +encrypt_fields = {"password"} ``` -通过在 `schema` 中指定 `encrypted = true`,可以将参数加密存储。APISIX 将提供以下功能: +如果是嵌套的参数,比如 `error-log-logger` 插件的 `clickhouse.password` 参数,需要用 `.` 来分隔: -- 通过 `Admin API` 来新增和更新资源时,对于 `encrypted = true` 的参数,APISIX 会自动加密存储在 etcd 中 -- 通过 `Admin API` 来获取资源时,以及在运行插件时,对于 `encrypted = true` 的参数,APISIX 会自动解密 +```lua +encrypt_fields = {"clickhouse.password"} +``` + +目前还不支持: + +1. 两层以上的嵌套 +2. 数组中的字段 + +通过在 `schema` 中指定 `encrypt_fields = {"password"}`,可以将参数加密存储。APISIX 将提供以下功能: + +- 通过 `Admin API` 来新增和更新资源时,对于 `encrypt_fields` 中声明的参数,APISIX 会自动加密存储在 etcd 中 +- 通过 `Admin API` 来获取资源时,以及在运行插件时,对于 `encrypt_fields` 中声明的参数,APISIX 会自动解密 如何开启该功能? @@ -301,7 +312,7 @@ apisix: - qeddd145sfvddff4 ``` -`keyring` 是一个数组,可以指定多个 key,APISIX 会按照 keyring 中 key 的顺序,依次尝试用 key 来解密数据(只对声明 `encrypted = true` 的参数)。如果解密失败,会尝试下一个 key,直到解密成功。 +`keyring` 是一个数组,可以指定多个 key,APISIX 会按照 keyring 中 key 的顺序,依次尝试用 key 来解密数据(只对在 `encrypt_fields` 声明的参数)。如果解密失败,会尝试下一个 key,直到解密成功。 如果 `keyring` 中的 key 都无法解密数据,则使用原始数据。 diff --git a/docs/zh/latest/plugins/authz-casdoor.md b/docs/zh/latest/plugins/authz-casdoor.md index a0ed3d9cccb0..1ad294805dfe 100644 --- a/docs/zh/latest/plugins/authz-casdoor.md +++ b/docs/zh/latest/plugins/authz-casdoor.md @@ -40,6 +40,8 @@ description: 本篇文档介绍了 Apache APISIX auth-casdoor 插件的相关信 | client_secret | string | 是 | Casdoor 的客户端密钥。 | | callback_url | string | 是 | 用于接收 code 与 state 的回调地址。 | +注意:schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + :::info IMPORTANT 指定 `endpoint_addr` 和 `callback_url` 属性时不要以 “/” 来结尾。 diff --git a/docs/zh/latest/plugins/authz-keycloak.md b/docs/zh/latest/plugins/authz-keycloak.md index 6bc5c7b9691a..811baaa3bdb9 100644 --- a/docs/zh/latest/plugins/authz-keycloak.md +++ b/docs/zh/latest/plugins/authz-keycloak.md @@ -66,6 +66,8 @@ description: 本文介绍了关于 Apache APISIX `authz-keycloak` 插件的基 | access_denied_redirect_uri | string | 否 | | [1, 2048] | 需要将用户重定向到的 URI,而不是返回类似 `"error_description":"not_authorized"` 这样的错误消息。 | | password_grant_token_generation_incoming_uri | string | 否 | | /api/token | 将此设置为使用密码授予类型生成令牌。该插件会将传入的请求 URI 与此值进行比较。 | +注意:schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 除上述释义外,还有以下需要注意的点: - Discovery and endpoints diff --git a/docs/zh/latest/plugins/basic-auth.md b/docs/zh/latest/plugins/basic-auth.md index f19dcab573a6..ac8035152c73 100644 --- a/docs/zh/latest/plugins/basic-auth.md +++ b/docs/zh/latest/plugins/basic-auth.md @@ -42,7 +42,7 @@ Consumer 端: | username | string | 是 | Consumer 的用户名并且该用户名是唯一,如果多个 Consumer 使用了相同的 `username`,将会出现请求匹配异常。| | password | string | 是 | 用户的密码。 | -注意:`password` 的 schema 中还定义了 `encrypted = true`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 +注意:schema 中还定义了 `encrypt_fields = {"password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 Route 端: diff --git a/docs/zh/latest/plugins/clickhouse-logger.md b/docs/zh/latest/plugins/clickhouse-logger.md index dc35db7e9d81..aed09ca71f6d 100644 --- a/docs/zh/latest/plugins/clickhouse-logger.md +++ b/docs/zh/latest/plugins/clickhouse-logger.md @@ -45,9 +45,9 @@ description: 本文介绍了 API 网关 Apache APISIX 如何使用 clickhouse-lo | name | string | 否 | "clickhouse logger" | | 标识 logger 的唯一标识符。 | | ssl_verify | boolean | 否 | true | [true,false] | 当设置为 `true` 时,验证证书。 | -该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)。 +注意:schema 中还定义了 `encrypt_fields = {"password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 -注意:`password` 的 schema 中还定义了 `encrypted = true`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 +该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)。 ## 配置插件元数据 diff --git a/docs/zh/latest/plugins/csrf.md b/docs/zh/latest/plugins/csrf.md index 5db88f8a0fa2..86fb54579869 100644 --- a/docs/zh/latest/plugins/csrf.md +++ b/docs/zh/latest/plugins/csrf.md @@ -43,6 +43,8 @@ description: CSRF 插件基于 Double Submit Cookie 的方式,帮助用户阻 | expires | number | 否 | `7200` | | CSRF Cookie 的过期时间,单位为秒。当设置为 `0` 时,会忽略 CSRF Cookie 过期时间检查。| | key | string | 是 | | | 加密 Token 的密钥。 | +注意:schema 中还定义了 `encrypt_fields = {"key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + ## 启用插件 以下示例展示了如何在指定路由上启用并配置 `csrf` 插件: diff --git a/docs/zh/latest/plugins/elasticsearch-logger.md b/docs/zh/latest/plugins/elasticsearch-logger.md index 82e035d05720..4b25d3077955 100644 --- a/docs/zh/latest/plugins/elasticsearch-logger.md +++ b/docs/zh/latest/plugins/elasticsearch-logger.md @@ -48,6 +48,8 @@ description: 本文介绍了 API 网关 Apache APISIX 的 elasticsearch-logger | ssl_verify | boolean | 否 | true | 当设置为 `true` 时则启用 SSL 验证。更多信息请参考 [lua-nginx-module](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake)。 | | timeout | integer | 否 | 10 | 发送给 Elasticsearch 请求超时时间。 | +注意:schema 中还定义了 `encrypt_fields = {"auth.password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 本插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。 ## 启用插件 diff --git a/docs/zh/latest/plugins/error-log-logger.md b/docs/zh/latest/plugins/error-log-logger.md index 02c717e6f2c1..daee4c521f5a 100644 --- a/docs/zh/latest/plugins/error-log-logger.md +++ b/docs/zh/latest/plugins/error-log-logger.md @@ -51,6 +51,8 @@ description: API 网关 Apache APISIX error-log-logger 插件用于将 APISIX | keepalive | integer | 否 | 30 | [1,...] | 复用连接时,连接保持的时间,以秒为单位。 | | level | string | 否 | WARN | | 进行错误日志筛选的级别,默认为 `WARN`,取值 ["STDERR", "EMERG", "ALERT", "CRIT", "ERR", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG"],其中 `ERR` 与 `ERROR` 级别一致。 | +注意:schema 中还定义了 `encrypt_fields = {"clickhouse.password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 本插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。 ## 启用插件 diff --git a/docs/zh/latest/plugins/google-cloud-logging.md b/docs/zh/latest/plugins/google-cloud-logging.md index 067557c29973..7a62b8ac991b 100644 --- a/docs/zh/latest/plugins/google-cloud-logging.md +++ b/docs/zh/latest/plugins/google-cloud-logging.md @@ -47,6 +47,8 @@ description: API 网关 Apache APISIX 的 google-cloud-logging 插件可用于 | resource | 否 | {"type": "global"} | 谷歌监控资源,请参考 [MonitoredResource](https://cloud.google.com/logging/docs/reference/v2/rest/v2/MonitoredResource)。 | | log_id | 否 | apisix.apache.org%2Flogs | 谷歌日志 ID,请参考 [LogEntry](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry)。 | +注意:schema 中还定义了 `encrypt_fields = {"auth_config.private_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 该插件支持使用批处理器来聚合并批量处理条目(日志和数据)。这样可以避免该插件频繁地提交数据。默认情况下每 `5` 秒钟或队列中的数据达到 `1000` 条时,批处理器会自动提交数据,如需了解更多信息或自定义配置,请参考 [Batch Processor](../batch-processor.md#配置)。 ## 启用插件 diff --git a/docs/zh/latest/plugins/hmac-auth.md b/docs/zh/latest/plugins/hmac-auth.md index 8621611d97c2..54c1d04548d4 100644 --- a/docs/zh/latest/plugins/hmac-auth.md +++ b/docs/zh/latest/plugins/hmac-auth.md @@ -47,6 +47,8 @@ description: 本文介绍了关于 Apache APISIX `hmac-auth` 插件的基本信 | validate_request_body | boolean | 否 | false | [ true, false ] | 当设置为 `true` 时,对请求 body 做签名校验。 | | max_req_body | integer | 否 | 512 * 1024 | | 最大允许的 body 大小。 | +注意:schema 中还定义了 `encrypt_fields = {"secret_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + ## 启用插件 首先,我们需要在 Consumer 中启用该插件,如下所示: diff --git a/docs/zh/latest/plugins/jwt-auth.md b/docs/zh/latest/plugins/jwt-auth.md index b4582f64263b..0f7196c5b8e1 100644 --- a/docs/zh/latest/plugins/jwt-auth.md +++ b/docs/zh/latest/plugins/jwt-auth.md @@ -51,6 +51,8 @@ Consumer 端: | vault | object | 否 | | | 是否使用 Vault 作为存储和检索密钥(HS256/HS512 的密钥或 RS256/ES256 的公钥和私钥)的方式。该插件默认使用 `kv/apisix/consumer//jwt-auth` 路径进行密钥检索。 | | lifetime_grace_period | integer | 否 | 0 | [0,...] | 定义生成 JWT 的服务器和验证 JWT 的服务器之间的时钟偏移。该值应该是零(0)或一个正整数。 | +注意:schema 中还定义了 `encrypt_fields = {"secret", "private_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + :::info IMPORTANT 如果你想要启用 Vault 集成,你需要在 [config.yaml](https://github.com/apache/apisix/blob/master/conf/config.yaml) 配置文件中,更新你的 Vault 服务器配置、主机地址和访问令牌。 diff --git a/docs/zh/latest/plugins/key-auth.md b/docs/zh/latest/plugins/key-auth.md index 8031854e7084..23817fea09c2 100644 --- a/docs/zh/latest/plugins/key-auth.md +++ b/docs/zh/latest/plugins/key-auth.md @@ -41,7 +41,7 @@ Consumer 端: | ---- | ------ | ------ | ------------------------------------------------------------------------------------------------------------- | | key | string | 是 | 不同的 Consumer 应有不同的 `key`,它应当是唯一的。如果多个 Consumer 使用了相同的 `key`,将会出现请求匹配异常。 | -注意:`key` 的 schema 中还定义了 `encrypted = true`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 +注意:schema 中还定义了 `encrypt_fields = {"key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 Router 端: diff --git a/docs/zh/latest/plugins/openid-connect.md b/docs/zh/latest/plugins/openid-connect.md index 5d5a11c30af3..13a6274cecfe 100644 --- a/docs/zh/latest/plugins/openid-connect.md +++ b/docs/zh/latest/plugins/openid-connect.md @@ -61,6 +61,8 @@ description: OpenID Connect(OIDC)是基于 OAuth 2.0 的身份认证协议 | session | object | 否 | | | 当设置 bearer_only 为 false 时,openid-connect 插件将使用 Authorization Code 在 IDP 上进行认证,因此你必须设置 session 相关设置。 | | session.secret | string | 是 | 自动生成 | 16 个以上字符 | 用于 session 加密和 HMAC 计算的密钥。 | +注意:schema 中还定义了 `encrypt_fields = {"client_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + ## 使用场景 :::tip diff --git a/docs/zh/latest/plugins/rocketmq-logger.md b/docs/zh/latest/plugins/rocketmq-logger.md index 235bc0f1c23b..5e952837d0f2 100644 --- a/docs/zh/latest/plugins/rocketmq-logger.md +++ b/docs/zh/latest/plugins/rocketmq-logger.md @@ -50,6 +50,8 @@ description: API 网关 Apache APISIX 的 rocketmq-logger 插件用于将日志 | include_resp_body | boolean | 否 | false | [false, true] | 当设置为 `true` 时,包含响应体。 | | include_resp_body_expr | array | 否 | | | 当 `include_resp_body` 属性设置为 `true` 时进行过滤响应体,并且只有当此处设置的表达式计算结果为 `true` 时,才会记录响应体。更多信息,请参考 [lua-resty-expr](https://github.com/api7/lua-resty-expr)。 | +注意:schema 中还定义了 `encrypt_fields = {"secret_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)。 :::tip 提示 diff --git a/docs/zh/latest/plugins/sls-logger.md b/docs/zh/latest/plugins/sls-logger.md index 3b2e737a074c..1162426f3100 100644 --- a/docs/zh/latest/plugins/sls-logger.md +++ b/docs/zh/latest/plugins/sls-logger.md @@ -44,6 +44,8 @@ title: sls-logger | include_req_body | 可选的 | 是否包含请求体。| |name| 可选的 | 批处理名字。| +注意:schema 中还定义了 `encrypt_fields = {"access_key_secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 本插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认设置情况下批处理器会每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解或自定义批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置) 配置部分。 ## 插件元数据设置 diff --git a/docs/zh/latest/plugins/tencent-cloud-cls.md b/docs/zh/latest/plugins/tencent-cloud-cls.md index 32a2b9e5c5e1..a947910578de 100644 --- a/docs/zh/latest/plugins/tencent-cloud-cls.md +++ b/docs/zh/latest/plugins/tencent-cloud-cls.md @@ -45,6 +45,8 @@ description: API 网关 Apache APISIX tencent-cloud-cls 插件可用于将日志 | include_resp_body | boolean | 否 | false | [false, true]| 当设置为 `true` 时,日志中将包含响应体。 | | global_tag | object | 否 | | | kv 形式的 JSON 数据,可以写入每一条日志,便于在 CLS 中检索。 | +注意:schema 中还定义了 `encrypt_fields = {"secret_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 + 该插件支持使用批处理器来聚合并批量处理条目(日志/数据)。这样可以避免插件频繁地提交数据,默认情况下批处理器每 `5` 秒钟或队列中的数据达到 `1000` 条时提交数据,如需了解批处理器相关参数设置,请参考 [Batch-Processor](../batch-processor.md#配置)。 ## 插件元数据 diff --git a/t/admin/plugins.t b/t/admin/plugins.t index 5edb3c427425..9791278e22d6 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -339,7 +339,7 @@ qr/\[\{"name":"wolf-rbac","priority":2555\},\{"name":"ldap-auth","priority":2540 } } --- response_body eval -qr/\{"properties":\{"password":\{"encrypted":true,"type":"string"\},"username":\{"type":"string"\}\},"required":\["username","password"\],"title":"work with consumer object","type":"object"\}/ +qr/\{"encrypt_fields":\["password"\],"properties":\{"password":\{"type":"string"\},"username":\{"type":"string"\}\},"required":\["username","password"\],"title":"work with consumer object","type":"object"\}/ diff --git a/t/plugin/authz-casdoor.t b/t/plugin/authz-casdoor.t index ace2c966bdda..926d3daef97a 100644 --- a/t/plugin/authz-casdoor.t +++ b/t/plugin/authz-casdoor.t @@ -438,3 +438,71 @@ invalid state done --- error_log failed when accessing token: invalid access_token + + + +=== TEST 10: data encryption for client_secret +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local callback_url = "http://127.0.0.1:" .. ngx.var.server_port .. + "/anything/callback" + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "uri": "/anything/*", + "plugins": { + "authz-casdoor": { + "callback_url":"]] .. callback_url .. [[", + "endpoint_addr": "http://127.0.0.1:10420", + "client_id":"7ceb9b7fda4a9061ec1c", + "client_secret":"3416238e1edf915eac08b8fe345b2b95cdba7e04" + } + }, + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }]] + ) + + 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 + + ngx.say(res.value.plugins["authz-casdoor"].client_secret) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["authz-casdoor"].client_secret) + } + } +--- response_body +3416238e1edf915eac08b8fe345b2b95cdba7e04 +YUfqAO0kPXjZIoAbPSuryCkUDksEmwSq08UDTIUWolN6KQwEUrh72TazePueo4/S diff --git a/t/plugin/authz-keycloak3.t b/t/plugin/authz-keycloak3.t index a198fb8f81f5..2671e903999f 100644 --- a/t/plugin/authz-keycloak3.t +++ b/t/plugin/authz-keycloak3.t @@ -106,3 +106,73 @@ passed --- error_code: 307 --- response_headers Location: http://127.0.0.1/test + + + +=== TEST 3: data encryption for client_secret +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "authz-keycloak": { + "token_endpoint": "https://127.0.0.1:8443/auth/realms/University/protocol/openid-connect/token", + "permissions": ["course_resource#view"], + "client_id": "course_management", + "client_secret": "d1ec69e9-55d2-4109-a3ea-befa071579d5", + "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket", + "timeout": 3000, + "ssl_verify": false, + "password_grant_token_generation_incoming_uri": "/api/token" + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin" + }, + "uri": "/api/token" + }]] + ) + + 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 + + ngx.say(res.value.plugins["authz-keycloak"].client_secret) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["authz-keycloak"].client_secret) + } + } +--- response_body +d1ec69e9-55d2-4109-a3ea-befa071579d5 +Fz1juZEEvh9PPXOmWFdMMJkREt3ZSzEVWcUZPxNP6achk3fosEvn37oN0qH4YgKB diff --git a/t/plugin/csrf.t b/t/plugin/csrf.t index 6f76dabb4ecb..1edc30239c4c 100644 --- a/t/plugin/csrf.t +++ b/t/plugin/csrf.t @@ -325,3 +325,66 @@ passed } --- response_body hello world + + + +=== TEST 15: data encryption for key +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "uri": "/hello", + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + }, + "plugins": { + "csrf": { + "key": "userkey", + "expires": 1000000000 + } + } + }]] + ) + + 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 + + ngx.say(res.value.plugins["csrf"].key) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["csrf"].key) + } + } +--- response_body +userkey +mt39FazQccyMqt4ctoRV7w== diff --git a/t/plugin/elasticsearch-logger.t b/t/plugin/elasticsearch-logger.t index b381bf752dbc..11b85e14b9fb 100644 --- a/t/plugin/elasticsearch-logger.t +++ b/t/plugin/elasticsearch-logger.t @@ -447,3 +447,71 @@ hello world --- wait: 2 --- error_log check elasticsearch custom body success + + + +=== TEST 12: data encryption for auth.password +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, { + uri = "/hello", + upstream = { + type = "roundrobin", + nodes = { + ["127.0.0.1:1980"] = 1 + } + }, + plugins = { + ["elasticsearch-logger"] = { + endpoint_addr = "http://127.0.0.1:9201", + field = { + index = "services" + }, + auth = { + username = "elastic", + password = "123456" + }, + batch_max_size = 1, + inactive_timeout = 1 + } + } + }) + + 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 + + ngx.say(res.value.plugins["elasticsearch-logger"].auth.password) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["elasticsearch-logger"].auth.password) + } + } +--- response_body +123456 +PTQvJEaPcNOXcOHeErC0XQ== diff --git a/t/plugin/error-log-logger-clickhouse.t b/t/plugin/error-log-logger-clickhouse.t index f6a328d7f208..41dfe15d43fb 100644 --- a/t/plugin/error-log-logger-clickhouse.t +++ b/t/plugin/error-log-logger-clickhouse.t @@ -211,3 +211,85 @@ this is an info message for test6 } --- response_body passed + + + +=== TEST 8: data encryption for clickhouse.password +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/plugin_metadata/error-log-logger', + ngx.HTTP_PUT, + [[{ + "clickhouse": { + "user": "default", + "password": "bar", + "database": "default", + "logtable": "t", + "endpoint_addr": "http://127.0.0.1:1980/clickhouse_logger_server" + }, + "batch_max_size": 15, + "inactive_timeout": 1 + }]] + ) + + 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/plugin_metadata/error-log-logger', + ngx.HTTP_GET + ) + res = json.decode(res) + if code >= 300 then + ngx.status = code + ngx.say(message) + return + end + + ngx.say(res.value["clickhouse"].password) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/plugin_metadata/error-log-logger')) + + ngx.say(res.body.node.value["clickhouse"].password) + } + } +--- response_body +bar +77+NmbYqNfN+oLm0aX5akg== + + + +=== TEST 9: verify use the decrypted password to connect to clickhouse +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local core = require("apisix.core") + core.log.warn("this is a warning message for test9") + } + } +--- response_body +--- error_log +this is a warning message for test9 +clickhouse headers: x-clickhouse-key:bar +--- wait: 5 diff --git a/t/plugin/google-cloud-logging2.t b/t/plugin/google-cloud-logging2.t index 8efec79422da..6fbe6b350eef 100644 --- a/t/plugin/google-cloud-logging2.t +++ b/t/plugin/google-cloud-logging2.t @@ -68,3 +68,128 @@ __DATA__ } --- response_body passed + + + +=== TEST 2: data encryption for auth_config.private_key +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local config = { + uri = "/hello", + upstream = { + type = "roundrobin", + nodes = { + ["127.0.0.1:1980"] = 1 + } + }, + plugins = { + ["google-cloud-logging"] = { + auth_config = { + private_key = [[ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDDzrFwnA3EvYyR +aeMgaLD3hBjvxKrz10uox1X8q7YYhf2ViRtLRUMa2bEMYksE5hbhwpNf6mKAnLOC +UuAT6cPPdUl/agKpJXviBPIR2LuzD17WsLJHp1HxUDssSkgfCaGcOGGNfLUhhIpF +2JUctLmxiZoAZySlSjcwupSuDJ0aPm0XO8r9H8Qu5kF2Vkz5e5bFivLTmvzrQTe4 +v5V1UI6hThElCSeUmdNF3uG3wopxlvq4zXgLTnuLbrNf/Gc4mlpV+UDgTISj32Ep +AB2vxKEbvQw4ti8YJnGXWjxLerhfrszFw+V8lpeduiDYA44ZFoVqvzxeIsVZNtcw +Iu7PvEPNAgMBAAECggEAVpyN9m7A1F631/aLheFpLgMbeKt4puV7zQtnaJ2XrZ9P +PR7pmNDpTu4uF3k/D8qrIm+L+uhVa+hkquf3wDct6w1JVnfQ93riImbnoKdK13ic +DcEZCwLjByfjFMNCxZ/gAZca55fbExlqhFy6EHmMjhB8s2LsXcTHRuGxNI/Vyi49 +sxECibe0U53aqdJbVWrphIS67cpwl4TUkN6mrHsNuDYNJ9dgkpapoqp4FTFQsBqC +afOK5qgJ68dWZ47FBUng+AZjdCncqAIuJxxItGVQP6YPsFs+OXcivIVHJr363TpC +l85FfdvqWV5OGBbwSKhNwiTNUVvfSQVmtURGWG/HbQKBgQD4gZ1z9+Lx19kT9WTz +lw93lxso++uhAPDTKviyWSRoEe5aN3LCd4My+/Aj+sk4ON/s2BV3ska5Im93j+vC +rCv3uPn1n2jUhWuJ3bDqipeTW4n/CQA2m/8vd26TMk22yOkkqw2MIA8sjJ//SD7g +tdG7up6DgGMP4hgbO89uGU7DAwKBgQDJtkKd0grh3u52Foeh9YaiAgYRwc65IE16 +UyD1OJxIuX/dYQDLlo5KyyngFa1ZhWIs7qC7r3xXH+10kfJY+Q+5YMjmZjlL8SR1 +Ujqd02R9F2//6OeswyReachJZbZdtiEw3lPa4jVFYfhSe0M2ZPxMwvoXb25eyCNI +1lYjSKq87wKBgHnLTNghjeDp4UKe6rNYPgRm0rDrhziJtX5JeUov1mALKb6dnmkh +GfRK9g8sQqKDfXwfC6Z2gaMK9YaryujGaWYoCpoPXtmJ6oLPXH4XHuLh4mhUiP46 +xn8FEfSimuQS4/FMxH8A128GHQSI7AhGFFzlwfrBWcvXC+mNDsTvMmLxAoGARc+4 +upppfccETQZ7JsitMgD1TMwA2f2eEwoWTAitvlXFNT9PYSbYVHaAJbga6PLLCbYF +FzAjHpxEOKYSdEyu7n/ayDL0/Z2V+qzc8KarDsg/0RgwppBbU/nUgeKb/U79qcYo +y4ai3UKNCS70Ei1dTMvmdpnwXwlxfNIBufB6dy0CgYBMYq9Lc31GkC6PcGEEbx6W +vjImOadWZbuOVnvEQjb5XCdcOsWsMcg96PtoeuyyHmhnEF1GsMzcIdQv/PHrvYpK +Yp8D0aqsLEgwGrJQER26FPpKmyIwvcL+nm6q5W31PnU9AOC/WEkB6Zs58hsMzD2S +kEJQcmfVew5mFXyxuEn3zA== +-----END PRIVATE KEY-----]], + project_id = "apisix", + token_uri = "http://127.0.0.1:1980/google/logging/token", + scopes = { + "https://apisix.apache.org/logs:admin" + }, + entries_uri = "http://127.0.0.1:1980/google/logging/entries", + }, + inactive_timeout = 1, + batch_max_size = 1, + } + } + } + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', ngx.HTTP_PUT, config) + + 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 + + ngx.say(res.value.plugins["google-cloud-logging"].auth_config.private_key) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["google-cloud-logging"].auth_config.private_key) + } + } +--- response_body +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDDzrFwnA3EvYyR +aeMgaLD3hBjvxKrz10uox1X8q7YYhf2ViRtLRUMa2bEMYksE5hbhwpNf6mKAnLOC +UuAT6cPPdUl/agKpJXviBPIR2LuzD17WsLJHp1HxUDssSkgfCaGcOGGNfLUhhIpF +2JUctLmxiZoAZySlSjcwupSuDJ0aPm0XO8r9H8Qu5kF2Vkz5e5bFivLTmvzrQTe4 +v5V1UI6hThElCSeUmdNF3uG3wopxlvq4zXgLTnuLbrNf/Gc4mlpV+UDgTISj32Ep +AB2vxKEbvQw4ti8YJnGXWjxLerhfrszFw+V8lpeduiDYA44ZFoVqvzxeIsVZNtcw +Iu7PvEPNAgMBAAECggEAVpyN9m7A1F631/aLheFpLgMbeKt4puV7zQtnaJ2XrZ9P +PR7pmNDpTu4uF3k/D8qrIm+L+uhVa+hkquf3wDct6w1JVnfQ93riImbnoKdK13ic +DcEZCwLjByfjFMNCxZ/gAZca55fbExlqhFy6EHmMjhB8s2LsXcTHRuGxNI/Vyi49 +sxECibe0U53aqdJbVWrphIS67cpwl4TUkN6mrHsNuDYNJ9dgkpapoqp4FTFQsBqC +afOK5qgJ68dWZ47FBUng+AZjdCncqAIuJxxItGVQP6YPsFs+OXcivIVHJr363TpC +l85FfdvqWV5OGBbwSKhNwiTNUVvfSQVmtURGWG/HbQKBgQD4gZ1z9+Lx19kT9WTz +lw93lxso++uhAPDTKviyWSRoEe5aN3LCd4My+/Aj+sk4ON/s2BV3ska5Im93j+vC +rCv3uPn1n2jUhWuJ3bDqipeTW4n/CQA2m/8vd26TMk22yOkkqw2MIA8sjJ//SD7g +tdG7up6DgGMP4hgbO89uGU7DAwKBgQDJtkKd0grh3u52Foeh9YaiAgYRwc65IE16 +UyD1OJxIuX/dYQDLlo5KyyngFa1ZhWIs7qC7r3xXH+10kfJY+Q+5YMjmZjlL8SR1 +Ujqd02R9F2//6OeswyReachJZbZdtiEw3lPa4jVFYfhSe0M2ZPxMwvoXb25eyCNI +1lYjSKq87wKBgHnLTNghjeDp4UKe6rNYPgRm0rDrhziJtX5JeUov1mALKb6dnmkh +GfRK9g8sQqKDfXwfC6Z2gaMK9YaryujGaWYoCpoPXtmJ6oLPXH4XHuLh4mhUiP46 +xn8FEfSimuQS4/FMxH8A128GHQSI7AhGFFzlwfrBWcvXC+mNDsTvMmLxAoGARc+4 +upppfccETQZ7JsitMgD1TMwA2f2eEwoWTAitvlXFNT9PYSbYVHaAJbga6PLLCbYF +FzAjHpxEOKYSdEyu7n/ayDL0/Z2V+qzc8KarDsg/0RgwppBbU/nUgeKb/U79qcYo +y4ai3UKNCS70Ei1dTMvmdpnwXwlxfNIBufB6dy0CgYBMYq9Lc31GkC6PcGEEbx6W +vjImOadWZbuOVnvEQjb5XCdcOsWsMcg96PtoeuyyHmhnEF1GsMzcIdQv/PHrvYpK +Yp8D0aqsLEgwGrJQER26FPpKmyIwvcL+nm6q5W31PnU9AOC/WEkB6Zs58hsMzD2S +kEJQcmfVew5mFXyxuEn3zA== +-----END PRIVATE KEY----- +YnwwDKc5vNzo0OU4StTRQbwgCnTZ3dmYiBFm8aGnvTxlE86D2nT07Q3BWhUdky6OGIox4MRLbiHz13NZjyUao/Nudh4PeTj5wMldPD5YvNWtbTG4ig/TNSdBncmIQPLPaUqSweE61pnASxodpTlBJ5k9yxfTmwBTOkzZevoKy9D2E4wF9vGCdkcPK/tAkvRoJTj6xD3xVuAbkcap/81oHplUZZ+ghlEnBZgOH8UMa73UfeNbOQVHD2mlU0LxkTXtwFhHWl50adrt890VDHev0+FUUDjv5Ysl8r/nnnlyq3SV4oqJfs/IVRKROe93e8sJ2/49o7kEv2XT1/6DjM/VsSLKfAi5rLNobcSaSzztSSLkrBFKQvvy2rRA7GFWKbIk+rPZhYmTMItDJv23XP6uzaLRPoq2f/AnRTKpWmA8Dk9TfFHsZLupKi1bmjCdtK8lpMCf9Au1rezt7+2BybQrtbbDbwPzC5bKHmKhc0GPTUzLAWQBin3tuZxSfk/MqRtG+AemwnFTHivJrfRwmc3db+b9W6WX09mV488f2M4qbqBmkiFU5VARWCGZ5vbop2KGhmB2fQPXTmj8QSYk6fBxFDnfzTfnYMIu2cQsbSBPCnoPinQNpBfFD3RQkkCiNtJ8GA8DWsivWsnW4jWyPmkIN/P1eLW1DSsU6V4cbhTQJs6/LzOCGAZB/ewu3mr1SDLWJPlIWW6atC/g0uiXkZ3VLUsS0BQffITf8sVXyz/BEbflLlT777zERDKyz/qS2JyR6U8s2h3Yg+GncPUCEF6Lx5Veb1lL+zs+Stvv+5/t2GfDlNYiwTU8HeffhEGgAv1s86OPo3CfWe7lEnu/MFHIm0czVenYdEVy449xj66DHqXUQVzVc+3NelW15FrKhcvU0Cxwqfk+xEOE185ssD06L+tOGjxPPvADjlcQQ1crH+tEcTTLnZZ/e16I10kcc5rBJwDy4COoeY6DZ0dFwtAdbjoR/KaSTGLK6n/u9Ow7OGDPZog4LhrzMOn2T7hk/oaMOKhlDvKroiSijhhkrQf5ZDhhh3GQn/ZRXjyiPWBqKEQiBJGyZ/iRONzJLsF8U8vsBzBToxmTe9prlwHusgAEIBUFrZRSvsVgsPCFOyJ6XJXDTdcCInHUGI9LsxWdlojYvvNuSvavkw1I4K+VBmlEG5FCMx56eX2X49hfXwRcM1ZyRRrmq6cRh+33aMeMLAtpKgTsQgmB/I01mGNZlstvU0XEFnCPuWcks50BTnvPEbU7GZJLE3HFmGb3vyC57E8oTR2FjhDrevPlLkxMPrLvXhwbmV+3YiZYq+8k6oBKfrrq41JRKr+SJDb7m6xL8AuZccMrNhDrkByQLi6zn95dIYc3+vNU4XBzvhpb7HMj2wvorxEW2HpQ+OVSZiZSCU6m4Fx6juj1D5pGs1nr68ybihqMrXuZBKP4b9Y6sw99kNmnWBdwNiY95sWy1qUe0MJq3r44hhVHvCUmzOVyO4aBmhMwgkaSQWpEeQwyIWENM1IMU6WUrKCSuLuKJAl5bM++ThBaLvIIMCyXl39136jHp97aVmHRXbSMPcSAb8l/YQ6SLK0HBxmFTXvroxHmPxPqrJ5jz65C72+uArgOZxJN6tyimIcTMyoJoN7N+QKxDLjgmqnJyEcthycEK3gikyloWsLppzEmHLHBDXlKpJLflvUujYrNsKf2xohx31gIlxBWCHP/1KL3QAehn+FEWUWsXn2hWAR0KAtmIOM7gZuCY8yKNDfXrAZJs14rwDlTbnhJvyijt1Tr6gleehmJDKSm2vM/NbznVTKwJDyMRner+vvc4zD06az/Y6Y4oM0e0IWM2fMaiiwjNAaKhhwJzqvM1c8+ZOfuRajmHFECEkYgXCKZiQxQihFG2wWp2i+xEGGwP2e+FbDdY9Ygyvw5SUvahyoX36AYbbTBOFY6E9aYUIM/Et8ZuXoWs1QaxGfJwcVvueqke45y3GKkp54sHXhrqfKX0TTiw6DCUs6dRTybxOjmjJCKp6Yw4KGWY0t3J0xbK08KTUMeHNxgtfYcz1/Wg/Q61CkUJkRNBninAAkEz8rV2olBHy1GZFFjCQySAyPH4PtWm1S4sBzdsui5wT+m2pC/DsCcQW++TGH9LdaHeT8B9u32lYToVN1/L2j5kjkhN13sNKfb6I9yYTnUqweQFU79toBfDt+6KNNfIA1TcmvZw8RcuMOArEqJQ6OPOhgUQBwsZaGeqFmAE4q64n5raS4OCdWtasFtItW3c5QHxkKoEEER04glVsCoxOvc80U= diff --git a/t/plugin/hmac-auth3.t b/t/plugin/hmac-auth3.t index 7e89b995d9d4..df41efaa16a5 100644 --- a/t/plugin/hmac-auth3.t +++ b/t/plugin/hmac-auth3.t @@ -682,3 +682,76 @@ location /t { } --- response_body passed + + + +=== TEST 13: delete exist consumers +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + -- delete exist consumers + local code, body = t('/apisix/admin/consumers/robin', ngx.HTTP_DELETE) + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 14: data encryption for secret_key +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "jack", + "plugins": { + "hmac-auth": { + "access_key": "my-access-key", + "secret_key": "my-secret-key", + "clock_skew": 10 + } + } + }]] + ) + + 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/consumers/jack', + ngx.HTTP_GET + ) + res = json.decode(res) + if code >= 300 then + ngx.status = code + ngx.say(message) + return + end + + ngx.say(res.value.plugins["hmac-auth"].secret_key) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/consumers/jack')) + ngx.say(res.body.node.value.plugins["hmac-auth"].secret_key) + } + } +--- response_body +my-secret-key +IRWpPjbDq5BCgHyIllnOMA== diff --git a/t/plugin/jwt-auth3.t b/t/plugin/jwt-auth3.t index 6a97771320a4..3e431232f406 100755 --- a/t/plugin/jwt-auth3.t +++ b/t/plugin/jwt-auth3.t @@ -300,3 +300,145 @@ GET /get Cookie: hello=world; jwt-cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs; foo=bar --- response_body eval qr/hello=world; foo=bar/ + + + +=== TEST 13: delete exist consumers +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + -- delete exist consumers + local code, body = t('/apisix/admin/consumers/jack', ngx.HTTP_DELETE) + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 14: data encryption for secret +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "jack", + "plugins": { + "jwt-auth": { + "key": "user-key", + "secret": "my-secret-key" + } + } + }]] + ) + + 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/consumers/jack', + ngx.HTTP_GET + ) + res = json.decode(res) + if code >= 300 then + ngx.status = code + ngx.say(message) + return + end + ngx.say(res.value.plugins["jwt-auth"].secret) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/consumers/jack')) + ngx.say(res.body.node.value.plugins["jwt-auth"].secret) + } + } +--- response_body +my-secret-key +IRWpPjbDq5BCgHyIllnOMA== + + + +=== TEST 15: data encryption for private_key +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + + -- dletet exist consumers + t('/apisix/admin/consumers/jack', ngx.HTTP_DELETE) + + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "jack", + "plugins": { + "jwt-auth": { + "key": "user-key-rs256", + "algorithm": "RS256", + "public_key": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr\n7noq/0ukiZqVQLSJPMOv0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQ==\n-----END PUBLIC KEY-----", + "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv\n0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7\n+pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL\nwQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF\nIeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb\n2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs\nYvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG\n-----END RSA PRIVATE KEY-----" + } + } + }]] + ) + + 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/consumers/jack', + ngx.HTTP_GET + ) + res = json.decode(res) + if code >= 300 then + ngx.status = code + ngx.say(message) + return + end + + ngx.say(res.value.plugins["jwt-auth"].private_key) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/consumers/jack')) + ngx.say(res.body.node.value.plugins["jwt-auth"].private_key) + } + } +--- response_body +-----BEGIN RSA PRIVATE KEY----- +MIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv +0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7 ++pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL +wQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF +IeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb +2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs +YvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG +-----END RSA PRIVATE KEY----- +HrMHUvE9Esvn7GnZ+vAynaIg/8wlB3r0zm0htmnwofYPZeBpLnpW3iN9UtQG4ZIBYRZih6EBuRK8W3Kychw/SgjIFuzVeTFowBCUfd1wZ4Q+frUOLZ0Xmkh8j3yHUprnh+d9PA8EHCEapdkWY3psJj6rTgrREzjDEVf/TV3EjjfgG16ih5/c3TChApLXwfEwfBp5APSf7kzMccCRbA4bXvMDsQSQAwVsRD8cjJkSdHTvuzfg1g8xoCy4I05DsMM8CybJAd+BDZnJxhrGIQaItu5/0XQJy+uy/niOpzYYN+NDX+8fl65VUxdUtqXF82ChRlmGP3+zKN7epufAsL/36pHOnS73Q7WBKRxyyA16BEBk0wK7rI+KemBfG5YFXjcBnPkxYssSudqhmlcr6e5Tl0LhVj/BIj94fVE3/EJ+NO3BJMrlhjorilrQKAsiCWujWSqAK7gtAp3YEO//yOygh/p8gh22NdIV0ykGAx4QNKINUgdgh+g8DdykNGLGStH8TPUs8GmzV7nxvw/0cbiocLps6uk0VjjVUqUAvOdwpbiRwv6effPUB6cxW3G6QllBbTP8I+eoFIRfYd6cFJPpX1AtISfNZw459WarwZmHrZGOQU4iKlyl2yLcKY634Fx5JykUY5YP+MYYDHbIcD2gxA== diff --git a/t/plugin/kafka-proxy.t b/t/plugin/kafka-proxy.t index a6ada516f74b..52ba9d8742b6 100644 --- a/t/plugin/kafka-proxy.t +++ b/t/plugin/kafka-proxy.t @@ -55,3 +55,68 @@ done done property "sasl" validation failed: property "password" is required property "sasl" validation failed: property "password" validation failed: wrong type: expected string, got number + + + +=== TEST 2: data encryption for sasl.password +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "kafka-proxy": { + "sasl": { + "username": "admin", + "password": "admin-secret" + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin" + }, + "uri": "/opentracing" + }]] + ) + + 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 + + ngx.say(res.value.plugins["kafka-proxy"].sasl.password) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["kafka-proxy"].sasl.password) + } + } +--- response_body +admin-secret +y4Z3aqo51xrt3f9UziNUrg== diff --git a/t/plugin/openid-connect2.t b/t/plugin/openid-connect2.t index 810df97755ef..c9c963319184 100644 --- a/t/plugin/openid-connect2.t +++ b/t/plugin/openid-connect2.t @@ -78,3 +78,72 @@ __DATA__ end } } + + + +=== TEST 2: data encryption for client_secret +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "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 + } + }, + "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 + + ngx.say(res.value.plugins["openid-connect"].client_secret) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["openid-connect"].client_secret) + } + } +--- response_body +60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa +xMlerg8pE2lPSDlQdPi+MsAwBnzqpyLRar3lUhP2Tdc2oXnWmit92p8cannhDYkBPc6P/Hlx0wSA0T2wle9QyHaW2oqw3bXDQSWWk8Vqq0o= diff --git a/t/plugin/rocketmq-logger2.t b/t/plugin/rocketmq-logger2.t index ae33d1f5c3f2..af84ecf28d7f 100644 --- a/t/plugin/rocketmq-logger2.t +++ b/t/plugin/rocketmq-logger2.t @@ -440,3 +440,68 @@ qr/send data to rocketmq: \{.*"body":"hello world\\n"/ } --- response_body done + + + +=== TEST 14: data encryption for secret_key +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "rocketmq-logger": { + "nameserver_list" : [ "127.0.0.1:9876" ], + "topic" : "test2", + "access_key": "foo", + "secret_key": "bar" + } + }, + "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 + + ngx.say(res.value.plugins["rocketmq-logger"].secret_key) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["rocketmq-logger"].secret_key) + } + } +--- response_body +bar +77+NmbYqNfN+oLm0aX5akg== diff --git a/t/plugin/sls-logger.t b/t/plugin/sls-logger.t index c8aaf9c4f59e..c1bce8107d46 100644 --- a/t/plugin/sls-logger.t +++ b/t/plugin/sls-logger.t @@ -240,3 +240,86 @@ passed GET /hello --- response_body hello world + + + +=== TEST 10: delete exist routes +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + -- delete exist consumers + local code, body = t('/apisix/admin/routes/1', ngx.HTTP_DELETE) + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 11: data encryption for access_key_secret +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "sls-logger": { + "host": "100.100.99.135", + "port": 10009, + "project": "your_project", + "logstore": "your_logstore", + "access_key_id": "your_access_key_id", + "access_key_secret": "your_access_key_secret", + "timeout": 30000 + } + }, + "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 + + ngx.say(res.value.plugins["sls-logger"].access_key_secret) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["sls-logger"].access_key_secret) + } + } +--- response_body +your_access_key_secret +1T6nR0fz4yhz/zTuRTvt7Xu3c9ASelDXG2//e/A5OiA= diff --git a/t/plugin/tencent-cloud-cls.t b/t/plugin/tencent-cloud-cls.t index e5736fa0fbc2..b16e5c1243c9 100644 --- a/t/plugin/tencent-cloud-cls.t +++ b/t/plugin/tencent-cloud-cls.t @@ -324,3 +324,88 @@ GET /opentracing --- response_body opentracing --- wait: 0.5 + + + +=== TEST 11: delete exist routes +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + -- delete exist consumers + local code, body = t('/apisix/admin/routes/1', ngx.HTTP_DELETE) + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 12: data encryption for secret_key +--- yaml_config +apisix: + data_encryption: + enable: true + keyring: + - edd1c9f0985e76a2 +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "tencent-cloud-cls": { + "cls_host": "127.0.0.1:10421", + "cls_topic": "143b5d70-139b-4aec-b54e-bb97756916de", + "secret_id": "secret_id", + "secret_key": "secret_key", + "batch_max_size": 1, + "max_retry_count": 1, + "retry_delay": 2, + "buffer_duration": 2, + "inactive_timeout": 2 + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1982": 1 + }, + "type": "roundrobin" + }, + "uri": "/opentracing" + }]] + ) + + 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 + + ngx.say(res.value.plugins["tencent-cloud-cls"].secret_key) + + -- get plugin conf from etcd, password is encrypted + local etcd = require("apisix.core.etcd") + local res = assert(etcd.get('/routes/1')) + ngx.say(res.body.node.value.plugins["tencent-cloud-cls"].secret_key) + } + } +--- response_body +secret_key +oshn8tcqE8cJArmEILVNPQ==