This is an automated email from the ASF dual-hosted git repository. ashishtiwari pushed a commit to branch revolyssup/use-system-defined-certs in repository https://gitbox.apache.org/repos/asf/apisix.git
commit 718e25cd4a56031c57b74eedbae1e58a45b0f503 Author: Ashish Tiwari <[email protected]> AuthorDate: Thu Oct 17 15:25:51 2024 +0530 feat: add support for "system" ssl_trusted_certificate This feature allows passing the system certs by default and using multiple available CA certs with ssl.ssl_trusted_certificate field --- apisix/cli/ops.lua | 33 +++++++++++++++++++------ apisix/cli/schema.lua | 3 +++ apisix/cli/util.lua | 40 ++++++++++++++++++++++++++++++ conf/config.yaml.example | 6 ++--- t/cli/test_stream_config.sh | 3 ++- t/cli/test_upstream_mtls.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 12 deletions(-) diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua index 16547fce3..0ea688ba4 100644 --- a/apisix/cli/ops.lua +++ b/apisix/cli/ops.lua @@ -502,17 +502,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") + if not pl_path.exists(cert_path) then + util.die("certificate path", cert_path, "doesn't exist\n") + end + + 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..f8a0a2aec 100644 --- a/apisix/cli/util.lua +++ b/apisix/cli/util.lua @@ -133,4 +133,44 @@ 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 + } + + function _M.get_system_trusted_certs_filepath() + for _, path in ipairs(trusted_certs_paths) do + if _M.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 44005ffd0..2c23ad45e 100644 --- a/conf/config.yaml.example +++ b/conf/config.yaml.example @@ -99,9 +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_protocols: TLSv1.2 TLSv1.3 # TLS versions supported. + 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_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. # Disabled by default because it renders Perfect Forward Secrecy (FPS) 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"
