summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRemi Tricot-Le Breton <rlebreton@haproxy.com>2023-02-28 17:46:25 +0100
committerWilliam Lallemand <wlallemand@haproxy.org>2023-03-02 15:37:19 +0100
commitb33fe2f4a218f201bb8c0b16718a8e581ddcb3b5 (patch)
treee19a4eac463dfa6b022173b365acf31ed8d07eb8
parentd42c896216fda687bee8252b3daaf22acdb17e2c (diff)
downloadhaproxy-b33fe2f4a218f201bb8c0b16718a8e581ddcb3b5.tar.gz
MINOR: ssl: Use dedicated proxy and log-format for OCSP update
Instead of using the same proxy as other http client calls (through lua for instance), the OCSP update will use a dedicated proxy which will enable it to change the log format and log conditions (for instance). This proxy will have the NOLOGNORM option and regular logging will be managed by the update task itself because in order to dump information related to OCSP updates, we need to control the moment when the logs are emitted (instead or relying on the stream's life which is decorrelated from the update itself). The update task then calls sess_log directly, which uses a dedicated ocsp logformat that fetches specific OCSP data. Sess_log was preferred to the more low level app_log because it offers the strength of "regular" sample fetches and allows to add generic information alongside OCSP ones in the log line. In case of connection error (unreachable server for instance), a regular httpclient log line will also be emitted. This line will have some extra HTTP related info that can't be provided by the ocsp update logging mechanism.
-rw-r--r--doc/configuration.txt12
-rw-r--r--src/ssl_ocsp.c50
2 files changed, 60 insertions, 2 deletions
diff --git a/doc/configuration.txt b/doc/configuration.txt
index e7a399343..4538af74e 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -14947,6 +14947,18 @@ ocsp-update [ off | on ]
On the other hand, if a certificate has an OCSP uri specified and no OCSP
response, setting this option to 'on' for the given certificate will ensure
that the OCSP response gets fetched automatically right after init.
+ Whenever an OCSP response is updated by the auto update task, a dedicated log
+ line is emitted. It will follow a dedicated log-format that looks like the
+ following "%ci:%cp [%tr] %ft %[ssl_ocsp_certid] %[ssl_ocsp_status]
+ %{+Q}[ssl_ocsp_status_str] %[ssl_ocsp_fail_cnt] %[ssl_ocsp_success_cnt]". The
+ specified "ssl_ocsp" sample fetches are not "public" because they cannot have
+ valid values when fetched out of the OCSP auto update process. Here is an
+ example of such a log line (with the longer outputs truncated for
+ readability):
+ <134>Feb 13 16:20:21 haproxy[37352]: -:- [13/Feb/2023:16:20:20.311] <HC_OCSP> \
+ 303B30090[...] 2 "HTTP error" 0 0
+ See "show ssl ocsp-updates" CLI command for a full list of error codes and
+ error messages.
prefer-client-ciphers
Use the client's preference when selecting the cipher suite, by default
diff --git a/src/ssl_ocsp.c b/src/ssl_ocsp.c
index 131f7aa47..54b7cca34 100644
--- a/src/ssl_ocsp.c
+++ b/src/ssl_ocsp.c
@@ -774,6 +774,7 @@ end:
*/
struct task *ocsp_update_task __read_mostly = NULL;
+static struct proxy *httpclient_ocsp_update_px;
static struct ssl_ocsp_task_ctx {
struct certificate_ocsp *cur_ocsp;
@@ -982,6 +983,22 @@ void ocsp_update_response_end_cb(struct httpclient *hc)
task_wakeup(task, TASK_WOKEN_MSG);
}
+
+/*
+ * Send a log line that will use the dedicated proxy's error_logformat string.
+ * It uses the sess_log function instead of app_log for instance in order to
+ * benefit from the "generic" items that can be added to a log format line such
+ * as the date and frontend name that can be found at the beginning of the
+ * ocspupdate_log_format line.
+ */
+static void ssl_ocsp_send_log()
+{
+ if (!ssl_ocsp_task_ctx.appctx)
+ return;
+
+ sess_log(ssl_ocsp_task_ctx.appctx->sess);
+}
+
/*
* This is the main function of the ocsp auto update mechanism. It has two
* distinct parts and the branching to one or the other is completely based on
@@ -1074,6 +1091,8 @@ static struct task *ssl_ocsp_update_responses(struct task *task, void *context,
ctx->update_status = OCSP_UPDT_OK;
ocsp->last_update_status = ctx->update_status;
+ ssl_ocsp_send_log();
+
/* Reinsert the entry into the update list so that it can be updated later */
ssl_ocsp_update_insert(ocsp);
/* Release the reference kept on the updated ocsp response. */
@@ -1152,7 +1171,9 @@ static struct task *ssl_ocsp_update_responses(struct task *task, void *context,
/* Depending on the processing that occurred in
* ssl_ocsp_create_request_details we could either have to send
* a GET or a POST request. */
- hc = httpclient_new(task, b_data(req_body) ? HTTP_METH_POST : HTTP_METH_GET, ist2(b_orig(req_url), b_data(req_url)));
+ hc = httpclient_new_from_proxy(httpclient_ocsp_update_px, task,
+ b_data(req_body) ? HTTP_METH_POST : HTTP_METH_GET,
+ ist2(b_orig(req_url), b_data(req_url)));
if (!hc) {
goto leave;
}
@@ -1202,6 +1223,7 @@ wait:
return task;
http_error:
+ ssl_ocsp_send_log();
/* Reinsert certificate into update list so that it can be updated later */
if (ocsp) {
++ocsp->num_failure;
@@ -1230,6 +1252,28 @@ http_error:
return task;
}
+char ocspupdate_log_format[] = "%ci:%cp [%tr] %ft %[ssl_ocsp_certid] %[ssl_ocsp_status] %{+Q}[ssl_ocsp_status_str] %[ssl_ocsp_fail_cnt] %[ssl_ocsp_success_cnt]";
+
+/*
+ * Initialize the proxy for the OCSP update HTTP client with 2 servers, one for
+ * raw HTTP, the other for HTTPS.
+ */
+static int ssl_ocsp_update_precheck()
+{
+ /* initialize the OCSP update dedicated httpclient */
+ httpclient_ocsp_update_px = httpclient_create_proxy("<HC_OCSP>");
+ if (!httpclient_ocsp_update_px)
+ return 1;
+ httpclient_ocsp_update_px->conf.error_logformat_string = strdup(ocspupdate_log_format);
+ httpclient_ocsp_update_px->conf.logformat_string = httpclient_log_format;
+ httpclient_ocsp_update_px->options2 |= PR_O2_NOLOGNORM;
+
+ return 0;
+}
+
+/* initialize the proxy and servers for the HTTP client */
+
+REGISTER_PRE_CHECK(ssl_ocsp_update_precheck);
@@ -1393,7 +1437,9 @@ static int cli_parse_update_ocsp_response(char **args, char *payload, struct app
goto end;
}
- hc = httpclient_new(appctx, b_data(req_body) ? HTTP_METH_POST : HTTP_METH_GET, ist2(b_orig(req_url), b_data(req_url)));
+ hc = httpclient_new_from_proxy(httpclient_ocsp_update_px, appctx,
+ b_data(req_body) ? HTTP_METH_POST : HTTP_METH_GET,
+ ist2(b_orig(req_url), b_data(req_url)));
if (!hc) {
memprintf(&err, "%sCan't allocate httpclient\n", err ? err : "");
goto end;