MINOR: ssl: Add global options to modify ocsp update min/max delay
The minimum and maximum delays between two automatic updates of a given
OCSP response can now be set via global options. It allows to limit the
update rate of OCSP responses for configurations that use many frontend
certificates with the ocsp-update option set if the updates are deemed
too costly.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 4538af7..ae9c49e 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1188,6 +1188,8 @@
- tune.ssl.lifetime
- tune.ssl.maxrecord
- tune.ssl.ssl-ctx-cache-size
+ - tune.ssl.ocsp-update.maxdelay
+ - tune.ssl.ocsp-update.mindelay
- tune.vars.global-max-size
- tune.vars.proc-max-size
- tune.vars.reqres-max-size
@@ -3355,6 +3357,25 @@
dynamically is expensive, they are cached. The default cache size is set to
1000 entries.
+tune.ssl.ocsp-update.maxdelay <number>
+ Sets the maximum interval between two automatic updates of the same OCSP
+ response. This time is expressed in seconds and defaults to 3600 (1 hour). It
+ must be set to a higher value than "tune.ssl.ocsp-update.mindelay". See
+ option "ocsp-update" for more information about the auto update mechanism.
+
+tune.ssl.ocsp-update.mindelay <number>
+ Sets the minimum interval between two automatic updates of the same OCSP
+ response. This time is expressed in seconds and defaults to 300 (5 minutes).
+ It is particularly useful for OCSP response that do not have explicit
+ expiration times. It must be set to a lower value than
+ "tune.ssl.ocsp-update.maxdelay". See option "ocsp-update" for more
+ information about the auto update mechanism.
+
+ Sets the size of the cache used to store generated certificates to <number>
+ entries. This is a LRU cache. Because generating a SSL certificate
+ dynamically is expensive, they are cached. The default cache size is set to
+ 1000 entries.
+
tune.stick-counters <number>
Sets the number of stick-counters that may be tracked at the same time by a
connection or a request via "track-sc*" actions in "tcp-request" or
@@ -14946,7 +14967,11 @@
short time after init.
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.
+ that the OCSP response gets fetched automatically right after init. The
+ default minimum and maximum delays (5 minutes and 1 hour respectively) can be
+ configured by the "tune.ssl.ocsp-update.maxdelay" and
+ "tune.ssl.ocsp-update.mindelay" global options.
+
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]
diff --git a/include/haproxy/ssl_ocsp-t.h b/include/haproxy/ssl_ocsp-t.h
index 4448431..d78f941 100644
--- a/include/haproxy/ssl_ocsp-t.h
+++ b/include/haproxy/ssl_ocsp-t.h
@@ -33,6 +33,11 @@
extern int ocsp_ex_index;
#endif
+#define SSL_OCSP_UPDATE_DELAY_MAX 60*60 /* 1H */
+#define SSL_OCSP_UPDATE_DELAY_MIN 5*60 /* 5 minutes */
+#define SSL_OCSP_UPDATE_MARGIN 60 /* 1 minute */
+#define SSL_OCSP_HTTP_ERR_REPLAY 60 /* 1 minute */
+
#if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
/*
* struct alignment works here such that the key.key is the same as key_data
diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h
index f7a96ba..661c700 100644
--- a/include/haproxy/ssl_sock-t.h
+++ b/include/haproxy/ssl_sock-t.h
@@ -293,6 +293,13 @@
int keylog; /* activate keylog */
int extra_files; /* which files not defined in the configuration file are we looking for */
int extra_files_noext; /* whether we remove the extension when looking up a extra file */
+
+#ifndef OPENSSL_NO_OCSP
+ struct {
+ unsigned int delay_max;
+ unsigned int delay_min;
+ } ocsp_update;
+#endif
};
/* The order here matters for picking a default context,
diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c
index 655115f..1b33eec 100644
--- a/src/cfgparse-ssl.c
+++ b/src/cfgparse-ssl.c
@@ -1906,8 +1906,61 @@
}
+static int ssl_parse_global_ocsp_maxdelay(char **args, int section_type, struct proxy *curpx,
+ const struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ int value = 0;
+ if (*(args[1]) == 0) {
+ memprintf(err, "'%s' expects an integer argument.", args[0]);
+ return -1;
+ }
+ value = atoi(args[1]);
+ if (value < 0) {
+ memprintf(err, "'%s' expects a positive numeric value.", args[0]);
+ return -1;
+ }
+
+ if (global_ssl.ocsp_update.delay_min > value) {
+ memprintf(err, "'%s' can not be lower than tune.ssl.ocsp-update.mindelay.", args[0]);
+ return -1;
+ }
+
+ global_ssl.ocsp_update.delay_max = value;
+
+ return 0;
+}
+
+static int ssl_parse_global_ocsp_mindelay(char **args, int section_type, struct proxy *curpx,
+ const struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ int value = 0;
+
+ if (*(args[1]) == 0) {
+ memprintf(err, "'%s' expects an integer argument.", args[0]);
+ return -1;
+ }
+
+ value = atoi(args[1]);
+ if (value < 0) {
+ memprintf(err, "'%s' expects a positive numeric value.", args[0]);
+ return -1;
+ }
+
+ if (value > global_ssl.ocsp_update.delay_max) {
+ memprintf(err, "'%s' can not be higher than tune.ssl.ocsp-update.maxdelay.", args[0]);
+ return -1;
+ }
+
+ global_ssl.ocsp_update.delay_min = value;
+
+ return 0;
+}
+
+
/* Note: must not be declared <const> as its list will be overwritten.
* Please take care of keeping this list alphabetically sorted, doing so helps
@@ -2081,6 +2134,10 @@
#endif
{ CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
{ CFG_GLOBAL, "ssl-load-extra-del-ext", ssl_parse_global_extra_noext },
+#ifndef OPENSSL_NO_OCSP
+ { CFG_GLOBAL, "tune.ssl.ocsp-update.maxdelay", ssl_parse_global_ocsp_maxdelay },
+ { CFG_GLOBAL, "tune.ssl.ocsp-update.mindelay", ssl_parse_global_ocsp_mindelay },
+#endif
{ 0, NULL, NULL },
}};
diff --git a/src/ssl_ocsp.c b/src/ssl_ocsp.c
index db736fa..3cd35a5 100644
--- a/src/ssl_ocsp.c
+++ b/src/ssl_ocsp.c
@@ -183,10 +183,6 @@
__decl_thread(HA_SPINLOCK_T ocsp_tree_lock);
struct eb_root ocsp_update_tree = EB_ROOT; /* updatable ocsp responses sorted by next_update in absolute time */
-#define SSL_OCSP_UPDATE_DELAY_MAX 60*60 /* 1H */
-#define SSL_OCSP_UPDATE_DELAY_MIN 5*60 /* 5 minutes */
-#define SSL_OCSP_UPDATE_MARGIN 60 /* 1 minute */
-#define SSL_OCSP_HTTP_ERR_REPLAY 60 /* 1 minute */
/* This function starts to check if the OCSP response (in DER format) contained
* in chunk 'ocsp_response' is valid (else exits on error).
@@ -916,7 +912,7 @@
{
int update_margin = (ocsp->expire >= SSL_OCSP_UPDATE_MARGIN) ? SSL_OCSP_UPDATE_MARGIN : 0;
- ocsp->next_update.key = MIN(now.tv_sec + SSL_OCSP_UPDATE_DELAY_MAX,
+ ocsp->next_update.key = MIN(now.tv_sec + global_ssl.ocsp_update.delay_max,
ocsp->expire - update_margin);
/* An already existing valid OCSP response that expires within less than
@@ -925,7 +921,7 @@
* update of the same response. */
if (b_data(&ocsp->response))
ocsp->next_update.key = MAX(ocsp->next_update.key,
- now.tv_sec + SSL_OCSP_UPDATE_DELAY_MIN);
+ now.tv_sec + global_ssl.ocsp_update.delay_min);
}
/*
@@ -980,7 +976,7 @@
* being at most 1 hour (with the current default values).
*/
replay_delay = MIN(SSL_OCSP_HTTP_ERR_REPLAY * (1 << ocsp->fail_count),
- SSL_OCSP_UPDATE_DELAY_MAX);
+ global_ssl.ocsp_update.delay_max);
if (ocsp->next_update.key < now.tv_sec + replay_delay)
ocsp->next_update.key = now.tv_sec + replay_delay;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 2d4eded..1ce2483 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -132,7 +132,11 @@
.extra_files = SSL_GF_ALL,
.extra_files_noext = 0,
#ifdef HAVE_SSL_KEYLOG
- .keylog = 0
+ .keylog = 0,
+#endif
+#ifndef OPENSSL_NO_OCSP
+ .ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
+ .ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
#endif
};