This is an automated email from the ASF dual-hosted git repository.
lzx404243 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 7ccdbd30ac Added config to support exit on client cert load failure
(#10958)
7ccdbd30ac is described below
commit 7ccdbd30ac8f03667d734fa40f04f1c250eed2c8
Author: Zhengxi Li <[email protected]>
AuthorDate: Tue Feb 27 10:48:50 2024 -0500
Added config to support exit on client cert load failure (#10958)
* Added ssl.client.cert.exit_on_load option.
* Added doc for config
* Updated test run names
---
doc/admin-guide/files/records.yaml.en.rst | 6 ++
src/iocore/net/P_SSLConfig.h | 1 +
src/iocore/net/SSLConfig.cc | 10 +-
src/records/RecordsConfig.cc | 2 +
tests/gold_tests/records/gold/full_records.yaml | 1 +
.../records/legacy_config/full_records.config | 1 +
.../gold_tests/tls/exit_on_cert_load_fail.test.py | 119 +++++++++++++++++++++
7 files changed, 139 insertions(+), 1 deletion(-)
diff --git a/doc/admin-guide/files/records.yaml.en.rst
b/doc/admin-guide/files/records.yaml.en.rst
index 81c02e4fb4..93da31b31d 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -3992,6 +3992,12 @@ Client-Related Configuration
The filename of SSL client certificate installed on |TS|.
+.. ts:cv:: CONFIG proxy.config.ssl.client.cert.exit_on_load_fail INT 0
+
+ By default (``0``), |TS| will start even if problems occur when loading the
+ SSL client certificates. If true (``1``), SSL client certificate load
+ failures will prevent |TS| from starting.
+
.. ts:cv:: CONFIG proxy.config.ssl.client.cert.path STRING /config
:reloadable:
diff --git a/src/iocore/net/P_SSLConfig.h b/src/iocore/net/P_SSLConfig.h
index 7870bf9467..0fa6439979 100644
--- a/src/iocore/net/P_SSLConfig.h
+++ b/src/iocore/net/P_SSLConfig.h
@@ -96,6 +96,7 @@ struct SSLConfigParams : public ConfigInfo {
char *clientKeyPathOnly;
char *clientCACertFilename;
char *clientCACertPath;
+ int clientCertExitOnLoadError;
YamlSNIConfig::Policy verifyServerPolicy;
YamlSNIConfig::Property verifyServerProperties;
bool tls_server_connection;
diff --git a/src/iocore/net/SSLConfig.cc b/src/iocore/net/SSLConfig.cc
index df1f2299e2..fc84ce517d 100644
--- a/src/iocore/net/SSLConfig.cc
+++ b/src/iocore/net/SSLConfig.cc
@@ -129,6 +129,7 @@ SSLConfigParams::reset()
ssl_session_cache_timeout = 0;
ssl_session_cache_auto_clear = 1;
configExitOnLoadError = 1;
+ clientCertExitOnLoadError = 0;
}
void
@@ -503,6 +504,7 @@ SSLConfigParams::initialize()
ssl_client_cert_path = nullptr;
REC_ReadConfigStringAlloc(ssl_client_cert_filename,
"proxy.config.ssl.client.cert.filename");
REC_ReadConfigStringAlloc(ssl_client_cert_path,
"proxy.config.ssl.client.cert.path");
+ REC_ReadConfigInteger(clientCertExitOnLoadError,
"proxy.config.ssl.client.cert.exit_on_load_fail");
set_paths_helper(ssl_client_cert_path, ssl_client_cert_filename,
&clientCertPathOnly, &clientCertPath);
ats_free_null(ssl_client_cert_filename);
ats_free_null(ssl_client_cert_path);
@@ -543,7 +545,13 @@ SSLConfigParams::initialize()
// can cause HTTP layer to connect using SSL. But only if SSL
// initialization hasn't failed already.
client_ctx = this->getCTX(this->clientCertPath, this->clientKeyPath,
this->clientCACertFilename, this->clientCACertPath);
- if (!client_ctx) {
+ if (client_ctx) {
+ return;
+ }
+ // Can't get SSL client context.
+ if (this->clientCertExitOnLoadError) {
+ Fatal("Can't initialize the SSL client, HTTPS in remap rules will not
function");
+ } else {
SSLError("Can't initialize the SSL client, HTTPS in remap rules will not
function");
}
}
diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc
index e8a7abc8ff..7aedc3fe00 100644
--- a/src/records/RecordsConfig.cc
+++ b/src/records/RecordsConfig.cc
@@ -1134,6 +1134,8 @@ static const RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.ssl.client.verify.server.properties",
RECD_STRING, "ALL", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
+ {RECT_CONFIG, "proxy.config.ssl.client.cert.exit_on_load_fail", RECD_INT,
"0", RECU_RESTART_TS, RR_NULL, RECC_NULL, "[0-1]", RECA_NULL}
+ ,
{RECT_CONFIG, "proxy.config.ssl.client.cert.filename", RECD_STRING, nullptr,
RECU_DYNAMIC, RR_NULL, RECC_STR, "^[^[:space:]]*$", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.ssl.client.cert.path", RECD_STRING,
TS_BUILD_SYSCONFDIR, RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
diff --git a/tests/gold_tests/records/gold/full_records.yaml
b/tests/gold_tests/records/gold/full_records.yaml
index 8978d8d131..8a11d24f78 100644
--- a/tests/gold_tests/records/gold/full_records.yaml
+++ b/tests/gold_tests/records/gold/full_records.yaml
@@ -509,6 +509,7 @@ ts:
enabled: 1
alpn_protocols: null
cert:
+ exit_on_load_fail: 0
filename: null
certification_level: 0
cipher_suite:
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:DHE-RSA-AES256-CCM8:DHE-RSA-AES256-CCM:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-ARIA256-GCM-SHA384:ECDHE-ARIA256-GCM-SHA384:DHE-DSS-ARIA256-GCM-SHA384:DHE-RSA-ARIA256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AE
[...]
diff --git a/tests/gold_tests/records/legacy_config/full_records.config
b/tests/gold_tests/records/legacy_config/full_records.config
index 2c90d65e25..96376c704f 100644
--- a/tests/gold_tests/records/legacy_config/full_records.config
+++ b/tests/gold_tests/records/legacy_config/full_records.config
@@ -362,6 +362,7 @@ CONFIG proxy.config.ssl.CA.cert.filename STRING nullptr
CONFIG proxy.config.ssl.client.verify.server.policy STRING ENFORCED
CONFIG proxy.config.ssl.client.verify.server.properties STRING ALL
CONFIG proxy.config.ssl.client.cert.filename STRING nullptr
+CONFIG proxy.config.ssl.client.cert.exit_on_load_fail INT 0
CONFIG proxy.config.ssl.client.private_key.filename STRING nullptr
CONFIG proxy.config.ssl.client.CA.cert.filename STRING nullptr
CONFIG proxy.config.ssl.client.sni_policy STRING host
diff --git a/tests/gold_tests/tls/exit_on_cert_load_fail.test.py
b/tests/gold_tests/tls/exit_on_cert_load_fail.test.py
new file mode 100644
index 0000000000..f578665c48
--- /dev/null
+++ b/tests/gold_tests/tls/exit_on_cert_load_fail.test.py
@@ -0,0 +1,119 @@
+'''
+Test the exit_on_load_fail behavior for the SSL cert loading.
+'''
+# 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 os
+
+Test.Summary = '''
+Test the exit_on_load_fail behavior for the SSL cert loading.
+'''
+
+
+class Test_exit_on_cert_load_fail:
+ """Configure a test to verify behavior of SSL cert load failures."""
+
+ ts_counter: int = 0
+
+ def __init__(self, name: str, is_testing_server_side: bool,
enable_exit_on_load=False):
+ """
+ Initialize the test.
+ :param name: The name of the test.
+ :param is_testing_server_side: Whether to test the server side or
client side cert loading.
+ enable_exit_on_load: Whether to enable the exit_on_load_fail config.
+ """
+ self.name = name
+ self.is_testing_server_side = is_testing_server_side
+ self.enable_exit_on_load = enable_exit_on_load
+
+ def _configure_traffic_server(self, tr: 'TestRun'):
+ """Configure Traffic Server.
+
+ :param tr: The TestRun object to associate the ts process with.
+ """
+ ts = tr.MakeATSProcess(f"ts-{Test_exit_on_cert_load_fail.ts_counter}",
enable_tls=True)
+ Test_exit_on_cert_load_fail.ts_counter += 1
+ self._ts = ts
+ client_cert_path = 'NULL'
+ enable_exit_on_server_cert_load_failure = 1 if
self.enable_exit_on_load and self.is_testing_server_side else 0
+ enable_exit_on_client_cert_load_failure = 1 if
self.enable_exit_on_load and not self.is_testing_server_side else 0
+
+ if not self.is_testing_server_side:
+ # Point to a non-existent cert to force a load failure.
+ client_cert_path = f'{ts.Variables.SSLDir}/non-existent-cert.pem'
+ # Also setup the server certs so that issues are limited to client
+ # cert loading.
+ self._ts.addDefaultSSLFiles()
+ self._ts.Disk.ssl_multicert_config.AddLine('dest_ip=*
ssl_cert_name=server.pem ssl_key_name=server.key')
+ self._ts.Disk.records_config.update(
+ {
+ 'proxy.config.ssl.server.cert.path': f'{ts.Variables.SSLDir}',
+ 'proxy.config.ssl.server.private_key.path':
f'{ts.Variables.SSLDir}',
+ 'proxy.config.ssl.client.cert.filename': client_cert_path,
+ 'proxy.config.ssl.server.multicert.exit_on_load_fail':
enable_exit_on_server_cert_load_failure,
+ 'proxy.config.ssl.client.cert.exit_on_load_fail':
enable_exit_on_client_cert_load_failure,
+ })
+ # The cert loading happen on startup, so the remap rule is not
+ # triggered.
+ RANDOM_PORT = 12345
+ self._ts.Disk.remap_config.AddLine(f'map /
https://127.0.0.1:{RANDOM_PORT}/')
+
+ def run(self):
+ """Run the test."""
+ tr = Test.AddTestRun(self.name)
+ self._configure_traffic_server(tr)
+
+ # The client process can be anything.
+ tr.Processes.Default.Command = "echo"
+ tr.Processes.Default.StartAfter(self._ts,
ready=When.FileExists(self._ts.Disk.diags_log))
+
+ # Override the default exclusion of error log.
+ self._ts.Disk.diags_log.Content = Testers.ContainsExpression("ERROR:",
"These tests should have error logs.")
+
+ if self.enable_exit_on_load:
+ self._ts.ReturnCode = 70
+ self._ts.Disk.diags_log.Content += Testers.ContainsExpression(
+ "FATAL: ", "Failure loading the certs results in a fatal
error.")
+ self._ts.Disk.diags_log.Content += Testers.ExcludesExpression(
+ "Traffic Server is fully initialized", "Traffic Server should
exit upon the load failure.")
+ else:
+ self._ts.ReturnCode = 0
+ self._ts.Disk.diags_log.Content += Testers.ContainsExpression(
+ "Traffic Server is fully initialized", "Traffic Server should
start up successfully.")
+
+ if self.is_testing_server_side:
+ self._ts.Disk.diags_log.Content += Testers.ContainsExpression(
+ "ERROR:.*failed to load", "Verify that there is a cert loading
issue.")
+ else:
+ self._ts.Disk.diags_log.Content += Testers.ContainsExpression(
+ "ERROR: failed to access cert", "Verify that there is a cert
loading issue.")
+ self._ts.Disk.diags_log.Content += Testers.ContainsExpression(
+ "Can't initialize the SSL client, HTTPS in remap rules will
not function",
+ "There should be an error loading the cert.")
+
+
+# Test server cert loading.
+Test_exit_on_cert_load_fail(
+ "load server cert with exit on load disabled",
is_testing_server_side=True, enable_exit_on_load=False).run()
+Test_exit_on_cert_load_fail(
+ "load server cert with exit on load enabled", is_testing_server_side=True,
enable_exit_on_load=True).run()
+
+# Test client cert loading.
+Test_exit_on_cert_load_fail(
+ "load client cert with exit on load disabled",
is_testing_server_side=False, enable_exit_on_load=False).run()
+Test_exit_on_cert_load_fail(
+ "load client cert with exit on load enabled",
is_testing_server_side=False, enable_exit_on_load=True).run()