Skip to content

Commit

Permalink
feat: support host level dynamic setting of tls protocol version (#9903)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlinsRan authored Aug 4, 2023
1 parent f99cf54 commit a4038d5
Show file tree
Hide file tree
Showing 18 changed files with 1,184 additions and 11 deletions.
4 changes: 4 additions & 0 deletions apisix/cli/ngx_tpl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,10 @@ http {
}
{% if ssl.enable then %}
ssl_client_hello_by_lua_block {
apisix.http_ssl_client_hello_phase()
}
ssl_certificate_by_lua_block {
apisix.http_ssl_phase()
}
Expand Down
29 changes: 28 additions & 1 deletion apisix/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,31 @@ end


function _M.http_ssl_phase()
local ok, err = router.router_ssl.set(ngx.ctx.matched_ssl)
if not ok then
if err then
core.log.error("failed to fetch ssl config: ", err)
end
ngx_exit(-1)
end
end


function _M.http_ssl_client_hello_phase()
local sni, err = apisix_ssl.server_name(true)
if not sni or type(sni) ~= "string" then
local advise = "please check if the client requests via IP or uses an outdated " ..
"protocol. If you need to report an issue, " ..
"provide a packet capture file of the TLS handshake."
core.log.error("failed to find SNI: " .. (err or advise))
ngx_exit(-1)
end

local ngx_ctx = ngx.ctx
local api_ctx = core.tablepool.fetch("api_ctx", 0, 32)
ngx_ctx.api_ctx = api_ctx

local ok, err = router.router_ssl.match_and_set(api_ctx)
local ok, err = router.router_ssl.match_and_set(api_ctx, true, sni)

ngx_ctx.matched_ssl = api_ctx.matched_ssl
core.tablepool.release("api_ctx", api_ctx)
Expand All @@ -192,6 +212,13 @@ function _M.http_ssl_phase()
if err then
core.log.error("failed to fetch ssl config: ", err)
end
core.log.error("failed to match any SSL certificate by SNI: ", sni)
ngx_exit(-1)
end

ok, err = apisix_ssl.set_protocols_by_clienthello(ngx_ctx.matched_ssl.value.ssl_protocols)
if not ok then
core.log.error("failed to set ssl protocols: ", err)
ngx_exit(-1)
end
end
Expand Down
9 changes: 9 additions & 0 deletions apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,15 @@ _M.ssl = {
enum = {1, 0},
default = 1
},
ssl_protocols = {
description = "set ssl protocols",
type = "array",
maxItems = 3,
uniqueItems = true,
items = {
enum = {"TLSv1.1", "TLSv1.2", "TLSv1.3"}
},
},
validity_end = timestamp_def,
validity_start = timestamp_def,
create_time = timestamp_def,
Expand Down
25 changes: 20 additions & 5 deletions apisix/ssl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core = require("apisix.core")
local ngx_ssl = require("ngx.ssl")
local secret = require("apisix.secret")
local core = require("apisix.core")
local secret = require("apisix.secret")
local ngx_ssl = require("ngx.ssl")
local ngx_ssl_client = require("ngx.ssl.clienthello")

local ngx_encode_base64 = ngx.encode_base64
local ngx_decode_base64 = ngx.decode_base64
local aes = require("resty.aes")
Expand All @@ -38,8 +40,13 @@ local pkey_cache = core.lrucache.new {
local _M = {}


function _M.server_name()
local sni, err = ngx_ssl.server_name()
function _M.server_name(clienthello)
local sni, err
if clienthello then
sni, err = ngx_ssl_client.get_client_hello_server_name()
else
sni, err = ngx_ssl.server_name()
end
if err then
return nil, err
end
Expand All @@ -57,6 +64,14 @@ function _M.server_name()
end


function _M.set_protocols_by_clienthello(ssl_protocols)
if ssl_protocols then
return ngx_ssl_client.set_protocols(ssl_protocols)
end
return true
end


local function init_iv_tbl(ivs)
local _aes_128_cbc_with_iv_tbl = core.table.new(2, 0)
local type_ivs = type(ivs)
Expand Down
26 changes: 24 additions & 2 deletions apisix/ssl/router/radixtree_sni.lua
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,35 @@ function _M.match_and_set(api_ctx, match_only, alt_sni)
end
end

local matched_ssl = api_ctx.matched_ssl
core.log.info("debug - matched: ", core.json.delay_encode(matched_ssl, true))
core.log.info("debug - matched: ", core.json.delay_encode(api_ctx.matched_ssl, true))

if match_only then
return true
end

ok, err = _M.set(api_ctx.matched_ssl, sni)
if not ok then
return false, err
end

return true
end


function _M.set(matched_ssl, sni)
if not matched_ssl then
return false, "failed to match ssl certificate"
end
local ok, err
if not sni then
sni, err = apisix_ssl.server_name()
if type(sni) ~= "string" then
local advise = "please check if the client requests via IP or uses an outdated " ..
"protocol. If you need to report an issue, " ..
"provide a packet capture file of the TLS handshake."
return false, "failed to find SNI: " .. (err or advise)
end
end
ngx_ssl.clear_certs()

local new_ssl_value = secret.fetch_secrets(matched_ssl.value) or matched_ssl.value
Expand Down
1 change: 1 addition & 0 deletions ci/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export_or_prefix() {
export OPENRESTY_PREFIX="/usr/local/openresty-debug"
export APISIX_MAIN="https://raw.githubusercontent.com/apache/incubator-apisix/master/rockspec/apisix-master-0.rockspec"
export PATH=$OPENRESTY_PREFIX/nginx/sbin:$OPENRESTY_PREFIX/luajit/bin:$OPENRESTY_PREFIX/bin:$PATH
export OPENSSL111_BIN=$OPENRESTY_PREFIX/openssl111/bin/openssl
}

create_lua_deps() {
Expand Down
10 changes: 9 additions & 1 deletion ci/linux-install-openresty.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ OPENSSL3_PREFIX=${OPENSSL3_PREFIX-/home/runner}
SSL_LIB_VERSION=${SSL_LIB_VERSION-openssl}

if [ "$OPENRESTY_VERSION" == "source" ]; then
export openssl_prefix=/usr/local/openresty/openssl111
export zlib_prefix=/usr/local/openresty/zlib
export pcre_prefix=/usr/local/openresty/pcre

export cc_opt="-DNGX_LUA_ABORT_AT_PANIC -I${zlib_prefix}/include -I${pcre_prefix}/include -I${openssl_prefix}/include"
export ld_opt="-L${zlib_prefix}/lib -L${pcre_prefix}/lib -L${openssl_prefix}/lib -Wl,-rpath,${zlib_prefix}/lib:${pcre_prefix}/lib:${openssl_prefix}/lib"

if [ "$COMPILE_OPENSSL3" == "yes" ]; then
apt install -y build-essential
git clone https://github.com/openssl/openssl
Expand Down Expand Up @@ -72,7 +79,8 @@ if [ "$OPENRESTY_VERSION" == "source" ]; then
chmod +x build-apisix-base.sh
./build-apisix-base.sh latest

sudo apt-get install openresty-openssl111-debug-dev
sudo apt-get install -y openresty-openssl111 openresty-openssl111-debug-dev libldap2-dev openresty-pcre openresty-zlib

exit 0
fi

Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,7 @@ SSL resource request address: /apisix/admin/ssls/{id}
| update_time | False | Auxiliary | Epoch timestamp (in seconds) of the updated time. If missing, this field will be populated automatically. | 1602883670 |
| type | False | Auxiliary | Identifies the type of certificate, default `server`. | `client` Indicates that the certificate is a client certificate, which is used when APISIX accesses the upstream; `server` Indicates that the certificate is a server-side certificate, which is used by APISIX when verifying client requests. |
| status | False | Auxiliary | Enables the current SSL. Set to `1` (enabled) by default. | `1` to enable, `0` to disable |
| ssl_protocols | False | An array of ssl protocols | It is used to control the SSL/TLS protocol version used between servers and clients. See [SSL Protocol](./ssl-protocol.md) for more examples. | `["TLSv1.2", "TLSv2.3"]` |
Example Configuration:
Expand Down
4 changes: 4 additions & 0 deletions docs/en/latest/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,10 @@
{
"type": "doc",
"id": "profile"
},
{
"type": "doc",
"id": "ssl-protocol"
}
]
},
Expand Down
Loading

0 comments on commit a4038d5

Please sign in to comment.