[low priority] Failed cert acquisition creates a new ACME account each attempt #21

Open
opened 2026-08-09 18:06:52 +00:00 by james.oates · 0 comments
Owner

Priority: low — robustness, surfaced while fixing the instant-acme 0.8 upgrade.

Observation

The kuruk.oates.ws logs showed ACME [...]: created new account for [email protected] on every renewal attempt. The account credentials are only persisted (acme_account_key_pem_enc) as part of update_tls_domain_cert, which runs after a full successful acquisition. So every acquisition that fails before completion (e.g. all the ones failing at "fetch authorizations" pre-0.8-fix) creates a fresh ACME account on Let's Encrypt (Account::builder().create() generates a new key each call) and never stores it.

Why it matters

Under repeated failure this leaks ACME accounts and can eventually hit Let's Encrypt's new-account rate limit (generous, but real — and staging/prod differ). It self-heals once acquisition succeeds (the account is then stored and reused via from_credentials on subsequent renewals), so it's only a problem while acquisition is broken — but that's exactly when you retry a lot.

Suggested fix

Persist the account key up front (on first account creation, before the order/challenge flow) and reuse it across attempts, so a failing acquisition reuses one account instead of minting a new one each time. Alternatively, create the account once per TLS domain and store it independently of cert success.

Context

Related to the instant-acme 0.7.2 → 0.8.5 upgrade (fixes the "missing field token" parse failure). Do this only after cert issuance is confirmed working end-to-end. Surfaced 2026-08-09.

**Priority: low** — robustness, surfaced while fixing the instant-acme 0.8 upgrade. ## Observation The `kuruk.oates.ws` logs showed `ACME [...]: created new account for [email protected]` on **every** renewal attempt. The account credentials are only persisted (`acme_account_key_pem_enc`) as part of `update_tls_domain_cert`, which runs **after a full successful acquisition**. So every acquisition that fails before completion (e.g. all the ones failing at "fetch authorizations" pre-0.8-fix) creates a *fresh* ACME account on Let's Encrypt (`Account::builder().create()` generates a new key each call) and never stores it. ## Why it matters Under repeated failure this leaks ACME accounts and can eventually hit Let's Encrypt's new-account rate limit (generous, but real — and staging/prod differ). It self-heals once acquisition succeeds (the account is then stored and reused via `from_credentials` on subsequent renewals), so it's only a problem while acquisition is broken — but that's exactly when you retry a lot. ## Suggested fix Persist the account key **up front** (on first account creation, before the order/challenge flow) and reuse it across attempts, so a failing acquisition reuses one account instead of minting a new one each time. Alternatively, create the account once per TLS domain and store it independently of cert success. ## Context Related to the instant-acme 0.7.2 → 0.8.5 upgrade (fixes the "missing field token" parse failure). Do this only after cert issuance is confirmed working end-to-end. Surfaced 2026-08-09.
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
IsoHex/edge-router#21
No description provided.