mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-05 13:06:10 +02:00
MINOR: acme: add 'dns-timeout' keyword for dns-01 challenge
When using the dns-01 challenge method with "challenge-ready dns", HAProxy retries DNS resolution indefinitely at the interval set by "dns-delay". This adds a "dns-timeout" keyword to set a maximum duration for the DNS check phase (default: 600s). If the next resolution attempt would be scheduled beyond that deadline, the renewal is aborted with an explicit error message. A new "dnsstarttime" field is stored in the acme_ctx to record when DNS resolution began, used to evaluate the timeout on each retry.
This commit is contained in:
parent
c49facbabe
commit
7f6999b764
@ -32320,6 +32320,18 @@ dns-delay <time>
|
||||
section, not the authoritative name servers. Results may therefore still be
|
||||
affected by DNS caching at the resolver level.
|
||||
|
||||
dns-timeout <time>
|
||||
When "challenge-ready" includes "dns", configure the maximum time allowed to
|
||||
successfully resolve the TXT record before aborting the challenge. The value
|
||||
is a time expressed in HAProxy time format (e.g. "10m", "600s"). Default is
|
||||
600 seconds.
|
||||
|
||||
If the next DNS resolution attempt would be triggered after the timeout has
|
||||
elapsed (taking into account "dns-delay"), the challenge is aborted with an
|
||||
error. This prevents an infinite retry loop when DNS propagation fails.
|
||||
|
||||
See also: "dns-delay"
|
||||
|
||||
keytype <string>
|
||||
Configure the type of key that will be generated. Value can be either "RSA"
|
||||
or "ECDSA". You can also configure the "curves" for ECDSA and the number of
|
||||
|
||||
@ -23,6 +23,7 @@ struct acme_cfg {
|
||||
int reuse_key; /* do we need to renew the private key */
|
||||
int cond_ready; /* ready condition */
|
||||
unsigned int dns_delay; /* delay in seconds before re-triggering DNS resolution (default: 300) */
|
||||
unsigned int dns_timeout; /* time after which the DNS check shouldn't be retried (default: 600) */
|
||||
char *directory; /* directory URL */
|
||||
char *map; /* storage for tokens + thumbprint */
|
||||
struct {
|
||||
@ -100,6 +101,7 @@ struct acme_ctx {
|
||||
struct ist finalize;
|
||||
struct ist certificate;
|
||||
unsigned int dnstasks; /* number of DNS tasks running for this ctx */
|
||||
unsigned int dnsstarttime; /* time at which we started the DNS checks */
|
||||
struct task *task;
|
||||
struct ebmb_node node;
|
||||
char name[VAR_ARRAY];
|
||||
|
||||
40
src/acme.c
40
src/acme.c
@ -198,6 +198,7 @@ struct acme_cfg *new_acme_cfg(const char *name)
|
||||
|
||||
ret->challenge = strdup("http-01"); /* default value */
|
||||
ret->dns_delay = 300; /* default DNS re-trigger delay in seconds */
|
||||
ret->dns_timeout = 600; /* default DNS retry timeout */
|
||||
|
||||
/* The default generated keys are EC-384 */
|
||||
ret->key.type = EVP_PKEY_EC;
|
||||
@ -524,6 +525,31 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
} else if (strcmp(args[0], "dns-timeout") == 0) {
|
||||
const char *res;
|
||||
|
||||
if (!*args[1]) {
|
||||
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||
goto out;
|
||||
|
||||
res = parse_time_err(args[1], &cur_acme->dns_timeout, TIME_UNIT_S);
|
||||
if (res == PARSE_TIME_OVER) {
|
||||
ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to '%s'\n", file, linenum, args[1], args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
} else if (res == PARSE_TIME_UNDER) {
|
||||
ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to '%s'\n", file, linenum, args[1], args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
} else if (res) {
|
||||
ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to '%s'\n", file, linenum, *res, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
} else if (strcmp(args[0], "reuse-key") == 0) {
|
||||
if (!*args[1]) {
|
||||
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section requires an argument\n", file, linenum, args[0], cursection);
|
||||
@ -930,6 +956,7 @@ static struct cfg_kw_list cfg_kws_acme = {ILH, {
|
||||
{ CFG_ACME, "reuse-key", cfg_parse_acme_kws },
|
||||
{ CFG_ACME, "challenge-ready", cfg_parse_acme_kws },
|
||||
{ CFG_ACME, "dns-delay", cfg_parse_acme_kws },
|
||||
{ CFG_ACME, "dns-timeout", cfg_parse_acme_kws },
|
||||
{ CFG_ACME, "acme-vars", cfg_parse_acme_vars_provider },
|
||||
{ CFG_ACME, "provider-name", cfg_parse_acme_vars_provider },
|
||||
{ CFG_GLOBAL, "acme.scheduler", cfg_parse_global_acme_sched },
|
||||
@ -2388,6 +2415,19 @@ re:
|
||||
if ((ctx->cfg->cond_ready & ACME_RDY_CLI) && !(all_cond_ready & ACME_RDY_CLI))
|
||||
goto wait;
|
||||
|
||||
/* set the start time of the DNS checks so we can apply
|
||||
* the timeout */
|
||||
if (ctx->dnsstarttime == 0)
|
||||
ctx->dnsstarttime = ns_to_sec(now_ns);
|
||||
|
||||
/* Check if the next resolution would be triggered too
|
||||
* late according to the dns_timeout and abort is
|
||||
* necessary. */
|
||||
if (ctx->dnsstarttime && ns_to_sec(now_ns) + ctx->cfg->dns_delay > ctx->dnsstarttime + ctx->cfg->dns_timeout) {
|
||||
memprintf(&errmsg, "dns-01: Couldn't resolve the TXT records in %ds.", ctx->cfg->dns_timeout);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
/* we don't need to wait, we can trigger the resolution
|
||||
* after the delay */
|
||||
st = ACME_RSLV_TRIGGER;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user