diff --git a/doc/configuration.txt b/doc/configuration.txt index 7c17f5408..3acf5c15e 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1824,6 +1824,18 @@ The following keywords are supported in the "global" section : Please note that this option is only available when HAProxy has been compiled with USE_51DEGREES and 51DEGREES_VER=4. +acme.scheduler { auto | off } + Enable or disable the ACME scheduler. + + The ACME scheduler starts at HAProxy startup, it will loop over the + certificates and start an ACME renewal task when the notAfter value is past + curtime + (notAfter - notBefore) / 12, or 7 days if notBefore is not defined. + The scheduler will then sleep and wakeup after 12 hours. + + The default value is "auto". + + See also: acme + ca-base Assigns a default directory to fetch SSL CA certificates and CRLs from when a relative path is used with "ca-file", "ca-verify-file" or "crl-file" diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h index 2c7f73b3b..44055492b 100644 --- a/include/haproxy/ssl_sock-t.h +++ b/include/haproxy/ssl_sock-t.h @@ -316,6 +316,10 @@ struct global_ssl { int disable; } ocsp_update; #endif + +#ifdef HAVE_ACME + int acme_scheduler; +#endif }; /* The order here matters for picking a default context, diff --git a/src/acme.c b/src/acme.c index a49c621b3..2700adf5f 100644 --- a/src/acme.c +++ b/src/acme.c @@ -411,6 +411,34 @@ out: return err_code; } +/* parse 'acme.scheduler' option */ +static int cfg_parse_global_acme_sched(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, + const char *file, int linenum, char **err) +{ + int err_code = 0; + + if (!*args[1]) { + memprintf(err, "parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection); + goto error; + } + if (alertif_too_many_args(1, file, linenum, args, &err_code)) + goto error; + + if (strcmp(args[1], "auto") == 0) { + global_ssl.acme_scheduler = 1; + } else if (strcmp(args[1], "off") == 0) { + global_ssl.acme_scheduler = 0; + } else { + memprintf(err, "parsing [%s:%d]: keyword '%s' in '%s' section requires either 'auto' or 'off' argument", file, linenum, args[0], cursection); + goto error; + } + + return 0; + +error: + return -1; +} + /* Initialize stuff once the section is parsed */ static int cfg_postsection_acme() { @@ -545,7 +573,7 @@ static int cfg_postparser_acme() } - if (acme_cfgs) { + if (acme_cfgs && global_ssl.acme_scheduler) { task = task_new_anywhere(); if (!task) { ret++; @@ -589,6 +617,7 @@ static struct cfg_kw_list cfg_kws_acme = {ILH, { { CFG_ACME, "bits", cfg_parse_acme_cfg_key }, { CFG_ACME, "curves", cfg_parse_acme_cfg_key }, { CFG_ACME, "map", cfg_parse_acme_kws }, + { CFG_GLOBAL, "acme.scheduler", cfg_parse_global_acme_sched }, { 0, NULL, NULL }, }}; @@ -2054,6 +2083,9 @@ time_t acme_schedule_date(struct ckch_store *store) time_t notAfter = 0; time_t notBefore = 0; + if (!global_ssl.acme_scheduler) + return 0; + /* compute the validity period of the leaf certificate */ if (!store->data || !store->data->cert) return 0; @@ -2347,12 +2379,18 @@ static int cli_acme_status_io_handler(struct appctx *appctx) if (store->conf.acme.id) { char str[50] = {}; - char *state = "Scheduled"; + char *state; time_t notAfter = 0; time_t sched = 0; time_t remain = 0; + int running = !!store->acme_task; - if (store->acme_task) + if (global_ssl.acme_scheduler) + state = "Scheduled"; + else + state = "Stopped"; + + if (running) state = "Running"; chunk_appendf(&trash, "%s\t%s\t%s\t", store->path, store->conf.acme.id, state); @@ -2367,12 +2405,16 @@ static int cli_acme_status_io_handler(struct appctx *appctx) /* Scheduled time */ remain = 0; - sched = acme_schedule_date(store); + if (!running) /* if running no schedule date yet */ + sched = acme_schedule_date(store); if (sched > date.tv_sec) remain = sched - date.tv_sec; strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime(&sched)); - chunk_appendf(&trash, "%s\t", str); - chunk_appendf(&trash, "%lud %luh%02lum%02lus\n", remain / 86400, (remain % 86400) / 3600, (remain % 3600) / 60, (remain % 60)); + chunk_appendf(&trash, "%s\t", sched ? str : "-"); + if (sched) + chunk_appendf(&trash, "%lud %luh%02lum%02lus\n", remain / 86400, (remain % 86400) / 3600, (remain % 3600) / 60, (remain % 60)); + else + chunk_appendf(&trash, "%s\n", "-"); if (applet_putchk(appctx, &trash) == -1) return 1; diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 793862b94..e7f01bc84 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -145,6 +145,10 @@ struct global_ssl global_ssl = { .ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_OFF, .ocsp_update.disable = 0, #endif +#ifdef HAVE_ACME + .acme_scheduler = 1, +#endif + }; static BIO_METHOD *ha_meth;