mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-05 06:37:02 +02:00
MEDIUM: acme: allow to wait and restart the task for DNS-01
DNS-01 needs a external process which would register a TXT record on a DNS provider, using a REST API or something else. To achieve this, the process should read the dpapi sink and wait for events. With the DNS-01 challenge, HAProxy will put the task to sleep before asking the ACME server to achieve the challenge. The task then need to be woke up, using the command implemented by this patch. This patch implements the "acme challenge_ready" command which should be used by the agent once the challenge was configured in order to wake the task up. Example: echo "@1 acme challenge_ready foobar.pem.rsa domain kikyo" | socat /tmp/master.sock -
This commit is contained in:
parent
3dde7626ba
commit
9ee14ed2d9
@ -55,6 +55,7 @@ struct acme_auth {
|
||||
struct ist auth; /* auth URI */
|
||||
struct ist chall; /* challenge URI */
|
||||
struct ist token; /* token */
|
||||
int ready; /* is the challenge ready ? */
|
||||
void *next;
|
||||
};
|
||||
|
||||
@ -80,6 +81,7 @@ struct acme_ctx {
|
||||
X509_REQ *req;
|
||||
struct ist finalize;
|
||||
struct ist certificate;
|
||||
struct task *task;
|
||||
struct mt_list el;
|
||||
};
|
||||
|
||||
|
71
src/acme.c
71
src/acme.c
@ -1753,6 +1753,11 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* if the challenge is not DNS-01, consider that the challenge
|
||||
* is ready because computed by HAProxy */
|
||||
if (strcasecmp(ctx->cfg->challenge, "DNS-01") != 0)
|
||||
auth->ready = 1;
|
||||
|
||||
auth->next = ctx->auths;
|
||||
ctx->auths = auth;
|
||||
ctx->next_auth = auth;
|
||||
@ -2111,6 +2116,11 @@ struct task *acme_process(struct task *task, void *context, unsigned int state)
|
||||
break;
|
||||
case ACME_CHALLENGE:
|
||||
if (http_st == ACME_HTTP_REQ) {
|
||||
|
||||
/* if the challenge is not ready, wait to be wakeup */
|
||||
if (!ctx->next_auth->ready)
|
||||
goto wait;
|
||||
|
||||
if (acme_req_challenge(task, ctx, ctx->next_auth, &errmsg) != 0)
|
||||
goto retry;
|
||||
}
|
||||
@ -2267,8 +2277,16 @@ struct task *acme_process(struct task *task, void *context, unsigned int state)
|
||||
task = NULL;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
wait:
|
||||
/* wait for a task_wakeup */
|
||||
ctx->http_state = ACME_HTTP_REQ;
|
||||
ctx->state = st;
|
||||
task->expire = TICK_ETERNITY;
|
||||
|
||||
MT_LIST_UNLOCK_FULL(&ctx->el, tmp);
|
||||
return task;
|
||||
}
|
||||
/*
|
||||
* Return 1 if the certificate must be regenerated
|
||||
* Check if the notAfter date will append in (validity period / 12) or 7 days per default
|
||||
@ -2534,6 +2552,7 @@ static int acme_start_task(struct ckch_store *store, char **errmsg)
|
||||
ctx->store = newstore;
|
||||
ctx->cfg = cfg;
|
||||
task->context = ctx;
|
||||
ctx->task = task;
|
||||
|
||||
MT_LIST_INIT(&ctx->el);
|
||||
MT_LIST_APPEND(&acme_tasks, &ctx->el);
|
||||
@ -2586,6 +2605,55 @@ static int cli_acme_renew_parse(char **args, char *payload, struct appctx *appct
|
||||
return cli_dynerr(appctx, errmsg);
|
||||
}
|
||||
|
||||
static int cli_acme_chall_ready_parse(char **args, char *payload, struct appctx *appctx, void *private)
|
||||
{
|
||||
char *errmsg = NULL;
|
||||
const char *crt;
|
||||
const char *dns;
|
||||
struct mt_list back;
|
||||
struct acme_ctx *ctx;
|
||||
struct acme_auth *auth;
|
||||
int found = 0;
|
||||
|
||||
if (!*args[2] && !*args[3] && !*args[4]) {
|
||||
memprintf(&errmsg, ": not enough parameters\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
crt = args[2];
|
||||
dns = args[4];
|
||||
|
||||
|
||||
MT_LIST_FOR_EACH_ENTRY_LOCKED(ctx, &acme_tasks, el, back) {
|
||||
|
||||
if (strcmp(ctx->store->path, crt) != 0)
|
||||
continue;
|
||||
|
||||
auth = ctx->auths;
|
||||
while (auth) {
|
||||
if (strncmp(dns, auth->dns.ptr, auth->dns.len) == 0) {
|
||||
if (!auth->ready) {
|
||||
auth->ready = 1;
|
||||
task_wakeup(ctx->task, TASK_WOKEN_MSG);
|
||||
found = 1;
|
||||
} else {
|
||||
memprintf(&errmsg, "ACME challenge for crt \"%s\" and dns \"%s\" was already READY !\n", crt, dns);
|
||||
}
|
||||
break;
|
||||
}
|
||||
auth = auth->next;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
memprintf(&errmsg, "Couldn't find the ACME task using crt \"%s\" and dns \"%s\" !\n", crt, dns);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return cli_msg(appctx, LOG_INFO, "Challenge Ready!");
|
||||
err:
|
||||
return cli_dynerr(appctx, errmsg);
|
||||
}
|
||||
|
||||
static int cli_acme_status_io_handler(struct appctx *appctx)
|
||||
{
|
||||
struct ebmb_node *node = NULL;
|
||||
@ -2668,6 +2736,7 @@ static int cli_acme_ps(char **args, char *payload, struct appctx *appctx, void *
|
||||
static struct cli_kw_list cli_kws = {{ },{
|
||||
{ { "acme", "renew", NULL }, "acme renew <certfile> : renew a certificate using the ACME protocol", cli_acme_renew_parse, NULL, NULL, NULL, 0 },
|
||||
{ { "acme", "status", NULL }, "acme status : show status of certificates configured with ACME", cli_acme_ps, cli_acme_status_io_handler, NULL, NULL, 0 },
|
||||
{ { "acme", "challenge_ready", NULL }, "acme challenge_ready <certfile> domain <domain> : show status of certificates configured with ACME", cli_acme_chall_ready_parse, NULL, NULL, NULL, 0 },
|
||||
{ { NULL }, NULL, NULL, NULL }
|
||||
}};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user