[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-12 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r767475036



##
File path: t/plugin/jwt-auth-vault.t
##
@@ -39,6 +39,16 @@ _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);
+

Review comment:
   LGTM




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-12 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r767416526



##
File path: t/plugin/jwt-auth-vault.t
##
@@ -0,0 +1,381 @@
+#
+# 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);
+
+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: sign a jwt and access/verify /secure-endpoint, fails as no secret 
entry into vault
+--- extra_yaml_config
+vault:
+  host: "http://0.0.0.0:8200;
+  timeout: 10
+  prefix: kv/apisix
+  token: root
+#END
+--- 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
+

[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-12 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r767363371



##
File path: t/plugin/jwt-auth-vault.t
##
@@ -163,6 +148,13 @@ passed
 
 
 === TEST 4: sign a jwt and access/verify /secure-endpoint, fails as no secret 
entry into vault
+--- yaml_config

Review comment:
   We can share the config via extra_yaml_config
   See 
https://github.com/apache/apisix/blob/71c256be81d95d56ea38f9874699801cbbad6a2e/t/plugin/ext-plugin/http-req-call.t#L47




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-12 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r767266639



##
File path: t/plugin/jwt-auth-vault.t
##
@@ -0,0 +1,368 @@
+#
+# 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);
+
+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":{}
+}
+}
+}]],
+[[{

Review comment:
   Could we remove the expected response? We don't need to check this 
output anymore. More other tests already do it.

##
File path: conf/config-default.yaml
##
@@ -281,6 +281,17 @@ etcd:
   # the default value is true, e.g. the 
certificate will be verified strictly.
 #sni: # the SNI for etcd TLS requests. If missed, 
the host part of the URL will be used.
 
+# storage backend for sensitive data storage and retrieval
+vault:

Review comment:
   Err. Actually, I mean like this :
   ```
   #vault:
 # ...
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-10 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r766469765



##
File path: t/plugin/jwt-auth-vault.t
##
@@ -0,0 +1,369 @@
+#
+# 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);
+
+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 - if public and private key are not provided for RS256
+--- config
+location /t {
+content_by_lua_block {
+local plugin = require("apisix.plugins.jwt-auth")
+local core = require("apisix.core")
+local conf = {
+key = "key-1",
+algorithm = "RS256"
+}
+
+local ok, err = plugin.check_schema(conf, 
core.schema.TYPE_CONSUMER)

Review comment:
We can use table drive test for check_schema. You can take this as an 
example: 
https://github.com/apache/apisix/blob/c178435d7ada4eeb713d9a1688fb5f54f971abdf/t/plugin/gzip.t#L494

##
File path: docs/en/latest/plugins/jwt-auth.md
##
@@ -51,6 +55,9 @@ For more information on JWT, refer to [JWT](https://jwt.io/) 
for more informatio
 | algorithm | string  | optional| "HS256" | ["HS256", "HS512", 
"RS256"] | encryption algorithm.
|
 | exp   | integer | optional| 86400   | [1,...]
 | token's expire time, in seconds  
|
 | base64_secret | boolean | optional| false   |
 | whether secret is base64 encoded 
|
+| vault | dictionary | optional|| | 
whether vault to be used for secret (secret for HS256/HS512  or public_key and 
private_key for RS256) storage and retrieval. The plugin by default uses the 
vault path as `kv/apisix/jwt-auth/keys/` for secret retrieval. |

Review comment:
   ```suggestion
   | vault | object | optional|| | whether 
vault to be used for secret (secret for HS256/HS512  or public_key and 
private_key for RS256) storage and retrieval. The plugin by default uses the 
vault path as `kv/apisix/jwt-auth/keys/` for secret retrieval. |
   ```

##
File path: apisix/plugins/jwt-auth.lua
##
@@ -28,7 +29,7 @@ local ngx_time = ngx.time
 local sub_str  = string.sub
 local plugin_name = "jwt-auth"
 local pcall = pcall
-
+local jwt_vault_prefix = "jwt-auth/keys/"

Review comment:
   What about changing it to `consumer//jwt-auth/`?
   I think about it several times. Although it requires to change several 
places in this PR, the new format is more extendable, and easier to recognize. 
People will remember the username better than the key.

##
File path: docs/en/latest/plugins/jwt-auth.md
##
@@ -51,6 +55,9 @@ For more information on JWT, refer to [JWT](https://jwt.io/) 
for more informatio
 | algorithm | string  | optional| "HS256" | ["HS256", "HS512", 
"RS256"] | encryption algorithm.
|
 | exp   | integer | optional| 86400   | [1,...]
 | token's expire time, in seconds  
   

[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-09 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r766274062



##
File path: apisix/plugins/jwt-auth.lua
##
@@ -76,7 +84,23 @@ local consumer_schema = {
 },
 },
 required = {"public_key", "private_key"},
-}
+},
+{
+properties = {
+vault = {
+type = "object",
+properties = {
+path = {type = "string"},
+add_prefix = {type = "boolean"}

Review comment:
   Please remove the path & add_prefix, which is too flexible, and made 
future evolution harder. Let's be strict from the beginning. It's easier to 
relax the rule than be more strict with the rule. If people really need this 
feature, we can add it at that time.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-08 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r765465329



##
File path: apisix/plugins/jwt-auth.lua
##
@@ -119,29 +143,74 @@ function _M.check_schema(conf, schema_type)
 if schema_type == core.schema.TYPE_CONSUMER then
 ok, err = core.schema.check(consumer_schema, conf)
 else
-ok, err = core.schema.check(schema, conf)
+return core.schema.check(schema, conf)
 end
 
 if not ok then
 return false, err
 end
 
-if schema_type == core.schema.TYPE_CONSUMER then
-if conf.algorithm ~= "RS256" and not conf.secret then
-conf.secret = ngx_encode_base64(resty_random.bytes(32, true))
+-- in nginx init_worker_by_lua context API calls are disabled,
+-- also that is a costly operation during system startup.
+if ngx.get_phase() == "init_worker" then

Review comment:
   > The full sync is done in apisix startup that is init_worker_by_lua 
phase.
   
   Not exactly. The full sync can happen elsewhere like the data in etcd is 
compacted.
   BTW, even the sync timer is triggered in the init_worker_by_lua, it runs in 
a separate "timer" phase. Currently, there is no way to distinguish a DP side 
check_schema out of the CP side.
   
   Even we have successfully checked the data, its benefit is limited. Maybe we 
can just leave a note in the doc?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-08 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r765462264



##
File path: apisix/plugins/jwt-auth.lua
##
@@ -76,7 +84,23 @@ local consumer_schema = {
 },
 },
 required = {"public_key", "private_key"},
-}
+},
+{
+properties = {
+vault = {
+type = "object",
+properties = {
+path = {type = "string"},
+add_prefix = {type = "boolean"}

Review comment:
   There are two cases people what to set a common path (or ref):
   1. they already have the data under another key
   2. they want to share the same data among configurations
   
For reason 1, since we already enforce the attributes name (secret, public 
key, .etc), it is not suitable to reuse the data format. And we may add new 
attribute requirements, which might conflict with the data already there.
   
   For reason 2, it is quite strange to share the same configuration among 
consumers. Maybe we can add this feature when it's needed. (More features 
require more doc & test, and more bugs sometimes).
   
   > Do you mean vault namespace? That's an enterprise feature [even I can't 
test it], we can look into it in the next version. WDYT?
   
   Sorry for misleading you. Actually, I mean the keys can have a common 
prefix, like `/kv/apisix/`, which is easier to recognize and manage.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-08 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r765460002



##
File path: apisix/admin/consumers.lua
##
@@ -102,6 +103,33 @@ function _M.get(consumer_name)
 end
 
 utils.fix_count(res.body, consumer_name)
+
+if consumer_name then
+-- if data is queried for a single consumer, and there is any plugin 
where the vault config
+-- is enabled - it fetches vault data and returns combined with etcd 
response.

Review comment:
   I think we can remove it.
   
   BTW, when people store their data in protection storage, easier to access or 
can be written is no longer a plus for them. Restriction access is more helpful.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org




[GitHub] [apisix] spacewander commented on a change in pull request #5745: feat(vault): vault lua module, integration with jwt-auth authentication plugin

2021-12-08 Thread GitBox


spacewander commented on a change in pull request #5745:
URL: https://github.com/apache/apisix/pull/5745#discussion_r765369332



##
File path: apisix/plugins/jwt-auth.lua
##
@@ -76,7 +84,23 @@ local consumer_schema = {
 },
 },
 required = {"public_key", "private_key"},
-}
+},
+{
+properties = {
+vault = {
+type = "object",
+properties = {
+path = {type = "string"},
+add_prefix = {type = "boolean"}

Review comment:
   We should not allow users to specify path & add_prefix in the MVP, which 
will make thing very complex.
   First, people may make mistakes, like using the same path according to 
multiple consumers.
   Second, we need to enforce users to put their data under the same namespace, 
so we can provide a consistent token for APISIX to read the data.

##
File path: apisix/admin/consumers.lua
##
@@ -102,6 +103,33 @@ function _M.get(consumer_name)
 end
 
 utils.fix_count(res.body, consumer_name)
+
+if consumer_name then
+-- if data is queried for a single consumer, and there is any plugin 
where the vault config
+-- is enabled - it fetches vault data and returns combined with etcd 
response.

Review comment:
   IMHO, it is not a good idea to merge the vault data with etcd response. 
Now everyone who can access Admin API could access the vault data, which is 
against the reason to use vault.

##
File path: apisix/plugins/jwt-auth.lua
##
@@ -198,7 +312,11 @@ end
 
 
 local function sign_jwt_with_HS(key, auth_conf, payload)
-local auth_secret = get_secret(auth_conf)
+local auth_secret, err = get_secret(auth_conf)
+if not auth_secret then
+core.log.error("failed to sign jwt, err: ", err)
+core.response.exit(500, "failed to sign jwt")

Review comment:
   ```suggestion
   core.response.exit(503, "failed to sign jwt")
   ```
   
   Use 503 for known failure.

##
File path: apisix/core/vault.lua
##
@@ -0,0 +1,116 @@
+--
+-- 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.
+--
+
+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, rel_path, 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 rel_path then
+req_addr = req_addr .. norm_path("/v1/"
+.. vault.prefix .. "/" .. key)
+else
+req_addr = req_addr .. norm_path("/" .. 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
+local function get(key, rel_path)
+core.log.info("fetching data from vault for key: ", key)
+
+local res, err = make_request_to_vault("GET", key, rel_path)
+if not res or err 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 vaule pair
+local function set(key, data,