feat: allow configuring fallback SNI (#5000)
The fallback SNI works around cases that client doesn't send a SNI
during handshake.
By configuring a fallback SNI we can configure a fallback certificate
with the current SSL APIs.
Fix #3147
Signed-off-by: spacewander <spacewanderlzx@gmail.com>
diff --git a/apisix/ssl.lua b/apisix/ssl.lua
index 1dc9cb3..828ebbe 100644
--- a/apisix/ssl.lua
+++ b/apisix/ssl.lua
@@ -35,6 +35,17 @@
local _M = {}
+function _M.server_name()
+ local sni, err = ngx_ssl.server_name()
+ if not err and not sni then
+ local local_conf = core.config.local_conf()
+ sni = core.table.try_read_attr(local_conf, "apisix", "ssl", "fallback_sni")
+ end
+
+ return sni, err
+end
+
+
local _aes_128_cbc_with_iv = false
local function get_aes_128_cbc_with_iv()
if _aes_128_cbc_with_iv == false then
diff --git a/apisix/ssl/router/radixtree_sni.lua b/apisix/ssl/router/radixtree_sni.lua
index 6f44a2f..6e7a41c 100644
--- a/apisix/ssl/router/radixtree_sni.lua
+++ b/apisix/ssl/router/radixtree_sni.lua
@@ -128,7 +128,7 @@
end
local sni
- sni, err = ngx_ssl.server_name()
+ 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, " ..
diff --git a/apisix/stream/router/ip_port.lua b/apisix/stream/router/ip_port.lua
index 44b0ab3..271ae73 100644
--- a/apisix/stream/router/ip_port.lua
+++ b/apisix/stream/router/ip_port.lua
@@ -18,7 +18,7 @@
local config_util = require("apisix.core.config_util")
local plugin_checker = require("apisix.plugin").stream_plugin_checker
local router_new = require("apisix.utils.router").new
-local ngx_ssl = require("ngx.ssl")
+local apisix_ssl = require("apisix.ssl")
local error = error
local tonumber = tonumber
local ipairs = ipairs
@@ -134,7 +134,7 @@
router_ver = user_routes.conf_version
end
- local sni = ngx_ssl.server_name()
+ local sni = apisix_ssl.server_name()
if sni and tls_router then
local sni_rev = sni:reverse()
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index ab1f3d4..781239b 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -139,9 +139,12 @@
ssl_ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl_session_tickets: false # disable ssl_session_tickets by default for 'ssl_session_tickets' would make Perfect Forward Secrecy useless.
# ref: https://github.com/mozilla/server-side-tls/issues/135
+
key_encrypt_salt: edd1c9f0985e76a2 # If not set, will save origin ssl key into etcd.
# If set this, must be a string of length 16. And it will encrypt ssl key with AES-128-CBC
# !!! So do not change it after saving your ssl, it can't decrypt the ssl keys have be saved if you change !!
+
+ #fallback_sni: "my.default.domain" # If set this, when the client doesn't send SNI during handshake, the fallback SNI will be used instead
enable_control: true
#control:
# ip: 127.0.0.1
diff --git a/t/router/radixtree-sni2.t b/t/router/radixtree-sni2.t
index e3ec3b7..57aadd0 100644
--- a/t/router/radixtree-sni2.t
+++ b/t/router/radixtree-sni2.t
@@ -354,3 +354,47 @@
failed to fetch ssl config: failed to find SNI: please check if the client requests via IP or uses an outdated protocol
--- no_error_log
[alert]
+
+
+
+=== TEST 9: client request without sni, but fallback_sni is set
+--- yaml_config
+apisix:
+ node_listen: 1984
+ ssl:
+ fallback_sni: "a.test2.com"
+--- config
+listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
+
+location /t {
+ content_by_lua_block {
+ -- etcd sync
+ ngx.sleep(0.2)
+
+ do
+ local sock = ngx.socket.tcp()
+
+ sock:settimeout(2000)
+
+ local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ local sess, err = sock:sslhandshake(nil, nil, false)
+ if not sess then
+ ngx.say("failed to do SSL handshake: ", err)
+ return
+ end
+ ngx.say("ssl handshake: ", sess ~= nil)
+ end -- do
+ -- collectgarbage()
+ }
+}
+--- request
+GET /t
+--- no_error_log
+[error]
+--- response_body
+ssl handshake: true
diff --git a/t/stream-node/sni.t b/t/stream-node/sni.t
index ab70117..ff80c95 100644
--- a/t/stream-node/sni.t
+++ b/t/stream-node/sni.t
@@ -277,7 +277,25 @@
-=== TEST 10: no sni matched, fall back to non-sni route
+=== TEST 10: use fallback sni to match route
+--- yaml_config
+apisix:
+ node_listen: 1984
+ stream_proxy:
+ tcp:
+ - 9100
+ ssl:
+ fallback_sni: a.test.com
+--- stream_tls_request
+mmm
+--- response_body
+hello world
+--- error_log
+proxy request to 127.0.0.2:1995
+
+
+
+=== TEST 11: no sni matched, fall back to non-sni route
--- config
location /t {
content_by_lua_block {
@@ -301,7 +319,7 @@
-=== TEST 11: hit route
+=== TEST 12: hit route
--- stream_tls_request
mmm
--- stream_sni: b.test.com
@@ -312,7 +330,7 @@
-=== TEST 12: clean up routes
+=== TEST 13: clean up routes
--- config
location /t {
content_by_lua_block {