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.
This commit is contained in:
Remi Tricot-Le Breton 2023-02-28 17:46:29 +01:00 committed by William Lallemand
parent 9c4437d024
commit 5843237993
6 changed files with 103 additions and 9 deletions

View File

@ -1188,6 +1188,8 @@ The following keywords are supported in the "global" section :
- 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 @@ tune.ssl.ssl-ctx-cache-size <number>
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 @@ ocsp-update [ off | on ]
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]

View File

@ -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

View File

@ -293,6 +293,13 @@ struct global_ssl {
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,

View File

@ -1906,6 +1906,59 @@ static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct p
}
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;
}
@ -2081,6 +2134,10 @@ static struct cfg_kw_list cfg_kws = {ILH, {
#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 },
}};

View File

@ -183,10 +183,6 @@ struct eb_root cert_ocsp_tree = EB_ROOT_UNIQUE;
__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 @@ static inline void ssl_ocsp_set_next_update(struct certificate_ocsp *ocsp)
{
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 @@ static inline void ssl_ocsp_set_next_update(struct certificate_ocsp *ocsp)
* 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 @@ int ssl_ocsp_update_insert_after_error(struct certificate_ocsp *ocsp)
* 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;

View File

@ -132,7 +132,11 @@ struct global_ssl global_ssl = {
.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
};