Skip to content

Commit aaad8ba

Browse files
authored
feat: add support for "system" ssl_trusted_certificate (#11809)
1 parent d599d20 commit aaad8ba

File tree

7 files changed

+150
-12
lines changed

7 files changed

+150
-12
lines changed

apisix/cli/ops.lua

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ local str_find = string.find
4949
local str_byte = string.byte
5050
local str_sub = string.sub
5151
local str_format = string.format
52+
local string = string
53+
local table = table
54+
5255

5356
local _M = {}
5457

@@ -502,17 +505,34 @@ Please modify "admin_key" in conf/config.yaml .
502505

503506

504507
if yaml_conf.apisix.ssl.ssl_trusted_certificate ~= nil then
505-
local cert_path = yaml_conf.apisix.ssl.ssl_trusted_certificate
506-
-- During validation, the path is relative to PWD
507-
-- When Nginx starts, the path is relative to conf
508-
-- Therefore we need to check the absolute version instead
509-
cert_path = pl_path.abspath(cert_path)
508+
local cert_paths = {}
509+
local ssl_certificates = yaml_conf.apisix.ssl.ssl_trusted_certificate
510+
for cert_path in string.gmatch(ssl_certificates, '([^,]+)') do
511+
cert_path = util.trim(cert_path)
512+
if cert_path == "system" then
513+
local trusted_certs_path, err = util.get_system_trusted_certs_filepath()
514+
if not trusted_certs_path then
515+
util.die(err)
516+
end
517+
table.insert(cert_paths, trusted_certs_path)
518+
else
519+
-- During validation, the path is relative to PWD
520+
-- When Nginx starts, the path is relative to conf
521+
-- Therefore we need to check the absolute version instead
522+
cert_path = pl_path.abspath(cert_path)
523+
if not pl_path.exists(cert_path) then
524+
util.die("certificate path", cert_path, "doesn't exist\n")
525+
end
510526

511-
if not pl_path.exists(cert_path) then
512-
util.die("certificate path", cert_path, "doesn't exist\n")
527+
table.insert(cert_paths, cert_path)
528+
end
513529
end
514530

515-
yaml_conf.apisix.ssl.ssl_trusted_certificate = cert_path
531+
local combined_cert_filepath = yaml_conf.apisix.ssl.ssl_trusted_combined_path
532+
or "/usr/local/apisix/conf/ssl_trusted_combined.pem"
533+
util.gen_trusted_certs_combined_file(combined_cert_filepath, cert_paths)
534+
535+
yaml_conf.apisix.ssl.ssl_trusted_certificate = combined_cert_filepath
516536
end
517537

518538
-- enable ssl with place holder crt&key

apisix/cli/schema.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ local config_schema = {
209209
ssl_trusted_certificate = {
210210
type = "string",
211211
},
212+
ssl_trusted_combined_path = {
213+
type = "string",
214+
},
212215
listen = {
213216
type = "array",
214217
items = {

apisix/cli/util.lua

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ local exit = os.exit
2424
local stderr = io.stderr
2525
local str_format = string.format
2626
local tonumber = tonumber
27+
local io = io
28+
local ipairs = ipairs
29+
local assert = assert
2730

2831
local _M = {}
2932

@@ -133,4 +136,54 @@ function _M.file_exists(file_path)
133136
return f ~= nil and close(f)
134137
end
135138

139+
do
140+
local trusted_certs_paths = {
141+
"/etc/ssl/certs/ca-certificates.crt", -- Debian/Ubuntu/Gentoo
142+
"/etc/pki/tls/certs/ca-bundle.crt", -- Fedora/RHEL 6
143+
"/etc/ssl/ca-bundle.pem", -- OpenSUSE
144+
"/etc/pki/tls/cacert.pem", -- OpenELEC
145+
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", -- CentOS/RHEL 7
146+
"/etc/ssl/cert.pem", -- OpenBSD, Alpine
147+
}
148+
149+
-- Check if a file exists using Lua's built-in `io.open`
150+
local function file_exists(path)
151+
local file = io.open(path, "r")
152+
if file then
153+
file:close()
154+
return true
155+
else
156+
return false
157+
end
158+
end
159+
160+
function _M.get_system_trusted_certs_filepath()
161+
for _, path in ipairs(trusted_certs_paths) do
162+
if file_exists(path) then
163+
return path
164+
end
165+
end
166+
167+
return nil,
168+
"Could not find trusted certs file in " ..
169+
"any of the `system`-predefined locations. " ..
170+
"Please install a certs file there or set " ..
171+
"`lua_ssl_trusted_certificate` to a " ..
172+
"specific file path instead of `system`"
173+
end
174+
end
175+
176+
177+
function _M.gen_trusted_certs_combined_file(combined_filepath, paths)
178+
local combined_file = assert(io.open(combined_filepath, "w"))
179+
for _, path in ipairs(paths) do
180+
local cert_file = assert(io.open(path, "r"))
181+
combined_file:write(cert_file:read("*a"))
182+
combined_file:write("\n")
183+
cert_file:close()
184+
end
185+
combined_file:close()
186+
end
187+
188+
136189
return _M

conf/config.yaml.example

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ apisix:
9999
# - ip: 127.0.0.3 # If not set, default to `0.0.0.0`.
100100
# port: 9445
101101
# enable_http3: true
102-
# ssl_trusted_certificate: /path/to/ca-cert # Set the path to CA certificates used to verify client
103-
# certificates in the PEM format.
102+
ssl_trusted_combined_path: /usr/local/apisix/conf/ssl_trusted_combined.pem # All the trusted certificates will be combined into a single file
103+
#ssl_trusted_certificate: system # Specifies comma separated list of trusted CA. Value can be either "system"(for using system available ca certs) or
104+
# a file path with trusted CA certificates in the PEM format
104105
ssl_protocols: TLSv1.2 TLSv1.3 # TLS versions supported.
105106
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
106107
ssl_session_tickets: false # If true, session tickets are used for SSL/TLS connections.

t/cli/test_stream_config.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ echo "
7878
apisix:
7979
ssl:
8080
ssl_trusted_certificate: t/certs/mtls_ca.crt
81+
ssl_trusted_combined_path: t/certs/mtls_ca_combined.crt
8182
proxy_mode: http&stream
8283
stream_proxy:
8384
tcp:
@@ -86,7 +87,7 @@ apisix:
8687

8788
make init
8889

89-
if ! grep "t/certs/mtls_ca.crt;" conf/nginx.conf > /dev/null; then
90+
if ! grep "t/certs/mtls_ca_combined.crt;" conf/nginx.conf > /dev/null; then
9091
echo "failed: failed to set trust certificate"
9192
exit 1
9293
fi

t/cli/test_upstream_mtls.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,63 @@ if ! grep -E 'self-signed certificate' logs/error.log; then
149149
fi
150150

151151
echo "passed: when proxy_ssl_verify is enabled and ssl_trusted_certificate is wrong ca cert, got 502"
152+
153+
154+
# test combined proxy_ssl_trusted_certificate success
155+
echo '
156+
apisix:
157+
ssl:
158+
ssl_trusted_certificate: system, t/certs/apisix.crt
159+
nginx_config:
160+
http_configuration_snippet: |
161+
server {
162+
listen 1983 ssl;
163+
server_name test.com;
164+
ssl_certificate ../t/certs/apisix.crt;
165+
ssl_certificate_key ../t/certs/apisix.key;
166+
location /hello {
167+
return 200 "hello world";
168+
}
169+
}
170+
http_server_configuration_snippet: |
171+
proxy_ssl_verify on;
172+
' > conf/config.yaml
173+
174+
rm logs/error.log || true
175+
make init
176+
make run
177+
sleep 0.1
178+
179+
curl -k -i http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
180+
{
181+
"uri": "/hello",
182+
"upstream": {
183+
"pass_host": "rewrite",
184+
"nodes": {
185+
"127.0.0.1:1983": 1
186+
},
187+
"scheme": "https",
188+
"hash_on": "vars",
189+
"upstream_host": "test.com",
190+
"type": "roundrobin",
191+
"tls": {
192+
"client_cert": "-----BEGIN CERTIFICATE-----\nMIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV\nBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G\nA1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa\nGA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n\nRG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM\nCHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe\ncvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF5jhZB3W6BkWUWR4oNFLLSqcVb\nVDPitz/Mt46Mo8amuS6zTbQetGnBARzPLtmVhJfoeLj0efMiOepOSZflj9Ob4yKR\n2bGdEFOdHPjm+4ggXU9jMKeLqdVvxll/JiVFBW5smPtW1Oc/BV5terhscJdOgmRr\nabf9xiIis9/qVYfyGn52u9452V0owUuwP7nZ01jt6iMWEGeQU6mwPENgvj1olji2\nWjdG2UwpUVp3jp3l7j1ekQ6mI0F7yI+LeHzfUwiyVt1TmtMWn1ztk6FfLRqwJWR/\nEvm95vnfS3Le4S2ky3XAgn2UnCMyej3wDN6qHR1onpRVeXhrBajbCRDRBMwaNw/1\n/3Uvza8QKK10PzQR6OcQ0xo9psMkd9j9ts/dTuo2fzaqpIfyUbPST4GdqNG9NyIh\n/B9g26/0EWcjyO7mYVkaycrtLMaXm1u9jyRmcQQI1cGrGwyXbrieNp63AgMBAAGj\ncTBvMB0GA1UdDgQWBBSZtSvV8mBwl0bpkvFtgyiOUUcbszAfBgNVHSMEGDAWgBSZ\ntSvV8mBwl0bpkvFtgyiOUUcbszAMBgNVHRMEBTADAQH/MB8GA1UdEQQYMBaCCHRl\nc3QuY29tggoqLnRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAHGEul/x7ViVgC\ntC8CbXEslYEkj1XVr2Y4hXZXAXKd3W7V3TC8rqWWBbr6L/tsSVFt126V5WyRmOaY\n1A5pju8VhnkhYxYfZALQxJN2tZPFVeME9iGJ9BE1wPtpMgITX8Rt9kbNlENfAgOl\nPYzrUZN1YUQjX+X8t8/1VkSmyZysr6ngJ46/M8F16gfYXc9zFj846Z9VST0zCKob\nrJs3GtHOkS9zGGldqKKCj+Awl0jvTstI4qtS1ED92tcnJh5j/SSXCAB5FgnpKZWy\nhme45nBQj86rJ8FhN+/aQ9H9/2Ib6Q4wbpaIvf4lQdLUEcWAeZGW6Rk0JURwEog1\n7/mMgkapDglgeFx9f/XztSTrkHTaX4Obr+nYrZ2V4KOB4llZnK5GeNjDrOOJDk2y\nIJFgBOZJWyS93dQfuKEj42hA79MuX64lMSCVQSjX+ipR289GQZqFrIhiJxLyA+Ve\nU/OOcSRr39Kuis/JJ+DkgHYa/PWHZhnJQBxcqXXk1bJGw9BNbhM=\n-----END CERTIFICATE-----\n",
193+
"client_key": "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"
194+
}
195+
}
196+
}'
197+
198+
sleep 1
199+
200+
code=$(curl -v -k -i -m 20 -o /dev/null -s -w %{http_code} http://127.0.0.1:9080/hello)
201+
202+
if [ ! $code -eq 200 ]; then
203+
echo "failed: connection to upstream with mTLS failed"
204+
exit 1
205+
fi
206+
207+
sleep 0.1
208+
209+
make stop
210+
211+
echo "passed: connection to upstream with mTLS success"

t/core/config_etcd.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ qr/(connection refused){1,}/
6060
apisix:
6161
node_listen: 1984
6262
ssl:
63-
ssl_trusted_certificate: t/servroot/conf/cert/etcd.pem
63+
ssl_trusted_combined_path: t/servroot/conf/cert/etcd.pem
6464
deployment:
6565
role: traditional
6666
role_traditional:

0 commit comments

Comments
 (0)