Fix cert provisioner clearing valid challenges on transient errors

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-10-14 15:39:20 +02:00
parent 98516d54ea
commit 84a80b9469
2 changed files with 48 additions and 16 deletions

View File

@@ -17,6 +17,7 @@ package certmanager
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"time" "time"
"github.com/getprobo/probo/pkg/coredata" "github.com/getprobo/probo/pkg/coredata"
@@ -115,6 +116,21 @@ func (p *Provisioner) checkPendingDomains(ctx context.Context) error {
) )
} }
func isFatalChallengeError(err error) bool {
if err == nil {
return false
}
errStr := strings.ToLower(err.Error())
return (strings.Contains(errStr, "invalid") &&
(strings.Contains(errStr, "challenge") ||
strings.Contains(errStr, "authorization") ||
strings.Contains(errStr, "order"))) ||
strings.Contains(errStr, "authorization must be pending") ||
strings.Contains(errStr, "expired")
}
func (p *Provisioner) handleStaleProvisioningAttempts(ctx context.Context, conn pg.Conn) error { func (p *Provisioner) handleStaleProvisioningAttempts(ctx context.Context, conn pg.Conn) error {
var domains coredata.CustomDomains var domains coredata.CustomDomains
if err := domains.ListStaleProvisioningDomains(ctx, conn, coredata.NewNoScope()); err != nil { if err := domains.ListStaleProvisioningDomains(ctx, conn, coredata.NewNoScope()); err != nil {
@@ -291,35 +307,50 @@ func (p *Provisioner) provisionDomainCertificate(
return nil return nil
} }
if isFatalChallengeError(err) {
p.logger.InfoCtx(
ctx,
"fatal challenge error, resetting domain to retry with fresh challenge",
log.String("domain", domain.Domain),
log.Int("retry_count", fullDomain.SSLRetryCount),
)
fullDomain.HTTPChallengeToken = nil
fullDomain.HTTPChallengeKeyAuth = nil
fullDomain.HTTPChallengeURL = nil
fullDomain.HTTPOrderURL = nil
fullDomain.SSLStatus = coredata.CustomDomainSSLStatusPending
if updateErr := fullDomain.Update(ctx, conn, coredata.NewNoScope(), p.encryptionKey); updateErr != nil {
p.logger.ErrorCtx(
ctx,
"cannot reset domain for retry",
log.String("domain", domain.Domain),
log.Error(updateErr),
)
return updateErr
}
return nil
}
p.logger.InfoCtx( p.logger.InfoCtx(
ctx, ctx,
"resetting domain to retry with fresh challenge", "transient error, keeping existing challenge for retry",
log.String("domain", domain.Domain), log.String("domain", domain.Domain),
log.Int("retry_count", fullDomain.SSLRetryCount), log.Int("retry_count", fullDomain.SSLRetryCount),
) )
fullDomain.HTTPChallengeToken = nil
fullDomain.HTTPChallengeKeyAuth = nil
fullDomain.HTTPChallengeURL = nil
fullDomain.HTTPOrderURL = nil
fullDomain.SSLStatus = coredata.CustomDomainSSLStatusPending
if updateErr := fullDomain.Update(ctx, conn, coredata.NewNoScope(), p.encryptionKey); updateErr != nil { if updateErr := fullDomain.Update(ctx, conn, coredata.NewNoScope(), p.encryptionKey); updateErr != nil {
p.logger.ErrorCtx( p.logger.ErrorCtx(
ctx, ctx,
"cannot reset domain for retry", "cannot update domain retry tracking",
log.String("domain", domain.Domain), log.String("domain", domain.Domain),
log.Error(updateErr), log.Error(updateErr),
) )
return updateErr return updateErr
} }
p.logger.InfoCtx(
ctx,
"domain reset to pending, will retry with new challenge on next cycle",
log.String("domain", domain.Domain),
)
return nil return nil
} }

View File

@@ -208,7 +208,7 @@ func (r *Renewer) renewDomain(ctx context.Context, conn pg.Conn, domain *coredat
return updateErr return updateErr
} }
return nil return fmt.Errorf("domain marked as failed after %d retry attempts: %w", maxRetries, err)
} }
// Update retry tracking but keep domain ACTIVE for next renewal cycle // Update retry tracking but keep domain ACTIVE for next renewal cycle
@@ -229,7 +229,8 @@ func (r *Renewer) renewDomain(ctx context.Context, conn pg.Conn, domain *coredat
log.Int("retry_count", lockedDomain.SSLRetryCount), log.Int("retry_count", lockedDomain.SSLRetryCount),
) )
return nil // Return the original error so caller knows renewal failed
return fmt.Errorf("renewal failed, will retry: %w", err)
} }
r.logger.InfoCtx( r.logger.InfoCtx(