This is an automated email from the ASF dual-hosted git repository. tokers pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push: new 4667633 feat(stream): support client certificate verification (#4445) 4667633 is described below commit 46676333600ef91581351a1176015eff6f7a0421 Author: 罗泽轩 <spacewander...@gmail.com> AuthorDate: Sat Jun 19 10:05:00 2021 +0800 feat(stream): support client certificate verification (#4445) Signed-off-by: spacewander <spacewander...@gmail.com> --- apisix/init.lua | 24 +++-- t/stream-node/mtls.t | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+), 5 deletions(-) diff --git a/apisix/init.lua b/apisix/init.lua index 2560b30..c984656 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -303,10 +303,8 @@ local function get_upstream_by_id(up_id) end -function _M.http_access_phase() - local ngx_ctx = ngx.ctx - - if ngx_ctx.api_ctx and ngx_ctx.api_ctx.ssl_client_verified then +local function verify_tls_client(ctx) + if ctx and ctx.ssl_client_verified then local res = ngx_var.ssl_client_verify if res ~= "SUCCESS" then if res == "NONE" then @@ -314,10 +312,22 @@ function _M.http_access_phase() else core.log.error("clent certificate verification is not passed: ", res) end - return core.response.exit(400) + + return false end end + return true +end + + +function _M.http_access_phase() + local ngx_ctx = ngx.ctx + + if not verify_tls_client(ngx_ctx.api_ctx) then + return core.response.exit(400) + end + -- always fetch table from the table pool, we don't need a reused api_ctx local api_ctx = core.tablepool.fetch("api_ctx", 0, 32) ngx_ctx.api_ctx = api_ctx @@ -825,6 +835,10 @@ function _M.stream_preread_phase() local ngx_ctx = ngx.ctx local api_ctx = ngx_ctx.api_ctx + if not verify_tls_client(ngx_ctx.api_ctx) then + return ngx_exit(1) + end + if not api_ctx then api_ctx = core.tablepool.fetch("api_ctx", 0, 32) ngx_ctx.api_ctx = api_ctx diff --git a/t/stream-node/mtls.t b/t/stream-node/mtls.t new file mode 100644 index 0000000..3caad2c --- /dev/null +++ b/t/stream-node/mtls.t @@ -0,0 +1,242 @@ +# +# 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; + +my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; +my $version = eval { `$nginx_binary -V 2>&1` }; + +if ($version !~ m/\/apisix-nginx-module/) { + plan(skip_all => "apisix-nginx-module not installed"); +} else { + plan('no_plan'); +} + +repeat_each(1); + +add_block_preprocessor(sub { + my ($block) = @_; + + if ((!defined $block->error_log) && (!defined $block->no_error_log)) { + $block->set_value("no_error_log", "[error]"); + } +}); + +run_tests(); + +__DATA__ + +=== TEST 1: set client certificate +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin") + local json = require("toolkit.json") + local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt") + local ssl_cert = t.read_file("t/certs/mtls_client.crt") + local ssl_key = t.read_file("t/certs/mtls_client.key") + local data = { + upstream = { + scheme = "https", + type = "roundrobin", + nodes = { + ["127.0.0.1:2005"] = 1, + }, + tls = { + client_cert = ssl_cert, + client_key = ssl_key, + } + }, + plugins = { + ["proxy-rewrite"] = { + uri = "/hello" + } + }, + uri = "/mtls" + } + local code, body = t.test('/apisix/admin/routes/1', + ngx.HTTP_PUT, + json.encode(data) + ) + + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + local data = { + upstream = { + type = "roundrobin", + nodes = { + ["127.0.0.1:1995"] = 1, + }, + } + } + assert(t.test('/apisix/admin/stream_routes/1', + ngx.HTTP_PUT, + json.encode(data) + )) + + local data = { + cert = ssl_cert, + key = ssl_key, + sni = "localhost", + client = { + ca = ssl_ca_cert, + depth = 2, + } + } + local code, body = t.test('/apisix/admin/ssl/1', + ngx.HTTP_PUT, + json.encode(data) + ) + + if code >= 300 then + ngx.status = code + end + ngx.print(body) + } + } +--- request +GET /t + + + +=== TEST 2: hit +--- stream_enable +--- request +GET /mtls +--- more_headers +Host: localhost +--- ignore_response +--- error_log +proxy request to 127.0.0.1:2005 +proxy request to 127.0.0.1:1995 + + + +=== TEST 3: reject client without cetificate +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin") + local json = require("toolkit.json") + local ssl_cert = t.read_file("t/certs/mtls_client.crt") + local ssl_key = t.read_file("t/certs/mtls_client.key") + local data = { + upstream = { + scheme = "https", + type = "roundrobin", + nodes = { + ["127.0.0.1:2005"] = 1, + } + }, + plugins = { + ["proxy-rewrite"] = { + uri = "/hello" + } + }, + uri = "/mtls" + } + local code, body = t.test('/apisix/admin/routes/1', + ngx.HTTP_PUT, + json.encode(data) + ) + + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + ngx.print(body) + } + } +--- request +GET /t + + + +=== TEST 4: hit +--- stream_enable +--- request +GET /mtls +--- more_headers +Host: localhost +--- ignore_response +--- error_log +proxy request to 127.0.0.1:2005 +--- no_error_log +proxy request to 127.0.0.1:1995 + + + +=== TEST 5: reject client with bad cetificate +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin") + local json = require("toolkit.json") + local ssl_cert = t.read_file("t/certs/apisix.crt") + local ssl_key = t.read_file("t/certs/apisix.key") + local data = { + upstream = { + scheme = "https", + type = "roundrobin", + nodes = { + ["127.0.0.1:2005"] = 1, + }, + tls = { + client_cert = ssl_cert, + client_key = ssl_key, + } + }, + plugins = { + ["proxy-rewrite"] = { + uri = "/hello" + } + }, + uri = "/mtls" + } + local code, body = t.test('/apisix/admin/routes/1', + ngx.HTTP_PUT, + json.encode(data) + ) + + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + ngx.print(body) + } + } +--- request +GET /t + + + +=== TEST 6: hit +--- stream_enable +--- request +GET /mtls +--- more_headers +Host: localhost +--- ignore_response +--- error_log +proxy request to 127.0.0.1:2005 +--- no_error_log +proxy request to 127.0.0.1:1995