This is an automated email from the ASF dual-hosted git repository. spacewander 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 089e8a218 feat(deployment): support connecting to etcd via https (#7269) 089e8a218 is described below commit 089e8a2181cb9872e1be239cafdb60b4f930e347 Author: 罗泽轩 <spacewander...@gmail.com> AuthorDate: Mon Jun 20 14:24:17 2022 +0800 feat(deployment): support connecting to etcd via https (#7269) --- .github/workflows/build.yml | 2 +- .github/workflows/centos7-ci.yml | 2 +- apisix/cli/file.lua | 8 --- apisix/cli/ngx_tpl.lua | 2 +- apisix/cli/ops.lua | 5 +- apisix/cli/schema.lua | 5 +- apisix/cli/snippet.lua | 42 ++++++++++----- apisix/core/etcd.lua | 42 +++++++++++---- t/bin/gen_snippet.lua | 51 ++++++++++++++++++ t/cli/test_deployment_traditional.sh | 20 +++++++ t/deployment/conf_server.t | 100 +++++++++++++++++++++++++++++++++++ 11 files changed, 243 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd199672e..6834d8651 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ jobs: - linux_openresty_1_17 test_dir: - t/plugin - - t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misc + - t/admin t/cli t/config-center-yaml t/control t/core t/debug t/deployment t/discovery t/error_page t/misc - t/node t/pubsub t/router t/script t/stream-node t/utils t/wasm t/xds-library t/xrpc runs-on: ${{ matrix.platform }} diff --git a/.github/workflows/centos7-ci.yml b/.github/workflows/centos7-ci.yml index 9b2f8fc81..589e5ed69 100644 --- a/.github/workflows/centos7-ci.yml +++ b/.github/workflows/centos7-ci.yml @@ -29,7 +29,7 @@ jobs: matrix: test_dir: - t/plugin - - t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misc + - t/admin t/cli t/config-center-yaml t/control t/core t/debug t/deployment t/discovery t/error_page t/misc - t/node t/pubsub t/router t/script t/stream-node t/utils t/wasm t/xds-library steps: diff --git a/apisix/cli/file.lua b/apisix/cli/file.lua index 5bd64a682..66600b54b 100644 --- a/apisix/cli/file.lua +++ b/apisix/cli/file.lua @@ -237,14 +237,6 @@ function _M.read_yaml_conf(apisix_home) end end - if default_conf.deployment - and default_conf.deployment.role == "traditional" - and default_conf.deployment.etcd - then - default_conf.etcd = default_conf.deployment.etcd - default_conf.etcd.unix_socket_proxy = "unix:./conf/config_listen.sock" - end - if default_conf.apisix.config_center == "yaml" then local apisix_conf_path = profile:yaml_path("apisix") local apisix_conf_yaml, _ = util.read_file(apisix_conf_path) diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua index 161c530b8..f22280766 100644 --- a/apisix/cli/ngx_tpl.lua +++ b/apisix/cli/ngx_tpl.lua @@ -64,7 +64,7 @@ lua { {% end %} } -{% if (enabled_stream_plugins["prometheus"] or conf_server) and not enable_http then %} +{% if enabled_stream_plugins["prometheus"] and not enable_http then %} http { {% if enabled_stream_plugins["prometheus"] then %} init_worker_by_lua_block { diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua index 3e933ddd3..9a275648e 100644 --- a/apisix/cli/ops.lua +++ b/apisix/cli/ops.lua @@ -540,7 +540,10 @@ Please modify "admin_key" in conf/config.yaml . proxy_mirror_timeouts = yaml_conf.plugin_attr["proxy-mirror"].timeout end - local conf_server = snippet.generate_conf_server(yaml_conf) + local conf_server, err = snippet.generate_conf_server(env, yaml_conf) + if err then + util.die(err, "\n") + end -- Using template.render local sys_conf = { diff --git a/apisix/cli/schema.lua b/apisix/cli/schema.lua index ab053a0a7..db4f47477 100644 --- a/apisix/cli/schema.lua +++ b/apisix/cli/schema.lua @@ -43,7 +43,7 @@ local etcd_schema = { key = { type = "string", }, - } + }, }, prefix = { type = "string", @@ -54,7 +54,8 @@ local etcd_schema = { items = { type = "string", pattern = [[^https?://]] - } + }, + minItems = 1, } }, required = {"prefix", "host"} diff --git a/apisix/cli/snippet.lua b/apisix/cli/snippet.lua index 014719511..191e3b0ed 100644 --- a/apisix/cli/snippet.lua +++ b/apisix/cli/snippet.lua @@ -22,19 +22,31 @@ local ipairs = ipairs local _M = {} -function _M.generate_conf_server(conf) +function _M.generate_conf_server(env, conf) if not (conf.deployment and conf.deployment.role == "traditional") then - return nil + return nil, nil end -- we use proxy even the role is traditional so that we can test the proxy in daily dev - local servers = conf.deployment.etcd.host + local etcd = conf.deployment.etcd + local servers = etcd.host + local enable_https = false + local prefix = "https://" + if servers[1]:find(prefix, 1, true) then + enable_https = true + end + -- there is not a compatible way to verify upstream TLS like the one we do in cosocket + -- so here we just ignore it as the verification is already done in the init phase for i, s in ipairs(servers) do - local prefix = "http://" - -- TODO: support https - if s:find(prefix, 1, true) then - servers[i] = s:sub(#prefix + 1) + if (s:find(prefix, 1, true) ~= nil) ~= enable_https then + return nil, "all nodes in the etcd cluster should enable/disable TLS together" + end + + local _, to = s:find("://", 1, true) + if not to then + return nil, "bad etcd endpoint format" end + servers[i] = s:sub(to + 1) end local conf_render = template.compile([[ @@ -44,12 +56,16 @@ function _M.generate_conf_server(conf) {% end %} } server { - listen unix:./conf/config_listen.sock; + listen unix:{* home *}/conf/config_listen.sock; access_log off; location / { - set $upstream_scheme 'http'; - - proxy_pass $upstream_scheme://apisix_conf_backend; + {% if enable_https then %} + proxy_pass https://apisix_conf_backend; + proxy_ssl_server_name on; + proxy_ssl_protocols TLSv1.2 TLSv1.3; + {% else %} + proxy_pass http://apisix_conf_backend; + {% end %} proxy_http_version 1.1; proxy_set_header Connection ""; @@ -57,7 +73,9 @@ function _M.generate_conf_server(conf) } ]]) return conf_render({ - servers = servers + servers = servers, + enable_https = enable_https, + home = env.apisix_home or ".", }) end diff --git a/apisix/core/etcd.lua b/apisix/core/etcd.lua index 9d289bd5d..274b3a9d8 100644 --- a/apisix/core/etcd.lua +++ b/apisix/core/etcd.lua @@ -19,15 +19,19 @@ -- -- @module core.etcd -local fetch_local_conf = require("apisix.core.config_local").local_conf -local array_mt = require("apisix.core.json").array_mt -local etcd = require("resty.etcd") -local clone_tab = require("table.clone") -local health_check = require("resty.etcd.health_check") -local ipairs = ipairs -local setmetatable = setmetatable -local string = string -local tonumber = tonumber +local fetch_local_conf = require("apisix.core.config_local").local_conf +local array_mt = require("apisix.core.json").array_mt +local etcd = require("resty.etcd") +local clone_tab = require("table.clone") +local health_check = require("resty.etcd.health_check") +local ipairs = ipairs +local setmetatable = setmetatable +local string = string +local tonumber = tonumber +local ngx_config_prefix = ngx.config.prefix() + + +local is_http = ngx.config.subsystem == "http" local _M = {} @@ -38,7 +42,25 @@ local function new() return nil, nil, err end - local etcd_conf = clone_tab(local_conf.etcd) + local etcd_conf + + if local_conf.deployment + and local_conf.deployment.role == "traditional" + -- we proxy the etcd requests in traditional mode so we can test the CP's behavior in + -- daily development. However, a stream proxy can't be the CP. + -- Hence, generate a HTTP conf server to proxy etcd requests in stream proxy is + -- unnecessary and inefficient. + and is_http + then + local sock_prefix = ngx_config_prefix + etcd_conf = clone_tab(local_conf.deployment.etcd) + etcd_conf.unix_socket_proxy = + "unix:" .. sock_prefix .. "/conf/config_listen.sock" + etcd_conf.host = {"http://127.0.0.1:2379"} + else + etcd_conf = clone_tab(local_conf.etcd) + end + local prefix = etcd_conf.prefix etcd_conf.http_host = etcd_conf.host etcd_conf.host = nil diff --git a/t/bin/gen_snippet.lua b/t/bin/gen_snippet.lua new file mode 100755 index 000000000..085409b6b --- /dev/null +++ b/t/bin/gen_snippet.lua @@ -0,0 +1,51 @@ +#!/usr/bin/env luajit +-- +-- 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. +-- +-- this script generates Nginx configuration in the test +-- so we can test some features with test-nginx +local pkg_cpath_org = package.cpath +local pkg_path_org = package.path +local pkg_cpath = "deps/lib64/lua/5.1/?.so;deps/lib/lua/5.1/?.so;" +local pkg_path = "deps/share/lua/5.1/?.lua;" +-- modify the load path to load our dependencies +package.cpath = pkg_cpath .. pkg_cpath_org +package.path = pkg_path .. pkg_path_org + + +local file = require("apisix.cli.file") +local schema = require("apisix.cli.schema") +local snippet = require("apisix.cli.snippet") +local yaml_conf, err = file.read_yaml_conf("t/servroot") +if not yaml_conf then + error(err) +end +local ok, err = schema.validate(yaml_conf) +if not ok then + error(err) +end + +local res, err +if arg[1] == "conf_server" then + res, err = snippet.generate_conf_server( + {apisix_home = "t/servroot/"}, + yaml_conf) +end + +if not res then + error(err or "none") +end +print(res) diff --git a/t/cli/test_deployment_traditional.sh b/t/cli/test_deployment_traditional.sh index f6d7d62c9..895675118 100755 --- a/t/cli/test_deployment_traditional.sh +++ b/t/cli/test_deployment_traditional.sh @@ -111,3 +111,23 @@ if grep '\[error\]' logs/error.log; then fi echo "passed: could connect to etcd" + +echo ' +deployment: + role: traditional + role_traditional: + config_provider: etcd + etcd: + prefix: "/apisix" + host: + - http://127.0.0.1:2379 + - https://127.0.0.1:2379 +' > conf/config.yaml + +out=$(make init 2>&1 || true) +if ! echo "$out" | grep 'all nodes in the etcd cluster should enable/disable TLS together'; then + echo "failed: should validate etcd host" + exit 1 +fi + +echo "passed: validate etcd host" diff --git a/t/deployment/conf_server.t b/t/deployment/conf_server.t new file mode 100644 index 000000000..84b045055 --- /dev/null +++ b/t/deployment/conf_server.t @@ -0,0 +1,100 @@ +# +# 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/\/1.17.8/) { + plan(skip_all => "require OpenResty 1.19+"); +} else { + plan('no_plan'); +} + +add_block_preprocessor(sub { + my ($block) = @_; + + if (!$block->request) { + $block->set_value("request", "GET /t"); + } + + if ((!defined $block->error_log) && (!defined $block->no_error_log)) { + $block->set_value("no_error_log", "[error]"); + } + +}); + +Test::Nginx::Socket::set_http_config_filter(sub { + my $config = shift; + my $snippet = `./t/bin/gen_snippet.lua conf_server`; + $config .= $snippet; + return $config; +}); + +run_tests(); + +__DATA__ + +=== TEST 1: sync in https +--- config + location /t { + content_by_lua_block { + local core = require("apisix.core") + local t = require("lib.test_admin").test + + local consumers, _ = core.config.new("/consumers", { + automatic = true, + item_schema = core.schema.consumer, + }) + + ngx.sleep(0.6) + local idx = consumers.prev_index + + local code, body = t('/apisix/admin/consumers', + ngx.HTTP_PUT, + [[{ + "username": "jobs", + "plugins": { + "basic-auth": { + "username": "jobs", + "password": "678901" + } + } + }]]) + + ngx.sleep(2) + local new_idx = consumers.prev_index + if new_idx > idx then + ngx.say("prev_index updated") + else + ngx.say("prev_index not update") + end + } + } +--- response_body +prev_index updated +--- extra_yaml_config +deployment: + role: traditional + role_traditional: + config_provider: etcd + etcd: + prefix: "/apisix" + host: + - https://127.0.0.1:12379 + tls: + verify: false