Skip to content

Commit

Permalink
Merge branch 'apache:master' into add_opentelemetry_variables
Browse files Browse the repository at this point in the history
  • Loading branch information
lework authored Mar 30, 2023
2 parents e6a677f + 508b73c commit b1bf997
Show file tree
Hide file tree
Showing 15 changed files with 497 additions and 30 deletions.
9 changes: 3 additions & 6 deletions apisix/cli/ops.lua
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,9 @@ local function init(env)
local checked_admin_key = false
local allow_admin = yaml_conf.deployment.admin and
yaml_conf.deployment.admin.allow_admin
if yaml_conf.apisix.enable_admin and allow_admin then
for _, allow_ip in ipairs(allow_admin) do
if allow_ip == "127.0.0.0/24" then
checked_admin_key = true
end
end
if yaml_conf.apisix.enable_admin and allow_admin
and #allow_admin == 1 and allow_admin[1] == "127.0.0.0/24" then
checked_admin_key = true
end

if yaml_conf.apisix.enable_admin and not checked_admin_key then
Expand Down
8 changes: 7 additions & 1 deletion apisix/core/config_util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,14 @@ function _M.cancel_clean_handler(item, idx, fire)
end

core_tab.remove(item.clean_handlers, pos)
if fire then
if not fire then
return
end

if f then
f(item)
else
log.error("The function used to clear the health checker is nil, please check")
end
end

Expand Down
41 changes: 41 additions & 0 deletions apisix/core/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,45 @@ end
_M.resolve_var = resolve_var


local resolve_var_with_captures
do
local _captures
-- escape is not supported very well, like there is a redundant '\' after escape "$1"
local pat = [[ (?<! \\) \$ \{? (\d+) \}? ]]

local function resolve(m)
local v = _captures[tonumber(m[1])]
if not v then
v = ""
end
return v
end

-- captures is the match result of regex uri in proxy-rewrite plugin
function resolve_var_with_captures(tpl, captures)
if not tpl then
return tpl, nil
end

local from = core_str.find(tpl, "$")
if not from then
return tpl, nil
end

captures = captures or {}

_captures = captures
local res, _, err = re_gsub(tpl, pat, resolve, "jox")
_captures = nil
if not res then
return nil, err
end

return res, nil
end
end
-- Resolve {$1, $2, ...} in the given string
_M.resolve_var_with_captures = resolve_var_with_captures


return _M
13 changes: 5 additions & 8 deletions apisix/plugins/cors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,6 @@ local function process_with_allow_origins(allow_origins, ctx, req_origin,
end

local function process_with_allow_origins_by_regex(conf, ctx, req_origin)
if conf.allow_origins_by_regex == nil then
return
end

if not conf.allow_origins_by_regex_rules_concat then
local allow_origins_by_regex_rules = {}
for i, re_rule in ipairs(conf.allow_origins_by_regex) do
Expand Down Expand Up @@ -293,13 +289,14 @@ end

function _M.header_filter(conf, ctx)
local req_origin = ctx.original_request_origin
-- Try allow_origins first, if mismatched, try allow_origins_by_regex.
-- If allow_origins_by_regex is not nil, should be matched to it only
local allow_origins
allow_origins = process_with_allow_origins(conf.allow_origins, ctx, req_origin)
if not match_origins(req_origin, allow_origins) then
if conf.allow_origins_by_regex == nil then
allow_origins = process_with_allow_origins(conf.allow_origins, ctx, req_origin)
else
allow_origins = process_with_allow_origins_by_regex(conf, ctx, req_origin)
end
if not allow_origins then
if not match_origins(req_origin, allow_origins) then
allow_origins = process_with_allow_origins_by_metadata(
conf.allow_origins_by_metadata, ctx, req_origin
)
Expand Down
27 changes: 22 additions & 5 deletions apisix/plugins/proxy-rewrite.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ local ipairs = ipairs
local ngx = ngx
local type = type
local re_sub = ngx.re.sub
local re_match = ngx.re.match
local sub_str = string.sub
local str_find = core.string.find

Expand All @@ -41,6 +42,10 @@ local lrucache = core.lrucache.new({
type = "plugin",
})

core.ctx.register_var("proxy_rewrite_regex_uri_captures", function(ctx)
return ctx.proxy_rewrite_regex_uri_captures
end)

local schema = {
type = "object",
properties = {
Expand Down Expand Up @@ -257,6 +262,7 @@ do
return re_sub(s, [[\?]], "%3F", "jo")
end


function _M.rewrite(conf, ctx)
for _, name in ipairs(upstream_names) do
if conf[name] then
Expand All @@ -278,15 +284,22 @@ function _M.rewrite(conf, ctx)

local uri, _, err = re_sub(upstream_uri, conf.regex_uri[1],
conf.regex_uri[2], "jo")
if uri then
upstream_uri = uri
else
if not uri then
local msg = "failed to substitute the uri " .. ctx.var.uri ..
" (" .. conf.regex_uri[1] .. ") with " ..
conf.regex_uri[2] .. " : " .. err
core.log.error(msg)
return 500, {message = msg}
end

local m, err = re_match(upstream_uri, conf.regex_uri[1], "jo")
if not m and err then
core.log.error("match error in proxy-rewrite plugin, please check: ", err)
return 500
end
ctx.proxy_rewrite_regex_uri_captures = m

upstream_uri = uri
end

if not conf.use_real_request_uri_unsafe then
Expand Down Expand Up @@ -325,14 +338,18 @@ function _M.rewrite(conf, ctx)

local field_cnt = #hdr_op.add
for i = 1, field_cnt, 2 do
local val = core.utils.resolve_var(hdr_op.add[i + 1], ctx.var)
local val = core.utils.resolve_var_with_captures(hdr_op.add[i + 1],
ctx.proxy_rewrite_regex_uri_captures)
val = core.utils.resolve_var(val, ctx.var)
local header = hdr_op.add[i]
core.request.add_header(ctx, header, val)
end

local field_cnt = #hdr_op.set
for i = 1, field_cnt, 2 do
local val = core.utils.resolve_var(hdr_op.set[i + 1], ctx.var)
local val = core.utils.resolve_var_with_captures(hdr_op.set[i + 1],
ctx.proxy_rewrite_regex_uri_captures)
val = core.utils.resolve_var(val, ctx.var)
core.request.set_header(ctx, hdr_op.set[i], val)
end

Expand Down
17 changes: 15 additions & 2 deletions apisix/upstream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ local error = error
local tostring = tostring
local ipairs = ipairs
local pairs = pairs
local pcall = pcall
local ngx_var = ngx.var
local is_http = ngx.config.subsystem == "http"
local upstreams
Expand Down Expand Up @@ -103,6 +104,12 @@ local function create_checker(upstream)
return healthcheck_parent.checker
end

if upstream.is_creating_checker then
core.log.info("another request is creating new checker")
return nil
end
upstream.is_creating_checker = true

local checker, err = healthcheck.new({
name = get_healthchecker_name(healthcheck_parent),
shm_name = "upstream-healthcheck",
Expand All @@ -111,20 +118,24 @@ local function create_checker(upstream)

if not checker then
core.log.error("fail to create healthcheck instance: ", err)
upstream.is_creating_checker = nil
return nil
end

if healthcheck_parent.checker then
core.config_util.cancel_clean_handler(healthcheck_parent,
local ok, err = pcall(core.config_util.cancel_clean_handler, healthcheck_parent,
healthcheck_parent.checker_idx, true)
if not ok then
core.log.error("cancel clean handler error: ", err)
end
end

core.log.info("create new checker: ", tostring(checker))

local host = upstream.checks and upstream.checks.active and upstream.checks.active.host
local port = upstream.checks and upstream.checks.active and upstream.checks.active.port
local up_hdr = upstream.pass_host == "rewrite" and upstream.upstream_host
local use_node_hdr = upstream.pass_host == "node"
local use_node_hdr = upstream.pass_host == "node" or nil
for _, node in ipairs(upstream.nodes) do
local host_hdr = up_hdr or (use_node_hdr and node.domain)
local ok, err = checker:add_target(node.host, port or node.port, host,
Expand All @@ -140,6 +151,8 @@ local function create_checker(upstream)
healthcheck_parent.checker_idx =
core.config_util.add_clean_handler(healthcheck_parent, release_checker)

upstream.is_creating_checker = nil

return checker
end

Expand Down
9 changes: 7 additions & 2 deletions docs/en/latest/mtls.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
title: Mutual TLS Authentication
keywords:
- Apache APISIX
- Mutual TLS
- mTLS
description: This document describes how you can secure communication to and within APISIX with mTLS.
---

<!--
Expand Down Expand Up @@ -68,7 +73,7 @@ curl --cacert /data/certs/mtls_ca.crt --key /data/certs/mtls_client.key --cert /

### How to configure

You need to build [APISIX-Base](./FAQ.md#how-do-i-build-the-apisix-base-environment) and configure `etcd.tls` section if you want APISIX to work on an etcd cluster with mTLS enabled.
You need to configure `etcd.tls` for APISIX to work on an etcd cluster with mTLS enabled as shown below:

```yaml title="conf/config.yaml"
deployment:
Expand Down Expand Up @@ -163,7 +168,7 @@ Sometimes the upstream requires mTLS. In this situation, the APISIX acts as the

When configuring `upstreams`, we could use parameter `tls.client_cert` and `tls.client_key` to configure the client certificate APISIX used to communicate with upstreams. Please refer to [Admin API](./admin-api.md#upstream) for details.

This feature requires APISIX to run on [APISIX-Base](./FAQ/#how-do-i-build-the-apisix-base-environment).
This feature requires APISIX to run on [APISIX-Base](./FAQ.md#how-do-i-build-the-apisix-base-environment).

Here is a similar Python script to patch a existed upstream with mTLS (changes admin API url if needed):

Expand Down
2 changes: 1 addition & 1 deletion docs/en/latest/plugins/cors.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The `cors` Plugins lets you enable [CORS](https://developer.mozilla.org/en-US/do
| expose_headers | string | False | "*" | Headers in the response allowed when accessing a cross-origin resource. Use `,` to add multiple headers. If `allow_credential` is set to `false`, you can enable CORS for all response headers by using `*`. If `allow_credential` is set to `true`, you can forcefully allow CORS on all response headers by using `**` but it will pose some security issues. |
| max_age | integer | False | 5 | Maximum time in seconds the result is cached. If the time is within this limit, the browser will check the cached result. Set to `-1` to disable caching. Note that the maximum value is browser dependent. See [Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives) for more details. |
| allow_credential | boolean | False | false | When set to `true`, allows requests to include credentials like cookies. According to CORS specification, if you set this to `true`, you cannot use '*' to allow all for the other attributes. |
| allow_origins_by_regex | array | False | nil | Regex to match with origin for enabling CORS. For example, `[".*\.test.com"]` can match all subdomain of `test.com`. |
| allow_origins_by_regex | array | False | nil | Regex to match with origin for enabling CORS. For example, `[".*\.test.com"]` can match all subdomain of `test.com`. When set to specified range, only domains in this range will be allowed, no matter what `allow_origins` is. |
| allow_origins_by_metadata | array | False | nil | Origins to enable CORS referenced from `allow_origins` set in the Plugin metadata. For example, if `"allow_origins": {"EXAMPLE": "https://example.com"}` is set in the Plugin metadata, then `["EXAMPLE"]` can be used to allow CORS on the origin `https://example.com`. |

:::info IMPORTANT
Expand Down
4 changes: 2 additions & 2 deletions docs/en/latest/plugins/proxy-rewrite.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ The `proxy-rewrite` Plugin rewrites Upstream proxy information such as `scheme`,
| regex_uri | array[string] | False | | | New upstream forwarding address. Regular expressions can be used to match the URL from client. If it matches, the URL template is forwarded to the Upstream otherwise, the URL from the client is forwarded. When both `uri` and `regex_uri` are configured, `uri` is used first. For example, `[" ^/iresty/(.*)/(.*)/(.*)", "/$1-$2-$3"]`. Here, the first element is the regular expression to match and the second element is the URL template forwarded to the Upstream. |
| host | string | False | | | New Upstream host address. |
| headers | object | False | | | |
| headers.add | object | false | | | Append the new headers. The format is `{"name: value",...}`. The values in the header can contain Nginx variables like $remote_addr and $balancer_ip. |
| headers.set | object | false | | | Overwrite the headers. If the header does not exist, it will be added. The format is `{"name": "value", ...}`. The values in the header can contain Nginx variables like $remote_addr and $balancer_ip. |
| headers.add | object | false | | | Append the new headers. The format is `{"name: value",...}`. The values in the header can contain Nginx variables like `$remote_addr` and `$balancer_ip`. It also supports referencing the match result of `regex_uri` as a variable like `$1-$2-$3`. |
| headers.set | object | false | | | Overwrite the headers. If the header does not exist, it will be added. The format is `{"name": "value", ...}`. The values in the header can contain Nginx variables like `$remote_addr` and `$balancer_ip`. It also supports referencing the match result of `regex_uri` as a variable like `$1-$2-$3`. |
| headers.remove | array | false | | | Remove the headers. The format is `["name", ...]`.
| use_real_request_uri_unsafe | boolean | False | false | | Use real_request_uri (original $request_uri in nginx) to bypass URI normalization. **Enabling this is considered unsafe as it bypasses all URI normalization steps**. |

Expand Down
2 changes: 1 addition & 1 deletion docs/zh/latest/plugins/cors.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ description: 本文介绍了 Apache APISIX cors 插件的基本信息及使用
| expose_headers | string || "*" | 允许跨域访问时响应方携带哪些非 `CORS 规范` 以外的 Header。如果你有多个 Header,请使用 `,` 分割。当 `allow_credential``false` 时,可以使用 `*` 来表示允许任意 Header 。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许任意 Header,但请注意这样存在安全隐患。 |
| max_age | integer || 5 | 浏览器缓存 CORS 结果的最大时间,单位为秒。在这个时间范围内,浏览器会复用上一次的检查结果,`-1` 表示不缓存。请注意各个浏览器允许的最大时间不同,详情请参考 [Access-Control-Max-Age - MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#directives)|
| allow_credential | boolean || false | 是否允许跨域访问的请求方携带凭据(如 Cookie 等)。根据 CORS 规范,如果设置该选项为 `true`,那么将不能在其他属性中使用 `*`|
| allow_origins_by_regex | array || nil | 使用正则表达式数组来匹配允许跨域访问的 Origin,如 `[".*\.test.com"]` 可以匹配任何 `test.com` 的子域名 `*`|
| allow_origins_by_regex | array || nil | 使用正则表达式数组来匹配允许跨域访问的 Origin,如 `[".*\.test.com"]` 可以匹配任何 `test.com` 的子域名 `*`如果 `allow_origins_by_regex` 属性已经指定,则会忽略 `allow_origins` 属性。 |
| allow_origins_by_metadata | array || nil | 通过引用插件元数据的 `allow_origins` 配置允许跨域访问的 Origin。比如当插件元数据为 `"allow_origins": {"EXAMPLE": "https://example.com"}` 时,配置 `["EXAMPLE"]` 将允许 Origin `https://example.com` 的访问。 |

:::info IMPORTANT
Expand Down
Loading

0 comments on commit b1bf997

Please sign in to comment.