diff --git a/README.md b/README.md index 53768330206c..b819601325fc 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against - [Elasticsearch](docs/en/latest/plugins/elasticsearch-logger.md): push logs to Elasticsearch. - [Datadog](docs/en/latest/plugins/datadog.md): push custom metrics to the DogStatsD server, comes bundled with [Datadog agent](https://docs.datadoghq.com/agent/), over the UDP protocol. DogStatsD basically is an implementation of StatsD protocol which collects the custom metrics for Apache APISIX agent, aggregates it into a single data point and sends it to the configured Datadog server. - [Helm charts](https://github.com/apache/apisix-helm-chart) - - [HashiCorp Vault](https://www.vaultproject.io/): Support secret management solution for accessing secrets from Vault secure storage backed in a low trust environment. Currently, RS256 keys (public-private key pairs) or secret keys can be linked from vault in [jwt-auth](docs/en/latest/plugins/jwt-auth.md#enable-jwt-auth-with-vault-compatibility) authentication plugin. + - [HashiCorp Vault](https://www.vaultproject.io/): Support secret management solution for accessing secrets from Vault secure storage backed in a low trust environment. Currently, RS256 keys (public-private key pairs) or secret keys can be linked from vault in jwt-auth authentication plugin using [APISIX Secret](docs/en/latest/terminology/secret.md) resource. - **Highly scalable** - [Custom plugins](docs/en/latest/plugin-develop.md): Allows hooking of common phases, such as `rewrite`, `access`, `header filter`, `body filter` and `log`, also allows to hook the `balancer` stage. diff --git a/apisix/core/vault.lua b/apisix/core/vault.lua deleted file mode 100644 index aeb8485d97ef..000000000000 --- a/apisix/core/vault.lua +++ /dev/null @@ -1,127 +0,0 @@ --- --- Licensed to the Apache Software Foundation (ASF) under one or more --- contributor license agreements. See the NOTICE file distributed with --- this work for additional information regarding copyright ownership. --- The ASF licenses this file to You under the Apache License, Version 2.0 --- (the "License"); you may not use this file except in compliance with --- the License. You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- - ---- Vault Tools. --- Vault is an identity-based secrets and encryption management system. --- --- @module core.vault - -local core = require("apisix.core") -local http = require("resty.http") -local json = require("cjson") - -local fetch_local_conf = require("apisix.core.config_local").local_conf -local norm_path = require("pl.path").normpath - -local _M = {} - -local function fetch_vault_conf() - local conf, err = fetch_local_conf() - if not conf then - return nil, "failed to fetch vault configuration from config yaml: " .. err - end - - if not conf.vault then - return nil, "accessing vault data requires configuration information" - end - return conf.vault -end - - -local function make_request_to_vault(method, key, skip_prefix, data) - local vault, err = fetch_vault_conf() - if not vault then - return nil, err - end - - local httpc = http.new() - -- config timeout or default to 5000 ms - httpc:set_timeout((vault.timeout or 5)*1000) - - local req_addr = vault.host - if not skip_prefix then - req_addr = req_addr .. norm_path("/v1/" - .. vault.prefix .. "/" .. key) - else - req_addr = req_addr .. norm_path("/v1/" .. key) - end - - local res, err = httpc:request_uri(req_addr, { - method = method, - headers = { - ["X-Vault-Token"] = vault.token - }, - body = core.json.encode(data or {}, true) - }) - if not res then - return nil, err - end - - return res.body -end - --- key is the vault kv engine path, joined with config yaml vault prefix. --- It takes an extra optional boolean param skip_prefix. If enabled, it simply doesn't use the --- prefix defined inside config yaml under vault config for fetching data. -local function get(key, skip_prefix) - core.log.info("fetching data from vault for key: ", key) - - local res, err = make_request_to_vault("GET", key, skip_prefix) - if not res then - return nil, "failed to retrtive data from vault kv engine " .. err - end - - return json.decode(res) -end - -_M.get = get - --- key is the vault kv engine path, data is json key value pair. --- It takes an extra optional boolean param skip_prefix. If enabled, it simply doesn't use the --- prefix defined inside config yaml under vault config for storing data. -local function set(key, data, skip_prefix) - core.log.info("storing data into vault for key: ", key, - "and value: ", core.json.delay_encode(data, true)) - - local res, err = make_request_to_vault("POST", key, skip_prefix, data) - if not res then - return nil, "failed to store data into vault kv engine " .. err - end - - return true -end -_M.set = set - - --- key is the vault kv engine path, joined with config yaml vault prefix. --- It takes an extra optional boolean param skip_prefix. If enabled, it simply doesn't use the --- prefix defined inside config yaml under vault config for deleting data. -local function delete(key, skip_prefix) - core.log.info("deleting data from vault for key: ", key) - - local res, err = make_request_to_vault("DELETE", key, skip_prefix) - - if not res then - return nil, "failed to delete data into vault kv engine " .. err - end - - return true -end - -_M.delete = delete - -return _M diff --git a/apisix/plugins/jwt-auth.lua b/apisix/plugins/jwt-auth.lua index 96c743e1ba07..f195830a696c 100644 --- a/apisix/plugins/jwt-auth.lua +++ b/apisix/plugins/jwt-auth.lua @@ -18,7 +18,6 @@ local core = require("apisix.core") local jwt = require("resty.jwt") local consumer_mod = require("apisix.consumer") local resty_random = require("resty.random") -local vault = require("apisix.core.vault") local new_tab = require ("table.new") local ngx_encode_base64 = ngx.encode_base64 @@ -71,10 +70,6 @@ local consumer_schema = { type = "boolean", default = false }, - vault = { - type = "object", - properties = {} - }, lifetime_grace_period = { type = "integer", minimum = 0, @@ -102,19 +97,6 @@ local consumer_schema = { }, required = {"public_key", "private_key"}, }, - { - properties = { - vault = { - type = "object", - properties = {} - }, - algorithm = { - enum = {"RS256", "ES256"}, - }, - }, - required = {"vault"}, - }, - } } }, @@ -147,11 +129,6 @@ function _M.check_schema(conf, schema_type) return false, err end - if conf.vault then - core.log.info("skipping jwt-auth schema validation with vault") - return true - end - if conf.algorithm ~= "RS256" and conf.algorithm ~= "ES256" and not conf.secret then conf.secret = ngx_encode_base64(resty_random.bytes(32, true)) elseif conf.base64_secret then @@ -161,8 +138,8 @@ function _M.check_schema(conf, schema_type) end if conf.algorithm == "RS256" or conf.algorithm == "ES256" then - -- Possible options are a) both are in vault, b) both in schema - -- c) one in schema, another in vault. + -- Possible options are a) public key is missing + -- b) private key is missing if not conf.public_key then return false, "missing valid public key" end @@ -243,25 +220,8 @@ local function fetch_jwt_token(conf, ctx) return val end - -local function get_vault_path(username) - return "consumer/".. username .. "/jwt-auth" -end - - local function get_secret(conf, consumer_name) local secret = conf.secret - if conf.vault then - local res, err = vault.get(get_vault_path(consumer_name)) - if not res then - return nil, err - end - - if not res.data or not res.data.secret then - return nil, "secret could not found in vault: " .. core.json.encode(res) - end - secret = res.data.secret - end if conf.base64_secret then return ngx_decode_base64(secret) @@ -274,32 +234,16 @@ end local function get_rsa_or_ecdsa_keypair(conf, consumer_name) local public_key = conf.public_key local private_key = conf.private_key - -- if keys are present in conf, no need to query vault (fallback) + if public_key and private_key then return public_key, private_key + elseif public_key and not private_key then + return nil, nil, "missing private key" + elseif not public_key and private_key then + return nil, nil, "missing public key" + else + return nil, nil, "public and private keys are missing" end - - local vout = {} - if conf.vault then - local res, err = vault.get(get_vault_path(consumer_name)) - if not res then - return nil, nil, err - end - - if not res.data then - return nil, nil, "key pairs could not found in vault: " .. core.json.encode(res) - end - vout = res.data - end - - if not public_key and not vout.public_key then - return nil, nil, "missing public key, not found in config/vault" - end - if not private_key and not vout.private_key then - return nil, nil, "missing private key, not found in config/vault" - end - - return public_key or vout.public_key, private_key or vout.private_key end diff --git a/apisix/secret/vault.lua b/apisix/secret/vault.lua index aff458f2c77d..eb2e6564cd94 100644 --- a/apisix/secret/vault.lua +++ b/apisix/secret/vault.lua @@ -45,12 +45,6 @@ local _M = { schema = schema } --- This code is copied from apisix/core/vault.lua. --- The functions in apisix/core/vault.lua are currently only used in the jwt-auth plugin, --- and it is not suitable to be placed in the core module of APISIX. --- --- When KMS is fully functional, we will remove apisix/core/vault.lua. --- local function make_request_to_vault(conf, method, key, data) local httpc = http.new() -- config timeout or default to 5000 ms diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 9e47f0660137..43bbad005e15 100755 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -250,19 +250,6 @@ nginx_config: # config for render the template to generate n tars: 1m cas-auth: 10m -# HashiCorp Vault storage backend for sensitive data retrieval. The config shows an example of what APISIX expects if you -# wish to integrate Vault for secret (sensetive string, public private keys etc.) retrieval. APISIX communicates with Vault -# server HTTP APIs. By default, APISIX doesn't need this configuration. -# vault: -# host: "http://0.0.0.0:8200" # The host address where the vault server is running. -# timeout: 10 # request timeout 30 seconds -# token: root # Authentication token to access Vault HTTP APIs -# prefix: kv/apisix # APISIX supports vault kv engine v1, where sensitive data are being stored - # and retrieved through vault HTTP APIs. enabling a prefix allows you to better enforcement of - # policies, generate limited scoped tokens and tightly control the data that can be accessed - # from APISIX. - - #discovery: # service discovery center # dns: # servers: diff --git a/docs/en/latest/getting-started.md b/docs/en/latest/getting-started.md index 5191b27b02d7..62a4a4810402 100644 --- a/docs/en/latest/getting-started.md +++ b/docs/en/latest/getting-started.md @@ -50,7 +50,7 @@ APISIX facilitates interface traffic handling for websites, mobile and IoT appli - Multi-platform support: APISIX can run from bare-metal machines to Kubernetes providing a vendor neutral, multi-platform solution. It also provides integration to cloud services like AWS Lambda, Azure Function, Lua functions and Apache OpenWhisk. - Fully dynamic: APISIX supports hot-reloading, meaning you don't need to restart the service to reflect changes in the configuration. - Fine-grained routing: APISIX supports using all [built-in NGINX variables](http://nginx.org/en/docs/varindex.html) for routing. You can define custom matching functions to filter requests and match Route. -- Ops-friendly: APISIX is renowned for its ops-friendliness by DevOps teams. It integrates with tools and platforms like [HashiCorp Vault](./plugins/jwt-auth.md#usage-with-hashicorp-vault), [Zipkin](./plugins/zipkin.md), [Apache SkyWalking](./plugins/skywalking.md), [Consul](./discovery/consul_kv.md), [Nacos](./discovery/nacos.md) and [Eureka](./discovery.md). With [APISIX Dashboard](https://github.com/apache/apisix-dashboard), operators can configure APISIX through an easy-to-use and intuitive UI. +- Ops-friendly: APISIX is renowned for its ops-friendliness by DevOps teams. It integrates with tools and platforms like [HashiCorp Vault](./terminology/secret.md#use-vault-to-manage-secrets), [Zipkin](./plugins/zipkin.md), [Apache SkyWalking](./plugins/skywalking.md), [Consul](./discovery/consul_kv.md), [Nacos](./discovery/nacos.md) and [Eureka](./discovery.md). With [APISIX Dashboard](https://github.com/apache/apisix-dashboard), operators can configure APISIX through an easy-to-use and intuitive UI. - Multi-language Plugin support: APISIX supports multiple programming languages for Plugin development. Developers can choose a language-specific SDK to write custom Plugins. ## Key concepts diff --git a/docs/en/latest/plugins/jwt-auth.md b/docs/en/latest/plugins/jwt-auth.md index f0b65ddcd3a4..de4064282479 100644 --- a/docs/en/latest/plugins/jwt-auth.md +++ b/docs/en/latest/plugins/jwt-auth.md @@ -33,8 +33,6 @@ The `jwt-auth` Plugin is used to add [JWT](https://jwt.io/) authentication to a A [Consumer](../terminology/consumer.md) of the service then needs to provide a key through a query string, a request header or a cookie to verify its request. -The `jwt-auth` Plugin can be integrated with [HashiCorp Vault](https://www.vaultproject.io/) to store and fetch secrets and RSA keys pairs from its [encrypted KV engine](https://www.vaultproject.io/docs/secrets/kv). Learn more from the [examples](#enable-jwt-auth-with-vault-compatibility) below. - ## Attributes For Consumer: @@ -48,19 +46,10 @@ For Consumer: | algorithm | string | False | "HS256" | ["HS256", "HS512", "RS256", "ES256"] | Encryption algorithm. | | exp | integer | False | 86400 | [1,...] | Expiry time of the token in seconds. | | base64_secret | boolean | False | false | | Set to true if the secret is base64 encoded. | -| 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. - -Refer to the Vault attributes in the default configuration file ([config-default.yaml](https://github.com/apache/apisix/blob/master/conf/config-default.yaml)) to learn more about these configurations. - -::: - For Route: | Name | Type | Required | Default | Description | @@ -70,6 +59,8 @@ For Route: | cookie | string | False | jwt | The cookie to get the token from. Lower priority than query. | | hide_credentials | boolean | False | false | Set to true will not pass the authorization request of header\query\cookie to the Upstream.| +You can implement `jwt-auth` with [HashiCorp Vault](https://www.vaultproject.io/) to store and fetch secrets and RSA keys pairs from its [encrypted KV engine](https://www.vaultproject.io/docs/secrets/kv) using the [APISIX Secret](../terminology/secret.md) resource. + ## API This Plugin adds `/apisix/plugin/jwt/sign` as an endpoint. @@ -139,88 +130,6 @@ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 }' ``` -### Usage with HashiCorp Vault - -[HashiCorp Vault](https://www.vaultproject.io/) offers a centralized key management solution and it can be used along with APISIX for authentication. - -So, if your organization frequently changes the secret/keys (secret for HS256/HS512 or public_key and private_key for RS256) and you don't want to update the APISIX consumer each time or if you don't want to use the key through the Admin API (to reduce secret sprawl), you can use Vault and the `jwt-auth` Plugin. - -:::note - -The current version of Apache APISIX expects the key names of the secrets stored in Vault to be among `secret`, `public_key`, and `private_key`. The former one is for the HS256/HS512 algorithm and the latter two are for the RS256 algorithm. - -Support for custom names will be added in a future release. - -::: - -To use Vault, you can add an empty vault object in your configuration. - -For example, if you have a stored HS256 signing secret inside Vault, you can use it in APISIX by: - -```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' -{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "key-1", - "vault": {} - } - } -}' -``` - -The Plugin will look for a key "secret" in the provided Vault path (`/consumer/jack/jwt-auth`) and uses it for JWT authentication. If the key is not found in the same path, the Plugin logs an error and JWT authentication fails. - -:::note - -The `vault.prefix` should be set in your configuration file (`conf/config.yaml`) file based on the base path you have chosen while enabling the Vault kv secret engine. - -For example, if you did `vault secrets enable -path=foobar kv`, you should use `foobar` in `vault.prefix`. - -::: - -If the key is not found in this path, the Plugin will log an error. - -And for RS256, both the public and private keys should stored in Vault and it can be configured by: - -```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' -{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "rsa-keypair", - "algorithm": "RS256", - "vault": {} - } - } -}' -``` - -The Plugin will look for keys "public_key" and "private_key" in the provided Vault path (`/consumer/jack/jwt-auth`) and uses it for JWT authentication. - -If the key is not found in this path, the Plugin will log an error. - -You can also configure the `public_key` in the Consumer configuration and use the `private_key` stored in Vault: - -```shell -curl http://127.0.0.1:9180/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' -{ - "username": "rico", - "plugins": { - "jwt-auth": { - "key": "user-key", - "algorithm": "RS256", - "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----" - "vault": {} - } - } -}' -``` - -You can also use the [APISIX Dashboard](/docs/dashboard/USER_GUIDE) to complete the operation through a web UI. - - ## 测试插件 首先,你需要为签发 token 的 API 配置一个 Route,该路由将使用 [public-api](../../../en/latest/plugins/public-api.md) 插件。 diff --git a/t/plugin/jwt-auth-vault.t b/t/plugin/jwt-auth-vault.t deleted file mode 100644 index b76c56acee47..000000000000 --- a/t/plugin/jwt-auth-vault.t +++ /dev/null @@ -1,386 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -use t::APISIX 'no_plan'; - -repeat_each(1); -no_long_string(); -no_root_location(); -no_shuffle(); - -add_block_preprocessor(sub { - my ($block) = @_; - - my $http_config = $block->http_config // <<_EOC_; - - server { - listen 8777; - - location /secure-endpoint { - content_by_lua_block { - ngx.say("successfully invoked secure endpoint") - } - } - } -_EOC_ - - $block->set_value("http_config", $http_config); - - my $vault_config = $block->extra_yaml_config // <<_EOC_; -vault: - host: "http://0.0.0.0:8200" - timeout: 10 - prefix: kv/apisix - token: root -_EOC_ - - $block->set_value("extra_yaml_config", $vault_config); - - if (!$block->request) { - $block->set_value("request", "GET /t"); - } - if (!$block->no_error_log && !$block->error_log) { - $block->set_value("no_error_log", "[error]\n[alert]"); - } -}); - -run_tests; - -__DATA__ - -=== TEST 1: schema check ---- config - location /t { - content_by_lua_block { - local plugin = require("apisix.plugins.jwt-auth") - local core = require("apisix.core") - for _, conf in ipairs({ - { - -- public and private key are not provided for RS256, returns error - key = "key-1", - algorithm = "RS256" - }, - { - -- public and private key are not provided but vault config is enabled. - key = "key-1", - algorithm = "RS256", - vault = {} - } - }) do - local ok, err = plugin.check_schema(conf, core.schema.TYPE_CONSUMER) - if not ok then - ngx.say(err) - else - ngx.say("ok") - end - end - } - } ---- response_body -failed to validate dependent schema for "algorithm": value should match only one schema, but matches none -ok - - - -=== TEST 2: create a consumer with plugin and username ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, body = t('/apisix/admin/consumers', - ngx.HTTP_PUT, - [[{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "key-hs256", - "algorithm": "HS256", - "vault":{} - } - } - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- response_body -passed - - - -=== TEST 3: enable jwt auth plugin using admin api ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, body = t('/apisix/admin/routes/1', - ngx.HTTP_PUT, - [[{ - "plugins": { - "jwt-auth": {} - }, - "upstream": { - "nodes": { - "127.0.0.1:8777": 1 - }, - "type": "roundrobin" - }, - "uri": "/secure-endpoint" - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- response_body -passed - - - -=== TEST 4: create public API route (jwt-auth sign) ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, body = t('/apisix/admin/routes/2', - ngx.HTTP_PUT, - [[{ - "plugins": { - "public-api": {} - }, - "uri": "/apisix/plugin/jwt/sign" - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- response_body -passed - - - -=== TEST 5: sign a jwt and access/verify /secure-endpoint, fails as no secret entry into vault ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=key-hs256', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/secure-endpoint?jwt=' .. sign, - ngx.HTTP_GET - ) - if code >= 300 then - ngx.status = code - end - ngx.print(res) - } - } ---- response_body -failed to sign jwt ---- error_code: 503 ---- error_log -failed to sign jwt, err: secret could not found in vault - - - -=== TEST 6: store HS256 secret into vault ---- exec -VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/consumer/jack/jwt-auth secret=$3nsitiv3-c8d3 ---- response_body -Success! Data written to: kv/apisix/consumer/jack/jwt-auth - - - -=== TEST 7: sign a HS256 jwt and access/verify /secure-endpoint ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=key-hs256', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/secure-endpoint?jwt=' .. sign, - ngx.HTTP_GET - ) - if code >= 300 then - ngx.status = code - end - ngx.print(res) - } - } ---- response_body -successfully invoked secure endpoint - - - -=== TEST 8: store rsa key pairs into vault from local filesystem ---- exec -VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/consumer/jim/jwt-auth public_key=@t/certs/public.pem private_key=@t/certs/private.pem ---- response_body -Success! Data written to: kv/apisix/consumer/jim/jwt-auth - - - -=== TEST 9: create consumer for RS256 algorithm with key pair fetched from vault ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, body = t('/apisix/admin/consumers', - ngx.HTTP_PUT, - [[{ - "username": "jim", - "plugins": { - "jwt-auth": { - "key": "rsa", - "algorithm": "RS256", - "vault":{} - } - } - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- response_body -passed - - - -=== TEST 10: sign a jwt with with rsa key pair and access /secure-endpoint ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=rsa', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/secure-endpoint?jwt=' .. sign, - ngx.HTTP_GET - ) - if code >= 300 then - ngx.status = code - end - ngx.print(res) - } - } ---- response_body -successfully invoked secure endpoint - - - -=== TEST 11: store rsa private key into vault from local filesystem ---- exec -VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/consumer/john/jwt-auth private_key=@t/certs/private.pem ---- response_body -Success! Data written to: kv/apisix/consumer/john/jwt-auth - - - -=== TEST 12: create consumer for RS256 algorithm with private key fetched from vault and public key in consumer schema ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, body = t('/apisix/admin/consumers', - ngx.HTTP_PUT, - [[{ - "username": "john", - "plugins": { - "jwt-auth": { - "key": "rsa1", - "algorithm": "RS256", - "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA79XYBopfnVMKxI533oU2\nVFQbEdSPtWRD+xSl73lHLVboGP1lSIZtnEj5AcTN2uDW6AYPiWL2iA3lEEsDTs7J\nBUXyl6pysBPfrqC8n/MOXKaD4e8U5GAHFiwHWg2WzHlfFSlFkLjzp0vPkDK+fQ4C\nlrd7shAyitB7use6DHcVCKuI4bFOoFbdI5sBGeyoD833g+ql9bRkH/vf8O+rPwHA\nM+47r1iv3lY3ex0P45PRd7U7rq8P8UIw6qOI1tiYuKlFJmjFdcwtYG0dctxWwgL1\n+7njrVQoWvuOTSsc9TDMhZkmmSsU3wXjaPxJpydck1C/w9ZLqsctKK5swYWhIcbc\nBQIDAQAB\n-----END PUBLIC KEY-----\n", - "vault":{} - } - } - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- response_body -passed - - - -=== TEST 13: sign a jwt with with rsa key pair and access /secure-endpoint ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=rsa1', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/secure-endpoint?jwt=' .. sign, - ngx.HTTP_GET - ) - if code >= 300 then - ngx.status = code - end - ngx.print(res) - } - } ---- response_body -successfully invoked secure endpoint