Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support store route's cert in secrets manager #9247

Merged
merged 15 commits into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/fips.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ jobs:
- name: Linux launch common services
run: |
make ci-env-up project_compose_ci=ci/pod/docker-compose.common.yml
sudo ./ci/init-common-test-service.sh
- name: Cache images
id: cache-images
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/gm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
- name: Linux launch common services
run: |
make ci-env-up project_compose_ci=ci/pod/docker-compose.common.yml
sudo ./ci/init-common-test-service.sh
- name: Linux Before install
env:
Expand Down
15 changes: 13 additions & 2 deletions apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -725,8 +725,19 @@ _M.ssl = {
default = "server",
enum = {"server", "client"}
},
cert = certificate_scheme,
key = private_key_schema,
cert = {
oneOf = {
certificate_scheme,
-- TODO: uniformly define the schema of secret_uri
{ type = "string", pattern = "^\\$(secret|env)://"}
}
},
key = {
oneOf = {
private_key_schema,
{ type = "string", pattern = "^\\$(secret|env)://"}
}
},
sni = {
type = "string",
pattern = host_def_pat,
Expand Down
21 changes: 17 additions & 4 deletions apisix/secret.lua
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,27 @@ function _M.init_worker()
end


local function parse_secret_uri(secret_uri)
local function check_secret_uri(secret_uri)
-- Avoid the error caused by has_prefix to cause a crash.
if type(secret_uri) ~= "string" then
return nil, "error secret_uri type: " .. type(secret_uri)
return false, "error secret_uri type: " .. type(secret_uri)
end

if not string.has_prefix(secret_uri, PREFIX) and
not string.has_prefix(upper(secret_uri), core.env.PREFIX) then
return false, "error secret_uri prefix: " .. secret_uri
end

if not string.has_prefix(secret_uri, PREFIX) then
return nil, "error secret_uri prefix: " .. secret_uri
return true
end

_M.check_secret_uri = check_secret_uri


local function parse_secret_uri(secret_uri)
local is_secret_uri, err = check_secret_uri(secret_uri)
if not is_secret_uri then
return is_secret_uri, err
end

local path = sub(secret_uri, #PREFIX + 1)
Expand Down
21 changes: 15 additions & 6 deletions apisix/ssl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
--
local core = require("apisix.core")
local ngx_ssl = require("ngx.ssl")
local secret = require("apisix.secret")
local ngx_encode_base64 = ngx.encode_base64
local ngx_decode_base64 = ngx.decode_base64
local aes = require("resty.aes")
Expand Down Expand Up @@ -252,9 +253,13 @@ function _M.check_ssl_conf(in_dp, conf)
end
end

local ok, err = validate(conf.cert, conf.key)
if not ok then
return nil, err
if not secret.check_secret_uri(conf.cert) and
not secret.check_secret_uri(conf.key) then

monkeyDluffy6017 marked this conversation as resolved.
Show resolved Hide resolved
local ok, err = validate(conf.cert, conf.key)
if not ok then
return nil, err
end
end

if conf.type == "client" then
Expand All @@ -268,9 +273,13 @@ function _M.check_ssl_conf(in_dp, conf)
end

for i = 1, numcerts do
local ok, err = validate(conf.certs[i], conf.keys[i])
if not ok then
return nil, "failed to handle cert-key pair[" .. i .. "]: " .. err
if not secret.check_secret_uri(conf.cert[i]) and
not secret.check_secret_uri(conf.key[i]) then

local ok, err = validate(conf.certs[i], conf.keys[i])
if not ok then
return nil, "failed to handle cert-key pair[" .. i .. "]: " .. err
end
end
end

Expand Down
5 changes: 4 additions & 1 deletion apisix/ssl/router/radixtree_sni.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ local get_request = require("resty.core.base").get_request
local router_new = require("apisix.utils.router").new
local core = require("apisix.core")
local apisix_ssl = require("apisix.ssl")
local secret = require("apisix.secret")
local ngx_ssl = require("ngx.ssl")
local config_util = require("apisix.core.config_util")
local ipairs = ipairs
Expand Down Expand Up @@ -212,7 +213,9 @@ function _M.match_and_set(api_ctx, match_only, alt_sni)

ngx_ssl.clear_certs()

ok, err = _M.set_cert_and_key(sni, matched_ssl.value)
local new_ssl_value = secret.fetch_secrets(matched_ssl.value) or matched_ssl.value

ok, err = _M.set_cert_and_key(sni, new_ssl_value)
if not ok then
return false, err
end
Expand Down
4 changes: 2 additions & 2 deletions docs/en/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1154,8 +1154,8 @@ SSL resource request address: /apisix/admin/ssls/{id}
| Parameter | Required | Type | Description | Example |
| ------------ | -------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| cert | True | Certificate | HTTPS certificate. | |
| key | True | Private key | HTTPS private key. | |
| cert | True | Certificate | HTTPS certificate. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | |
| key | True | Private key | HTTPS private key. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | |
soulbird marked this conversation as resolved.
Show resolved Hide resolved
| certs | False | An array of certificates | Used for configuring multiple certificates for the same domain excluding the one provided in the `cert` field. | |
| keys | False | An array of private keys | Private keys to pair with the `certs`. | |
| client.ca | False | Certificate | Sets the CA certificate that verifies the client. Requires OpenResty 1.19+. | |
Expand Down
4 changes: 2 additions & 2 deletions docs/zh/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1162,8 +1162,8 @@ SSL 资源请求地址:/apisix/admin/ssls/{id}

| 名称 | 必选项 | 类型 | 描述 | 示例 |
| ----------- | ------ | -------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------ |
| cert || 证书 | HTTP 证书。 | |
| key || 私钥 | HTTPS 证书私钥 | |
| cert || 证书 | HTTP 证书。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 | |
| key || 私钥 | HTTPS 证书私钥。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 | |
| certs || 证书字符串数组 | 当你想给同一个域名配置多个证书时,除了第一个证书需要通过 `cert` 传递外,剩下的证书可以通过该参数传递上来。 | |
| keys || 私钥字符串数组 | `certs` 对应的证书私钥,需要与 `certs` 一一对应。 | |
| client.ca || 证书 | 设置将用于客户端证书校验的 `CA` 证书。该特性需要 OpenResty 为 1.19 及以上版本。 | |
Expand Down
87 changes: 87 additions & 0 deletions t/gm/gm.t
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@
# specific language governing permissions and limitations
# under the License.

BEGIN {
$ENV{TEST_ENV_GMSSL_CRT_ENC} = "-----BEGIN CERTIFICATE-----
MIIB2DCCAX6gAwIBAgIBAzAKBggqgRzPVQGDdTBFMQswCQYDVQQGEwJBQTELMAkG
A1UECAwCQkIxCzAJBgNVBAoMAkNDMQswCQYDVQQLDAJERDEPMA0GA1UEAwwGc3Vi
IGNhMB4XDTIyMTEwMjAzMTkzNloXDTMyMTAzMDAzMTkzNlowSTELMAkGA1UEBhMC
QUExCzAJBgNVBAgMAkJCMQswCQYDVQQKDAJDQzELMAkGA1UECwwCREQxEzARBgNV
BAMMCnNlcnZlciBlbmMwWjAUBggqgRzPVQGCLQYIKoEcz1UBgi0DQgAED+MQrLrZ
9PbMmz/44Kb73Qc7FlMs7u034XImjJREBAn1KzZ7jqcYfCiV/buhmu1sLhMXnB69
mERtf1tAaXcgIaNaMFgwCQYDVR0TBAIwADALBgNVHQ8EBAMCAzgwHQYDVR0OBBYE
FBxHDo0gHhMoYkDeHWySTIJy5BZpMB8GA1UdIwQYMBaAFCTrpmbUig3JfveqAIGJ
6n+vAk2AMAoGCCqBHM9VAYN1A0gAMEUCIHtXgpOxcb3mZv2scRZHZz5YGFr45dfk
VfLkF9BkrB/xAiEA8EeUg7nCFfgHzrfgB7v0wgN1Hrgj8snTUO6IDfkBKYM=
-----END CERTIFICATE-----
";
}

use t::APISIX;

if (-f "/usr/local/tongsuo/bin/openssl") {
Expand Down Expand Up @@ -168,3 +184,74 @@ location /t {
--- response_body
--- error_log
SSL_do_handshake() failed
=== TEST 5: set ssl: server_enc with secret ref
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local t = require("lib.test_admin")
local f = assert(io.open("t/certs/server_sign.crt"))
local cert_sign = f:read("*a")
f:close()
local f = assert(io.open("t/certs/server_enc.key"))
local pkey_enc = f:read("*a")
f:close()
local f = assert(io.open("t/certs/server_sign.key"))
local pkey_sign = f:read("*a")
f:close()
local data = {
cert = "$env://TEST_ENV_GMSSL_CRT_ENC",
key = pkey_enc,
certs = {cert_sign},
keys = {pkey_sign},
sni = "localhost",
gm = true,
}
local code, body = t.test('/apisix/admin/ssls/1',
ngx.HTTP_PUT,
core.json.encode(data)
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/echo"
}]]
)
ngx.say(body)
}
}
--- response_body
passed
=== TEST 6: hit
--- exec
/usr/local/tongsuo/bin/openssl s_client -connect localhost:1994 -servername localhost -cipher ECDHE-SM2-WITH-SM4-SM3 -enable_ntls -ntls -verifyCAfile t/certs/gm_ca.crt -sign_cert t/certs/client_sign.crt -sign_key t/certs/client_sign.key -enc_cert t/certs/client_enc.crt -enc_key t/certs/client_enc.key
--- response_body eval
qr/^CONNECTED/
--- no_error_log
SSL_do_handshake() failed
[error]
Loading