]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl/log: add keylog format variables and env vars
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 1 Apr 2026 08:56:24 +0000 (10:56 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Wed, 1 Apr 2026 14:28:49 +0000 (16:28 +0200)
Add keylog_format_fc and keylog_format_bc global variables containing
the SSLKEYLOGFILE log-format strings for the frontend (client-facing)
and backend (server-facing) TLS connections respectively. These produce
output compatible with the SSLKEYLOGFILE format described at:
https://tlswg.org/sslkeylogfile/draft-ietf-tls-keylogfile.html

Both formats are also exported as environment variables at startup:
  HAPROXY_KEYLOG_FC_LOG_FMT
  HAPROXY_KEYLOG_BC_LOG_FMT

These variables contains \n so they might not be compatible with syslog
servers, using them with stderr or a sink might be required.

These can be referenced directly in "log-format" directives to produce
SSLKEYLOGFILE-compatible output, usable by network analyzers such as
Wireshark to decrypt captured TLS traffic.

doc/configuration.txt
examples/keylog-test.cfg [new file with mode: 0644]
include/haproxy/log.h
src/haproxy.c
src/log.c

index 14885de9591170e12e1c2234c5e0add180cde4de..990edef75992f5a2ab3d589c78c3ff3c15342c2e 100644 (file)
@@ -990,23 +990,26 @@ within conditional blocks and not to reference them in the global section's
 The table below summaries the status of each variable for the different working
 modes:
 
-  +--------------------------+---------+------------+-----------+
-  |        variable          | usable  | modifiable |  listed   |
-  |                          +---------+------------+-----------+
-  |                          |  M | W  |   M  |  W  |  M  |  W  |
-  +--------------------------+----+----+------+-----+-----+-----+
-  | HAPROXY_STARTUP_VERSION  |  X | X  |      |     |  X  |  X  |
-  | HAPROXY_BRANCH           |  X | X  |      |     |  X  |  X  |
-  | HAPROXY_CFGFILES         |    |    |      |     |  X  |  X  |
-  | HAPROXY_MWORKER          |    |    |      |     |  X  |  X  |
-  | HAPROXY_CLI              |    |    |      |     |     |  X  |
-  | HAPROXY_MASTER_CLI       |    |    |      |     |  X  |     |
-  | HAPROXY_LOCALPEER        |    | X  |      |     |     |  X  |
-  | HAPROXY_HTTP_LOG_FMT     |    | X  |      |  X  |     |     |
-  | HAPROXY_HTTP_CLF_LOG_FMT |    | X  |      |  X  |     |     |
-  | HAPROXY_HTTPS_LOG_FMT    |    | X  |      |  X  |     |     |
-  | HAPROXY_TCP_LOG_FMT      |    | X  |      |  X  |     |     |
-  +--------------------------+----+----+------+-----+-----+-----+
+  +---------------------------+---------+------------+-----------+
+  |          variable         | usable  | modifiable |  listed   |
+  |                           +---------+------------+-----------+
+  |                           |  M | W  |   M  |  W  |  M  |  W  |
+  +---------------------------+----+----+------+-----+-----+-----+
+  | HAPROXY_STARTUP_VERSION   |  X | X  |      |     |  X  |  X  |
+  | HAPROXY_BRANCH            |  X | X  |      |     |  X  |  X  |
+  | HAPROXY_CFGFILES          |    |    |      |     |  X  |  X  |
+  | HAPROXY_MWORKER           |    |    |      |     |  X  |  X  |
+  | HAPROXY_CLI               |    |    |      |     |     |  X  |
+  | HAPROXY_MASTER_CLI        |    |    |      |     |  X  |     |
+  | HAPROXY_LOCALPEER         |    | X  |      |     |     |  X  |
+  | HAPROXY_HTTP_LOG_FMT      |    | X  |      |  X  |     |     |
+  | HAPROXY_HTTP_CLF_LOG_FMT  |    | X  |      |  X  |     |     |
+  | HAPROXY_HTTPS_LOG_FMT     |    | X  |      |  X  |     |     |
+  | HAPROXY_TCP_LOG_FMT       |    | X  |      |  X  |     |     |
+  | HAPROXY_TCP_CLF_LOG_FMT   |    | X  |      |  X  |     |     |
+  | HAPROXY_KEYLOG_FC_LOG_FMT |    | X  |      |  X  |     |     |
+  | HAPROXY_KEYLOG_BC_LOG_FMT |    | X  |      |  X  |     |     |
+  +---------------------------+----+----+------+-----+-----+-----+
 
 The variables in question are the following:
 
@@ -1039,6 +1042,16 @@ The variables in question are the following:
   * HAPROXY_TCP_CLF_LOG_FMT: similar to HAPROXY_HTTP_CLF_LOG_FMT but for TCP
     CLF log format as defined in section 8.2.2 "TCP log format".
 
+  * HAPROXY_KEYLOG_FC_LOG_FMT: contains the keylog format for the frontend
+    (client-facing) TLS connection, with key entries separated by newlines so
+    it might not be compatible with your syslog server. "tune.ssl.keylog on" is
+    required.
+
+  * HAPROXY_KEYLOG_BC_LOG_FMT: similar to HAPROXY_KEYLOG_FC_LOG_FMT but for the
+    backend (server-facing) TLS connection. Key entries are separated by
+    newlines so it might not be compatible with your syslog server.
+    "tune.ssl.keylog on" is required.
+
   * HAPROXY_MWORKER: In master-worker mode, this variable is set to 1.
 
   * HAPROXY_CLI: configured listeners addresses of the stats socket of every
@@ -5531,6 +5544,12 @@ tune.ssl.keylog { on | off }
                 EXPORTER_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_exporter_secret]\n
                 EARLY_EXPORTER_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_early_exporter_secret]"
 
+  HAProxy also provides the above formats as predefined environment variables
+  that can be used directly in a "log-format" directive:
+
+    $HAPROXY_KEYLOG_FC_LOG_FMT   frontend (client-facing) connection keys
+    $HAPROXY_KEYLOG_BC_LOG_FMT   backend (server-facing) connection keys
+
 tune.ssl.lifetime <timeout>
   Sets how long a cached SSL session may remain valid. This time is expressed
   in seconds and defaults to 300 (5 min). It is important to understand that it
diff --git a/examples/keylog-test.cfg b/examples/keylog-test.cfg
new file mode 100644 (file)
index 0000000..0e615d0
--- /dev/null
@@ -0,0 +1,69 @@
+# Example: log HTTP traffic and TLS session keys to separate destinations
+#
+# "option httpslog" sends HTTP access logs to the /dev/log syslog server.
+# TLS session keys are written to 2 ring buffers.
+#
+# Requirements:
+#   - HAProxy built with OpenSSL support
+#   - "tune.ssl.keylog on" in the global section
+#
+# Retrieve TLS session keys from the ring buffer via the CLI:
+#   For frontend connections:
+#
+#   (echo "show events keylog-fc -w"; read) | socat /tmp/worker.socket -
+#
+#   For backend connections:
+#
+#   (echo "show events keylog-bc -w"; read) | socat /tmp/worker.socket -
+#
+# The result is in SSLKEYLOGFILE format and can be saved to a file and loaded
+# into Wireshark to decrypt captured TLS traffic.
+
+global
+    stats socket /tmp/worker.socket mode 0660
+    tune.ssl.keylog on
+
+# Ring buffer for TLS session keys.
+# "format raw" stores only the log message text, without any syslog envelope,
+# producing output in the SSLKEYLOGFILE format directly.
+ring keylog-fc
+    description "TLS session key frontend log"
+    format raw
+    maxlen 2000
+    size 1M
+
+ring keylog-bc
+    description "TLS session key backend log"
+    format raw
+    maxlen 2000
+    size 1M
+
+
+defaults
+    mode http
+    timeout client  30s
+    timeout server  30s
+    timeout connect  5s
+
+log-profile keylog-fc
+    on any format "${HAPROXY_KEYLOG_FC_LOG_FMT}"
+
+log-profile keylog-bc
+    on any format "${HAPROXY_KEYLOG_BC_LOG_FMT}"
+
+frontend https-in
+    bind :443 ssl crt "common.pem"
+
+    option httpslog
+
+    # HTTPs access logs sent to the syslog server
+    log /dev/log format raw local0
+
+    # TLS session keys written to the ring buffer
+    log ring@keylog-fc profile keylog-fc local1
+    log ring@keylog-bc profile keylog-bc local1
+
+    default_backend be1
+
+backend be1
+    server s1 10.0.0.123:443 ssl verify none
index aec00e6ab3a94abe1a5f45031d34fa83c4ba6b91..8a36518027a121e12966220dbb0be0348e0ecc26 100644 (file)
@@ -42,6 +42,8 @@ extern char clf_tcp_log_format[];
 extern char default_http_log_format[];
 extern char clf_http_log_format[];
 extern char default_https_log_format[];
+extern char keylog_format_fc[];
+extern char keylog_format_bc[];
 
 extern char default_rfc5424_sd_log_format[];
 
index 2145cbadf4087f8fecf312671875bfed88d8bae8..39d1a0ac6a2b24feeceb18083886ca4e7d108664 100644 (file)
@@ -1121,6 +1121,8 @@ static int read_cfg()
        setenv("HAPROXY_HTTPS_LOG_FMT", default_https_log_format, 1);
        setenv("HAPROXY_TCP_LOG_FMT", default_tcp_log_format, 1);
        setenv("HAPROXY_TCP_CLF_LOG_FMT", clf_tcp_log_format, 1);
+       setenv("HAPROXY_KEYLOG_FC_LOG_FMT", keylog_format_fc, 1);
+       setenv("HAPROXY_KEYLOG_BC_LOG_FMT", keylog_format_bc, 1);
        setenv("HAPROXY_BRANCH", PRODUCT_BRANCH, 1);
        list_for_each_entry(cfg, &cfg_cfgfiles, list) {
                int ret;
index a544ea18cdbe37422df3cf5b3ec07244f9ecf1d3..5094c556a96228573033fc77198f52519ef4ceb9 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -334,6 +334,23 @@ char default_tcp_log_format[] = "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%
 char clf_tcp_log_format[] = "%{+Q}o %{-Q}ci - - [%T] \"TCP \" 000 %B \"\" \"\" %cp %ms %ft %b %s %Th %Tw %Tc %Tt %U %ts-- %ac %fc %bc %sc %rc %sq %bq \"\" \"\" ";
 char *log_format = NULL;
 
+char keylog_format_bc[] = "CLIENT_EARLY_TRAFFIC_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_client_early_traffic_secret]\n"
+                          "CLIENT_HANDSHAKE_TRAFFIC_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_client_handshake_traffic_secret]\n"
+                          "SERVER_HANDSHAKE_TRAFFIC_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_server_handshake_traffic_secret]\n"
+                          "CLIENT_TRAFFIC_SECRET_0 %[ssl_bc_client_random,hex] %[ssl_bc_client_traffic_secret_0]\n"
+                          "SERVER_TRAFFIC_SECRET_0 %[ssl_bc_client_random,hex] %[ssl_bc_server_traffic_secret_0]\n"
+                          "EXPORTER_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_exporter_secret]\n"
+                          "EARLY_EXPORTER_SECRET %[ssl_bc_client_random,hex] %[ssl_bc_early_exporter_secret]";
+
+char keylog_format_fc[] = "CLIENT_EARLY_TRAFFIC_SECRET %[ssl_fc_client_random,hex] %[ssl_fc_client_early_traffic_secret]\n"
+                          "CLIENT_HANDSHAKE_TRAFFIC_SECRET %[ssl_fc_client_random,hex] %[ssl_fc_client_handshake_traffic_secret]\n"
+                          "SERVER_HANDSHAKE_TRAFFIC_SECRET %[ssl_fc_client_random,hex] %[ssl_fc_server_handshake_traffic_secret]\n"
+                          "CLIENT_TRAFFIC_SECRET_0 %[ssl_fc_client_random,hex] %[ssl_fc_client_traffic_secret_0]\n"
+                          "SERVER_TRAFFIC_SECRET_0 %[ssl_fc_client_random,hex] %[ssl_fc_server_traffic_secret_0]\n"
+                          "EXPORTER_SECRET %[ssl_fc_client_random,hex] %[ssl_fc_exporter_secret]\n"
+                          "EARLY_EXPORTER_SECRET %[ssl_fc_client_random,hex] %[ssl_fc_early_exporter_secret]";
+
+
 /* Default string used for structured-data part in RFC5424 formatted
  * syslog messages.
  */
@@ -351,7 +368,9 @@ static inline int logformat_str_isdefault(const char *str)
               str == clf_http_log_format ||
               str == default_tcp_log_format ||
               str == clf_tcp_log_format ||
-              str == default_rfc5424_sd_log_format;
+              str == default_rfc5424_sd_log_format ||
+              str == keylog_format_bc ||
+              str == keylog_format_fc;
 }
 
 /* free logformat str if it is not a default (static) one */