This is an automated email from the ASF dual-hosted git repository.

wenming 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 aaad8ba42 feat: add support for "system" ssl_trusted_certificate 
(#11809)
aaad8ba42 is described below

commit aaad8ba4276452a608649511a1d210eb2e4fddb8
Author: Ashish Tiwari <[email protected]>
AuthorDate: Mon Dec 9 15:05:51 2024 +0530

    feat: add support for "system" ssl_trusted_certificate (#11809)
---
 apisix/cli/ops.lua          | 36 +++++++++++++++++++++------
 apisix/cli/schema.lua       |  3 +++
 apisix/cli/util.lua         | 53 +++++++++++++++++++++++++++++++++++++++
 conf/config.yaml.example    |  5 ++--
 t/cli/test_stream_config.sh |  3 ++-
 t/cli/test_upstream_mtls.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++
 t/core/config_etcd.t        |  2 +-
 7 files changed, 150 insertions(+), 12 deletions(-)

diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index 16547fce3..c10bcfaa7 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -49,6 +49,9 @@ local str_find = string.find
 local str_byte = string.byte
 local str_sub = string.sub
 local str_format = string.format
+local string = string
+local table = table
+
 
 local _M = {}
 
@@ -502,17 +505,34 @@ Please modify "admin_key" in conf/config.yaml .
 
 
     if yaml_conf.apisix.ssl.ssl_trusted_certificate ~= nil then
-        local cert_path = yaml_conf.apisix.ssl.ssl_trusted_certificate
-        -- During validation, the path is relative to PWD
-        -- When Nginx starts, the path is relative to conf
-        -- Therefore we need to check the absolute version instead
-        cert_path = pl_path.abspath(cert_path)
+        local cert_paths = {}
+        local ssl_certificates = yaml_conf.apisix.ssl.ssl_trusted_certificate
+        for cert_path in string.gmatch(ssl_certificates, '([^,]+)') do
+            cert_path = util.trim(cert_path)
+            if cert_path == "system" then
+                local trusted_certs_path, err = 
util.get_system_trusted_certs_filepath()
+                if not trusted_certs_path then
+                    util.die(err)
+                end
+                table.insert(cert_paths, trusted_certs_path)
+            else
+                -- During validation, the path is relative to PWD
+                -- When Nginx starts, the path is relative to conf
+                -- Therefore we need to check the absolute version instead
+                cert_path = pl_path.abspath(cert_path)
+                if not pl_path.exists(cert_path) then
+                    util.die("certificate path", cert_path, "doesn't exist\n")
+                end
 
-        if not pl_path.exists(cert_path) then
-            util.die("certificate path", cert_path, "doesn't exist\n")
+                table.insert(cert_paths, cert_path)
+            end
         end
 
-        yaml_conf.apisix.ssl.ssl_trusted_certificate = cert_path
+        local combined_cert_filepath = 
yaml_conf.apisix.ssl.ssl_trusted_combined_path
+                                       or 
"/usr/local/apisix/conf/ssl_trusted_combined.pem"
+        util.gen_trusted_certs_combined_file(combined_cert_filepath, 
cert_paths)
+
+        yaml_conf.apisix.ssl.ssl_trusted_certificate = combined_cert_filepath
     end
 
     -- enable ssl with place holder crt&key
diff --git a/apisix/cli/schema.lua b/apisix/cli/schema.lua
index e6720f88f..1def95484 100644
--- a/apisix/cli/schema.lua
+++ b/apisix/cli/schema.lua
@@ -209,6 +209,9 @@ local config_schema = {
                         ssl_trusted_certificate = {
                             type = "string",
                         },
+                        ssl_trusted_combined_path = {
+                            type = "string",
+                        },
                         listen = {
                             type = "array",
                             items = {
diff --git a/apisix/cli/util.lua b/apisix/cli/util.lua
index bcd56a241..d69468efb 100644
--- a/apisix/cli/util.lua
+++ b/apisix/cli/util.lua
@@ -24,6 +24,9 @@ local exit = os.exit
 local stderr = io.stderr
 local str_format = string.format
 local tonumber = tonumber
+local io = io
+local ipairs = ipairs
+local assert = assert
 
 local _M = {}
 
@@ -133,4 +136,54 @@ function _M.file_exists(file_path)
     return f ~= nil and close(f)
 end
 
+do
+    local trusted_certs_paths = {
+        "/etc/ssl/certs/ca-certificates.crt",                -- 
Debian/Ubuntu/Gentoo
+        "/etc/pki/tls/certs/ca-bundle.crt",                  -- Fedora/RHEL 6
+        "/etc/ssl/ca-bundle.pem",                            -- OpenSUSE
+        "/etc/pki/tls/cacert.pem",                           -- OpenELEC
+        "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", -- CentOS/RHEL 7
+        "/etc/ssl/cert.pem",                                 -- OpenBSD, Alpine
+    }
+
+    -- Check if a file exists using Lua's built-in `io.open`
+    local function file_exists(path)
+        local file = io.open(path, "r")
+        if file then
+            file:close()
+            return true
+        else
+            return false
+        end
+    end
+
+    function _M.get_system_trusted_certs_filepath()
+        for _, path in ipairs(trusted_certs_paths) do
+            if file_exists(path) then
+                return path
+            end
+        end
+
+        return nil,
+            "Could not find trusted certs file in " ..
+            "any of the `system`-predefined locations. " ..
+            "Please install a certs file there or set " ..
+            "`lua_ssl_trusted_certificate` to a " ..
+            "specific file path instead of `system`"
+    end
+end
+
+
+function _M.gen_trusted_certs_combined_file(combined_filepath, paths)
+    local combined_file = assert(io.open(combined_filepath, "w"))
+    for _, path in ipairs(paths) do
+        local cert_file = assert(io.open(path, "r"))
+        combined_file:write(cert_file:read("*a"))
+        combined_file:write("\n")
+        cert_file:close()
+    end
+    combined_file:close()
+end
+
+
 return _M
diff --git a/conf/config.yaml.example b/conf/config.yaml.example
index eea2335bc..d6846642f 100644
--- a/conf/config.yaml.example
+++ b/conf/config.yaml.example
@@ -99,8 +99,9 @@ apisix:
       # - ip: 127.0.0.3                           # If not set, default to 
`0.0.0.0`.
       #   port: 9445
       #   enable_http3: true
-    # ssl_trusted_certificate: /path/to/ca-cert   # Set the path to CA 
certificates used to verify client
-                                                  # certificates in the PEM 
format.
+    ssl_trusted_combined_path: /usr/local/apisix/conf/ssl_trusted_combined.pem 
# All the trusted certificates will be combined into a single file
+    #ssl_trusted_certificate: system              # Specifies comma separated 
list of trusted CA. Value can be either "system"(for using system available ca 
certs) or
+                                                # a file path with trusted CA 
certificates in the PEM format
     ssl_protocols: TLSv1.2 TLSv1.3                # TLS versions supported.
     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  # If true, session tickets are used for 
SSL/TLS connections.
diff --git a/t/cli/test_stream_config.sh b/t/cli/test_stream_config.sh
index baab138a0..2843b5c5d 100755
--- a/t/cli/test_stream_config.sh
+++ b/t/cli/test_stream_config.sh
@@ -78,6 +78,7 @@ echo "
 apisix:
     ssl:
         ssl_trusted_certificate: t/certs/mtls_ca.crt
+        ssl_trusted_combined_path: t/certs/mtls_ca_combined.crt
     proxy_mode: http&stream
     stream_proxy:
         tcp:
@@ -86,7 +87,7 @@ apisix:
 
 make init
 
-if ! grep "t/certs/mtls_ca.crt;" conf/nginx.conf > /dev/null; then
+if ! grep "t/certs/mtls_ca_combined.crt;" conf/nginx.conf > /dev/null; then
     echo "failed: failed to set trust certificate"
     exit 1
 fi
diff --git a/t/cli/test_upstream_mtls.sh b/t/cli/test_upstream_mtls.sh
index 0318a4539..b2b366aa0 100755
--- a/t/cli/test_upstream_mtls.sh
+++ b/t/cli/test_upstream_mtls.sh
@@ -149,3 +149,63 @@ if ! grep -E 'self-signed certificate' logs/error.log; then
 fi
 
 echo "passed: when proxy_ssl_verify is enabled and ssl_trusted_certificate is 
wrong ca cert, got 502"
+
+
+#  test combined proxy_ssl_trusted_certificate success
+echo '
+apisix:
+  ssl:
+    ssl_trusted_certificate: system, t/certs/apisix.crt
+nginx_config:
+  http_configuration_snippet: |
+    server {
+        listen 1983 ssl;
+        server_name test.com;
+        ssl_certificate             ../t/certs/apisix.crt;
+        ssl_certificate_key         ../t/certs/apisix.key;
+        location /hello {
+            return 200 "hello world";
+        }
+    }
+  http_server_configuration_snippet: |
+    proxy_ssl_verify on;
+' > conf/config.yaml
+
+rm logs/error.log || true
+make init
+make run
+sleep 0.1
+
+curl -k -i http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: 
edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
+{
+    "uri": "/hello",
+    "upstream": {
+        "pass_host": "rewrite",
+        "nodes": {
+            "127.0.0.1:1983": 1
+        },
+        "scheme": "https",
+        "hash_on": "vars",
+        "upstream_host": "test.com",
+        "type": "roundrobin",
+        "tls": {
+            "client_cert": "-----BEGIN 
CERTIFICATE-----\nMIIEojCCAwqgAwIBAgIJAK253pMhgCkxMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV\nBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxDzANBgNVBAcMBlpodUhhaTEPMA0G\nA1UECgwGaXJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTAgFw0xOTA2MjQyMjE4MDVa\nGA8yMTE5MDUzMTIyMTgwNVowVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5n\nRG9uZzEPMA0GA1UEBwwGWmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMM\nCHRlc3QuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCM0rqJe\ncvgnCfOw4fATotPwk5Ba0gC2YvIrO+gSbQkyxXF
 [...]
+            "client_key": 
"HrMHUvE9Esvn7GnZ+vAynaIg/8wlB3r0zm0htmnwofYLp1VhtLeU1EmMJkPLUkcn2+v6Uav9bOQMkPdSpUMcEpRplLSXs+miu+B07CCUnsMrXkfQawRMIoePJZSLH5+PfDAlWIK2Q+ruYnjtnpNziiAtXf/HRRwHHMelnfedXqD8kn3Toe46ZYyBir99o/r/do5ludez5oY7qhOgNSWKCfnZE8Ip82g7t7n7jsAf5tTdRulUGBQ4ITV2zM3cxpD0PWnWMbOfygZIDxR8QU9wj8ihuFL1s1NM8PplcKbUxC4QlrSN+ZNkr6mxy+akPmXlABwcFIiSK7c/xvU1NjoILnhPpL6aRpbhmQX/a1XUCl+2INlQ5QbXbTN+JmDBhrU9NiYecRJMfmA1N/lhwgt01tUnxMoAhfpUVgEbZNalCJt+wn8TC+Xp3DZ0bCpXrfzqsprGKan9qC3mCN03j
 [...]
+        }
+    }
+}'
+
+sleep 1
+
+code=$(curl -v -k -i -m 20 -o /dev/null -s -w %{http_code} 
http://127.0.0.1:9080/hello)
+
+if [ ! $code -eq 200 ]; then
+    echo "failed: connection to upstream with mTLS failed"
+    exit 1
+fi
+
+sleep 0.1
+
+make stop
+
+echo "passed: connection to upstream with mTLS success"
diff --git a/t/core/config_etcd.t b/t/core/config_etcd.t
index 7f31fc859..75b0e9bb6 100644
--- a/t/core/config_etcd.t
+++ b/t/core/config_etcd.t
@@ -60,7 +60,7 @@ qr/(connection refused){1,}/
 apisix:
   node_listen: 1984
   ssl:
-    ssl_trusted_certificate: t/servroot/conf/cert/etcd.pem
+    ssl_trusted_combined_path: t/servroot/conf/cert/etcd.pem
 deployment:
   role: traditional
   role_traditional:

Reply via email to