You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/06/11 09:23:26 UTC
[apisix] branch master updated: feat(stream): accept tls over tcp
(#4409)
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 b822423 feat(stream): accept tls over tcp (#4409)
b822423 is described below
commit b822423b9a1f0f42537462356697d128c4fa897d
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Fri Jun 11 17:23:16 2021 +0800
feat(stream): accept tls over tcp (#4409)
---
README.md | 2 +-
apisix/cli/ngx_tpl.lua | 13 +++-
apisix/cli/ops.lua | 35 +++++++++
apisix/init.lua | 19 +++++
apisix/router.lua | 6 ++
ci/linux_apisix_current_luarocks_runner.sh | 3 +
conf/config-default.yaml | 5 +-
docs/ar/README.md | 2 +-
docs/en/latest/admin-api.md | 2 +-
docs/en/latest/{https.md => certificate.md} | 2 +-
docs/en/latest/config.json | 2 +-
docs/en/latest/grpc-proxy.md | 2 +-
docs/en/latest/stream-proxy.md | 38 +++++++++-
docs/es/latest/README.md | 2 +-
docs/zh/latest/README.md | 2 +-
docs/zh/latest/admin-api.md | 2 +-
docs/zh/latest/{https.md => certificate.md} | 2 +-
docs/zh/latest/config.json | 2 +-
docs/zh/latest/grpc-proxy.md | 2 +-
docs/zh/latest/stream-proxy.md | 32 +++++++++
t/APISIX.pm | 55 +++++++++++++++
t/cli/test_tls_over_tcp.sh | 58 +++++++++++++++
t/stream-node/tls.t | 106 ++++++++++++++++++++++++++++
utils/create-ssl.py | 41 +++++++++++
24 files changed, 416 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index 7c752db..e5e1b27 100644
--- a/README.md
+++ b/README.md
@@ -74,7 +74,7 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against
- Proxy Protocol
- Proxy Dubbo: Dubbo Proxy based on Tengine.
- HTTP(S) Forward Proxy
- - [SSL](docs/en/latest/https.md): Dynamically load an SSL certificate.
+ - [SSL](docs/en/latest/certificate.md): Dynamically load an SSL certificate.
- **Full Dynamic**
diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index eeb36f4..6d48056 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -99,13 +99,22 @@ stream {
}
server {
- {% for _, addr in ipairs(stream_proxy.tcp or {}) do %}
- listen {*addr*} {% if enable_reuseport then %} reuseport {% end %} {% if proxy_protocol and proxy_protocol.enable_tcp_pp then %} proxy_protocol {% end %};
+ {% for _, item in ipairs(stream_proxy.tcp or {}) do %}
+ listen {*item.addr*} {% if item.tls then %} ssl {% end %} {% if enable_reuseport then %} reuseport {% end %} {% if proxy_protocol and proxy_protocol.enable_tcp_pp then %} proxy_protocol {% end %};
{% end %}
{% for _, addr in ipairs(stream_proxy.udp or {}) do %}
listen {*addr*} udp {% if enable_reuseport then %} reuseport {% end %};
{% end %}
+ {% if tcp_enable_ssl then %}
+ ssl_certificate {* ssl.ssl_cert *};
+ ssl_certificate_key {* ssl.ssl_cert_key *};
+
+ ssl_certificate_by_lua_block {
+ apisix.stream_ssl_phase()
+ }
+ {% end %}
+
{% if proxy_protocol and proxy_protocol.enable_tcp_pp_to_upstream then %}
proxy_protocol on;
{% end %}
diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index 8f8716b..49d0be1 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -192,6 +192,25 @@ local config_schema = {
{
type = "string",
},
+ {
+ type = "object",
+ properties = {
+ addr = {
+ anyOf = {
+ {
+ type = "integer",
+ },
+ {
+ type = "string",
+ },
+ }
+ },
+ tls = {
+ type = "boolean",
+ }
+ },
+ required = {"addr"}
+ },
},
},
uniqueItems = true,
@@ -435,6 +454,21 @@ Please modify "admin_key" in conf/config.yaml .
yaml_conf.apisix.ssl.ssl_cert = "cert/ssl_PLACE_HOLDER.crt"
yaml_conf.apisix.ssl.ssl_cert_key = "cert/ssl_PLACE_HOLDER.key"
+ local tcp_enable_ssl
+ -- compatible with the original style which only has the addr
+ if yaml_conf.apisix.stream_proxy and yaml_conf.apisix.stream_proxy.tcp then
+ local tcp = yaml_conf.apisix.stream_proxy.tcp
+ for i, item in ipairs(tcp) do
+ if type(item) ~= "table" then
+ tcp[i] = {addr = item}
+ else
+ if item.tls then
+ tcp_enable_ssl = true
+ end
+ end
+ end
+ end
+
local dubbo_upstream_multiplex_count = 32
if yaml_conf.plugin_attr and yaml_conf.plugin_attr["dubbo-proxy"] then
local dubbo_conf = yaml_conf.plugin_attr["dubbo-proxy"]
@@ -460,6 +494,7 @@ Please modify "admin_key" in conf/config.yaml .
error_log = {level = "warn"},
enabled_plugins = enabled_plugins,
dubbo_upstream_multiplex_count = dubbo_upstream_multiplex_count,
+ tcp_enable_ssl = tcp_enable_ssl,
}
if not yaml_conf.apisix then
diff --git a/apisix/init.lua b/apisix/init.lua
index f3b53f0..de9ac1e 100644
--- a/apisix/init.lua
+++ b/apisix/init.lua
@@ -761,6 +761,25 @@ function _M.http_control()
end
+function _M.stream_ssl_phase()
+ local ngx_ctx = ngx.ctx
+ local api_ctx = ngx_ctx.api_ctx
+
+ if api_ctx == nil then
+ api_ctx = core.tablepool.fetch("api_ctx", 0, 32)
+ ngx_ctx.api_ctx = api_ctx
+ end
+
+ local ok, err = router.router_ssl.match_and_set(api_ctx)
+ if not ok then
+ if err then
+ core.log.error("failed to fetch ssl config: ", err)
+ end
+ ngx_exit(-1)
+ end
+end
+
+
function _M.stream_init(args)
core.log.info("enter stream_init")
diff --git a/apisix/router.lua b/apisix/router.lua
index 840f0cd..9bdafeb 100644
--- a/apisix/router.lua
+++ b/apisix/router.lua
@@ -106,9 +106,15 @@ end
function _M.stream_init_worker()
+ local router_ssl_name = "radixtree_sni"
+
local router_stream = require("apisix.stream.router.ip_port")
router_stream.stream_init_worker(filter)
_M.router_stream = router_stream
+
+ local router_ssl = require("apisix.ssl.router." .. router_ssl_name)
+ router_ssl.init_worker()
+ _M.router_ssl = router_ssl
end
diff --git a/ci/linux_apisix_current_luarocks_runner.sh b/ci/linux_apisix_current_luarocks_runner.sh
index e055c4c..3ca7c0e 100755
--- a/ci/linux_apisix_current_luarocks_runner.sh
+++ b/ci/linux_apisix_current_luarocks_runner.sh
@@ -58,6 +58,9 @@ script() {
# apisix cli test
./utils/set-dns.sh
+ # install test dependencies
+ sudo pip install requests
+
for f in ./t/cli/test_*.sh; do
sudo PATH="$PATH" "$f"
done
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index 3aefd6f..c2c124e 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -98,8 +98,9 @@ apisix:
ssl: 'radixtree_sni' # radixtree_sni: match route by SNI(base on radixtree)
#stream_proxy: # TCP/UDP proxy
# tcp: # TCP proxy port list
- # - 9100
- # - "127.0.0.1:9101"
+ # - addr: 9100
+ # tls: true
+ # - addr: "127.0.0.1:9101"
# udp: # UDP proxy port list
# - 9200
# - "127.0.0.1:9201"
diff --git a/docs/ar/README.md b/docs/ar/README.md
index c2ac6b0..26ef9fe 100644
--- a/docs/ar/README.md
+++ b/docs/ar/README.md
@@ -79,7 +79,7 @@
- بروتوكول الوكيل
- الوكيل Dubbo: Dubbo يعتمد على Tengine.
- HTTP(S) وكيل إعادة التوجيه
- - [SSL](docs/en/latest/https.md): تحميل شهادة SSL ديناميكيًا.
+ - [SSL](docs/en/latest/certificate.md): تحميل شهادة SSL ديناميكيًا.
- **ديناميكية كاملة**
diff --git a/docs/en/latest/admin-api.md b/docs/en/latest/admin-api.md
index 2ea7aef..bf60739 100644
--- a/docs/en/latest/admin-api.md
+++ b/docs/en/latest/admin-api.md
@@ -812,7 +812,7 @@ Config Example:
}
```
-More examples can be found in [HTTPS](./https.md).
+More examples can be found in [Certificate](./certificate.md).
## Global Rule
diff --git a/docs/en/latest/https.md b/docs/en/latest/certificate.md
similarity index 99%
rename from docs/en/latest/https.md
rename to docs/en/latest/certificate.md
index 30c2325..5507e5e 100644
--- a/docs/en/latest/https.md
+++ b/docs/en/latest/certificate.md
@@ -1,5 +1,5 @@
---
-title: HTTPS
+title: Certificate
---
<!--
diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json
index 241acbf..39ff50c 100644
--- a/docs/en/latest/config.json
+++ b/docs/en/latest/config.json
@@ -185,7 +185,7 @@
},
{
"type": "doc",
- "id": "https"
+ "id": "certificate"
},
{
"type": "doc",
diff --git a/docs/en/latest/grpc-proxy.md b/docs/en/latest/grpc-proxy.md
index ca4d05b..dd71f03 100644
--- a/docs/en/latest/grpc-proxy.md
+++ b/docs/en/latest/grpc-proxy.md
@@ -36,7 +36,7 @@ gRPC client -> APISIX -> gRPC/gRPCS server
Here's an example, to proxying gRPC service by specified route:
* attention: the `scheme` of the route's upstream must be `grpc` or `grpcs`.
-* attention: APISIX use TLS‑encrypted HTTP/2 to expose gRPC service, so need to [config SSL certificate](https.md)
+* attention: APISIX use TLS‑encrypted HTTP/2 to expose gRPC service, so need to [config SSL certificate](certificate.md)
* attention: APISIX also support to expose gRPC service with plaintext HTTP/2, which does not rely on TLS, usually used to proxy gRPC service in intranet environment
* the grpc server example:[grpc_server_example](https://github.com/iresty/grpc_server_example)
diff --git a/docs/en/latest/stream-proxy.md b/docs/en/latest/stream-proxy.md
index 1cfa05c..627d029 100644
--- a/docs/en/latest/stream-proxy.md
+++ b/docs/en/latest/stream-proxy.md
@@ -23,12 +23,12 @@ title: Stream Proxy
TCP is the protocol for many popular applications and services, such as LDAP, MySQL, and RTMP. UDP (User Datagram Protocol) is the protocol for many popular non-transactional applications, such as DNS, syslog, and RADIUS.
-APISIX can dynamic load balancing TCP/UDP proxy. In Nginx world, we call TCP/UDP proxy to stream proxy, we followed this statement.
+APISIX can dynamically load balancing TCP/UDP proxy. In Nginx world, we call TCP/UDP proxy to stream proxy, we followed this statement.
## How to enable stream proxy?
Setting the `stream_proxy` option in `conf/config.yaml`, specify a list of addresses that require dynamic proxy.
-By default, no any stream proxy is enabled.
+By default, no stream proxy is enabled.
```yaml
apisix:
@@ -82,6 +82,38 @@ curl http://127.0.0.1:9080/apisix/admin/stream_routes/1 -H 'X-API-KEY: edd1c9f03
}'
```
-It means APISIX will proxy the request to `127.0.0.1:1995` which the server address is `127.0.0.1` and the server port is equal `2000`.
+It means APISIX will proxy the request to `127.0.0.1:1995` which the server address is `127.0.0.1` and the server port is equal to `2000`.
Read [Admin API's Stream Route section](./admin-api.md#stream-route) for the complete options list.
+
+## Accept TLS over TCP
+
+APISIX can accept TLS over TCP.
+
+First of all, we need to enable TLS for the TCP address:
+
+```yaml
+apisix:
+ stream_proxy: # TCP/UDP proxy
+ tcp: # TCP proxy address list
+ - addr: 9100
+ tls: true
+```
+
+Second, we need to configure certificate for the given SNI.
+See [Admin API's SSL section](./admin-api.md#ssl) for how to do.
+
+Third, we need to configure a stream route to match and proxy it to the upstream:
+
+```shell
+curl http://127.0.0.1:9080/apisix/admin/stream_routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+{
+ "remote_addr": "127.0.0.1",
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1995": 1
+ },
+ "type": "roundrobin"
+ }
+}'
+```
diff --git a/docs/es/latest/README.md b/docs/es/latest/README.md
index 9f2d086..dd5c0e3 100644
--- a/docs/es/latest/README.md
+++ b/docs/es/latest/README.md
@@ -76,7 +76,7 @@ ensayos A/B, ensayos de despliegue de canarios (canary release), despliegue azul
- Proxy de Protocolo
- Proxy Dubbo: Proxy de Dubbo basado en Tengine.
- Proxy de HTTP(S) hacia adelante
- - [SSL](../../en/latest/https.md): Carga dinámica de certificado SSL.
+ - [SSL](../../en/latest/certificate.md): Carga dinámica de certificado SSL.
- **Completamente Dinámico**
diff --git a/docs/zh/latest/README.md b/docs/zh/latest/README.md
index 198dede..eb470c0 100644
--- a/docs/zh/latest/README.md
+++ b/docs/zh/latest/README.md
@@ -78,7 +78,7 @@ A/B 测试、金丝雀发布(灰度发布)、蓝绿部署、限流限速、抵
- Proxy Protocol
- Dubbo 代理:基于 Tengine,可以实现 Dubbo 请求的代理。
- HTTP(S) 反向代理
- - [SSL](https.md):动态加载 SSL 证书。
+ - [SSL](certificate.md):动态加载 SSL 证书。
- **全动态能力**
diff --git a/docs/zh/latest/admin-api.md b/docs/zh/latest/admin-api.md
index 44135b5..499b1f4 100644
--- a/docs/zh/latest/admin-api.md
+++ b/docs/zh/latest/admin-api.md
@@ -815,7 +815,7 @@ ssl 对象 json 配置内容:
}
```
-更多的配置示例见 [HTTPS](./https.md)。
+更多的配置示例见 [证书](./certificate.md)。
[Back to TOC](#目录)
diff --git a/docs/zh/latest/https.md b/docs/zh/latest/certificate.md
similarity index 99%
rename from docs/zh/latest/https.md
rename to docs/zh/latest/certificate.md
index e8ed5d2..831740f 100644
--- a/docs/zh/latest/https.md
+++ b/docs/zh/latest/certificate.md
@@ -1,5 +1,5 @@
---
-title: HTTPS
+title: 证书
---
<!--
diff --git a/docs/zh/latest/config.json b/docs/zh/latest/config.json
index 1d60963..d596e85 100644
--- a/docs/zh/latest/config.json
+++ b/docs/zh/latest/config.json
@@ -168,7 +168,7 @@
},
{
"type": "doc",
- "id": "https"
+ "id": "certificate"
},
{
"type": "doc",
diff --git a/docs/zh/latest/grpc-proxy.md b/docs/zh/latest/grpc-proxy.md
index 64a0981..e57a652 100644
--- a/docs/zh/latest/grpc-proxy.md
+++ b/docs/zh/latest/grpc-proxy.md
@@ -35,7 +35,7 @@ title: gRPC 代理
在指定 Route 中,代理 gRPC 服务接口:
* 注意:这个 Route 对应的 Upstream 的 `scheme` 必须设置为 `grpc` 或者 `grpcs`。
-* 注意: APISIX 使用 TLS 加密的 HTTP/2 暴露 gRPC 服务, 所以需要先 [配置 SSL 证书](https.md);
+* 注意: APISIX 使用 TLS 加密的 HTTP/2 暴露 gRPC 服务, 所以需要先 [配置 SSL 证书](certificate.md);
* 注意: APISIX 也支持通过纯文本的 HTTP/2 暴露 gRPC 服务,这不需要依赖 SSL,通常用于内网环境代理gRPC服务
* 下面例子所代理的 gRPC 服务可供参考:[grpc_server_example](https://github.com/api7/grpc_server_example)。
diff --git a/docs/zh/latest/stream-proxy.md b/docs/zh/latest/stream-proxy.md
index 12c274d..d68587e 100644
--- a/docs/zh/latest/stream-proxy.md
+++ b/docs/zh/latest/stream-proxy.md
@@ -83,3 +83,35 @@ curl http://127.0.0.1:9080/apisix/admin/stream_routes/1 -H 'X-API-KEY: edd1c9f03
例子中 APISIX 会把服务器地址为 `127.0.0.1`, 端口为 `2000` 代理到上游地址 `127.0.0.1:1995`。
完整的匹配选项列表参见 [Admin API 的 Stream Route](./admin-api.md#stream-route)。
+
+## 接收 TLS over TCP
+
+APISIX 支持接收 TLS over TCP。
+
+首先,我们需要给对应的 TCP 地址启用 TLS:
+
+```yaml
+apisix:
+ stream_proxy: # TCP/UDP proxy
+ tcp: # TCP proxy address list
+ - addr: 9100
+ tls: true
+```
+
+接着,我们需要为给定的 SNI 配置证书。
+具体步骤参考 [Admin API 的 SSL](./admin-api.md#ssl)。
+
+然后,我们需要配置一个 route,匹配连接并代理到上游:
+
+```shell
+curl http://127.0.0.1:9080/apisix/admin/stream_routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+{
+ "remote_addr": "127.0.0.1",
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1995": 1
+ },
+ "type": "roundrobin"
+ }
+}'
+```
diff --git a/t/APISIX.pm b/t/APISIX.pm
index f8bd235..200dd86 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -238,6 +238,52 @@ _EOC_
my $timeout = $block->timeout // 5;
$block->set_value("timeout", $timeout);
+ my $stream_tls_request = $block->stream_tls_request;
+ if ($stream_tls_request) {
+ # generate a springboard to send tls stream request
+ $block->set_value("stream_conf_enable", 1);
+ $block->set_value("request", "GET /stream_tls_request");
+
+ my $sni = "nil";
+ if ($block->stream_sni) {
+ $sni = '"' . $block->stream_sni . '"';
+ }
+ chomp $stream_tls_request;
+
+ my $config = <<_EOC_;
+ location /stream_tls_request {
+ content_by_lua_block {
+ local sock = ngx.socket.tcp()
+ local ok, err = sock:connect("127.0.0.1", 2005)
+ if not ok then
+ ngx.say("failed to connect: ", err)
+ return
+ end
+
+ local sess, err = sock:sslhandshake(nil, $sni, false)
+ if not sess then
+ ngx.say("failed to do SSL handshake: ", err)
+ return
+ end
+
+ local bytes, err = sock:send("$stream_tls_request")
+ if not bytes then
+ ngx.say("send stream request error: ", err)
+ return
+ end
+ local data, err = sock:receive("*a")
+ if not data then
+ sock:close()
+ ngx.say("receive stream response error: ", err)
+ return
+ end
+ ngx.print(data)
+ }
+ }
+_EOC_
+ $block->set_value("config", $config)
+ }
+
my $stream_enable = $block->stream_enable;
my $stream_conf_enable = $block->stream_conf_enable;
my $extra_stream_config = $block->extra_stream_config // '';
@@ -297,6 +343,15 @@ _EOC_
}
my $stream_server_config = $block->stream_server_config // <<_EOC_;
+ listen 2005 ssl;
+ ssl_certificate cert/apisix.crt;
+ ssl_certificate_key cert/apisix.key;
+ lua_ssl_trusted_certificate cert/apisix.crt;
+
+ ssl_certificate_by_lua_block {
+ apisix.stream_ssl_phase()
+ }
+
preread_by_lua_block {
-- wait for etcd sync
ngx.sleep($wait_etcd_sync)
diff --git a/t/cli/test_tls_over_tcp.sh b/t/cli/test_tls_over_tcp.sh
new file mode 100755
index 0000000..1c7f255
--- /dev/null
+++ b/t/cli/test_tls_over_tcp.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+#
+# 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.
+#
+
+. ./t/cli/common.sh
+
+# check tls over tcp proxy
+echo "
+apisix:
+ stream_proxy:
+ tcp:
+ - addr: 9100
+ tls: true
+nginx_config:
+ stream_configuration_snippet: |
+ server {
+ listen 9101;
+ return \"OK FROM UPSTREAM\";
+ }
+
+" > conf/config.yaml
+
+make run
+sleep 0.1
+
+ ./utils/create-ssl.py t/certs/mtls_server.crt t/certs/mtls_server.key test.com
+
+curl -k -i http://127.0.0.1:9080/apisix/admin/stream_routes/1 \
+ -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d \
+ '{"upstream":{"nodes":{"127.0.0.1:9101":1},"type":"roundrobin"}}'
+
+sleep 0.1
+if ! echo -e 'mmm' | \
+ openssl s_client -connect 127.0.0.1:9100 -servername test.com -CAfile t/certs/mtls_ca.crt \
+ -ign_eof | \
+ grep 'OK FROM UPSTREAM';
+then
+ echo "failed: should proxy tls over tcp"
+ exit 1
+fi
+
+make stop
+echo "passed: proxy tls over tcp"
diff --git a/t/stream-node/tls.t b/t/stream-node/tls.t
new file mode 100644
index 0000000..bd525d1
--- /dev/null
+++ b/t/stream-node/tls.t
@@ -0,0 +1,106 @@
+#
+# 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 'no_plan';
+
+log_level('info');
+no_root_location();
+worker_connections(1024);
+no_shuffle();
+
+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 stream / ssl
+--- config
+ location /t {
+ content_by_lua_block {
+ local core = require("apisix.core")
+ local t = require("lib.test_admin")
+
+ local ssl_cert = t.read_file("t/certs/apisix.crt")
+ local ssl_key = t.read_file("t/certs/apisix.key")
+ local data = {
+ cert = ssl_cert, key = ssl_key,
+ sni = "test.com",
+ }
+ local code, body = t.test('/apisix/admin/ssl/1',
+ ngx.HTTP_PUT,
+ core.json.encode(data)
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ return
+ end
+
+ local code, body = t.test('/apisix/admin/stream_routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1995": 1
+ },
+ "type": "roundrobin"
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: hit route
+--- stream_tls_request
+mmm
+--- stream_sni: test.com
+--- response_body
+hello world
+
+
+
+=== TEST 3: wrong sni
+--- stream_tls_request
+mmm
+--- stream_sni: xx.com
+--- error_log
+failed to find any SSL certificate by SNI: xx.com
+
+
+
+=== TEST 4: missing sni
+--- stream_tls_request
+mmm
+--- error_log
+failed to find SNI
diff --git a/utils/create-ssl.py b/utils/create-ssl.py
new file mode 100755
index 0000000..93f2068
--- /dev/null
+++ b/utils/create-ssl.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# coding: utf-8
+#
+# 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.
+#
+import sys
+# sudo pip install requests
+import requests
+
+# Usage: ./create-ssl.py t.crt t.key test.com
+if len(sys.argv) <= 3:
+ print("bad argument")
+ sys.exit(1)
+with open(sys.argv[1]) as f:
+ cert = f.read()
+with open(sys.argv[2]) as f:
+ key = f.read()
+sni = sys.argv[3]
+api_key = "edd1c9f034335f136f87ad84b625c8f1"
+resp = requests.put("http://127.0.0.1:9080/apisix/admin/ssl/1", json={
+ "cert": cert,
+ "key": key,
+ "snis": [sni],
+}, headers={
+ "X-API-KEY": api_key,
+})
+print(resp.status_code)
+print(resp.text)