Skip to content

Commit f56e1cd

Browse files
estenryeclaude
andcommitted
fix: re-finalize order when in processing state for ZeroSSL compatibility
ZeroSSL exhibits non-standard ACME behavior: after returning 403 orderNotReady on the first finalize call (which transitions the order to 'processing'), the order never self-transitions to 'valid'. Simply polling the order status is insufficient — a second finalize POST is required to trigger actual certificate issuance. Change the StatusProcessing case in the main sync loop to call finalizeOrder() instead of re-queuing. If ZeroSSL is not yet ready for the second finalize, it returns 403 again, which pf9.4's handler detects as 'processing' and the cycle continues until ZeroSSL accepts the finalization and returns the certificate. Combined with: 90s finalizeOrder timeout (pf9.3), processing state detection in finalizeOrder's 403 handler (pf9.4), and PR cert-manager#7583's StatusProcessing case (which this commit replaces with active retry). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 234eb54 commit f56e1cd

1 file changed

Lines changed: 7 additions & 9 deletions

File tree

pkg/controller/acmeorders/sync.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -244,17 +244,15 @@ func (c *controller) Sync(ctx context.Context, o *cmacme.Order) (err error) {
244244
// to fulfill an order, the underlying order finalizer may return an order still in the processing state.
245245
// In that case the worker should continue to poll the ACME server until the order transitions to either
246246
// valid or invalid.
247+
//
248+
// ZeroSSL exhibits non-standard ACME behavior: it returns 403 orderNotReady on the first finalize
249+
// call and transitions the order to 'processing', but the order never self-transitions to 'valid'.
250+
// A second finalize POST is required to trigger actual certificate issuance. We attempt re-finalization
251+
// here; if ZeroSSL is not ready, it will return 403 again and the order cycles back to this case.
247252
case acmeOrder.Status == acmeapi.StatusProcessing:
248-
log.V(logf.InfoLevel).Info("Order is in processing state, waiting for ACME server to update the status of the order...")
253+
log.V(logf.InfoLevel).Info("Order is in processing state, re-attempting finalization to handle servers that require a second finalize call")
249254
c.setOrderState(&o.Status, string(cmacme.Processing))
250-
251-
// Re-queue the Order to be processed again after RequeuePeriod has passed.
252-
c.scheduledWorkQueue.Add(types.NamespacedName{
253-
Name: o.Name,
254-
Namespace: o.Namespace,
255-
}, RequeuePeriod)
256-
257-
return nil
255+
return c.finalizeOrder(ctx, cl, o, genericIssuer)
258256

259257
case !anyChallengesFailed(challenges) && allChallengesFinal(challenges):
260258
log.V(logf.DebugLevel).Info("All challenges are in a final state, updating order state")

0 commit comments

Comments
 (0)