fix(certmanager#514): check DNS configuration before starting ACME

Signed-off-by: MustafaAamir <mustafa.290101@gmail.com>
This commit is contained in:
MustafaAamir
2025-11-09 02:18:22 +00:00
committed by Bryan Frimin
parent a3fcd522ca
commit 60a3402b24
7 changed files with 48 additions and 13 deletions

View File

@@ -25,11 +25,11 @@ import (
"fmt" "fmt"
"time" "time"
"go.gearno.de/kit/httpclient"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/crypto/keys" "go.probo.inc/probo/pkg/crypto/keys"
"go.probo.inc/probo/pkg/crypto/pem" "go.probo.inc/probo/pkg/crypto/pem"
"go.probo.inc/probo/pkg/version" "go.probo.inc/probo/pkg/version"
"go.gearno.de/kit/httpclient"
"go.gearno.de/kit/log"
"golang.org/x/crypto/acme" "golang.org/x/crypto/acme"
) )

View File

@@ -19,10 +19,10 @@ import (
"net/http" "net/http"
"strings" "strings"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
"go.gearno.de/kit/log" "go.gearno.de/kit/log"
"go.gearno.de/kit/pg" "go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
) )
type ACMEChallengeHandler struct { type ACMEChallengeHandler struct {

View File

@@ -19,10 +19,10 @@ import (
"fmt" "fmt"
"time" "time"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
"go.gearno.de/kit/log" "go.gearno.de/kit/log"
"go.gearno.de/kit/pg" "go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
) )
type ( type (

View File

@@ -20,10 +20,10 @@ import (
"strings" "strings"
"time" "time"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
"go.gearno.de/kit/log" "go.gearno.de/kit/log"
"go.gearno.de/kit/pg" "go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
) )
type ( type (
@@ -31,6 +31,7 @@ type (
pg *pg.Client pg *pg.Client
acmeService *ACMEService acmeService *ACMEService
encryptionKey cipher.EncryptionKey encryptionKey cipher.EncryptionKey
cnameTarget string
interval time.Duration interval time.Duration
logger *log.Logger logger *log.Logger
} }
@@ -40,6 +41,7 @@ func NewProvisioner(
pg *pg.Client, pg *pg.Client,
acmeService *ACMEService, acmeService *ACMEService,
encryptionKey cipher.EncryptionKey, encryptionKey cipher.EncryptionKey,
cnameTarget string,
interval time.Duration, interval time.Duration,
logger *log.Logger, logger *log.Logger,
) *Provisioner { ) *Provisioner {
@@ -47,6 +49,7 @@ func NewProvisioner(
pg: pg, pg: pg,
acmeService: acmeService, acmeService: acmeService,
encryptionKey: encryptionKey, encryptionKey: encryptionKey,
cnameTarget: cnameTarget,
interval: interval, interval: interval,
logger: logger.Named("certmanager.provisioner"), logger: logger.Named("certmanager.provisioner"),
} }
@@ -75,6 +78,28 @@ func (p *Provisioner) Run(ctx context.Context) error {
} }
} }
func (p *Provisioner) checkDNSConfiguration(domain string) error {
if p.cnameTarget == "" {
return nil
}
cnameRecords, err := net.LookupCNAME(domain)
if err != nil {
return fmt.Errorf("DNS lookup Failed: %w", err)
}
expectedTarget := strings.TrimSuffix(p.cnameTarget, ".")
actualTarget := strings.TrimSuffix(cnameRecords, ".")
if !strings.EqualFold(actualTarget, expectedTarget) {
return fmt.Errorf(
"DNS configuration mismatch: domain %q resolves to %q, expected %q",
domain,
actualTarget,
expectedTarget,
)
}
return nil
}
func (p *Provisioner) checkPendingDomains(ctx context.Context) error { func (p *Provisioner) checkPendingDomains(ctx context.Context) error {
return p.pg.WithConn( return p.pg.WithConn(
ctx, ctx,
@@ -208,7 +233,17 @@ func (p *Provisioner) provisionDomainCertificate(
domain *coredata.CustomDomain, domain *coredata.CustomDomain,
) error { ) error {
if domain.SSLStatus == coredata.CustomDomainSSLStatusPending { if domain.SSLStatus == coredata.CustomDomainSSLStatusPending {
p.logger.InfoCtx(ctx, "initiating HTTP challenge for domain", log.String("domain", domain.Domain)) if err := p.checkDNSConfiguration(domain.Domain); err != nil {
p.logger.WarnCtx(
ctx,
"DNS configuration check failed, skipping ACME challenge",
log.String("domain", domain.Domain),
log.Error(err),
)
return fmt.Errorf("DNS configuration not ready: %w", err)
}
p.logger.InfoCtx(ctx, "DNS configuration verified, initiating HTTP challenge for domain", log.String("domain", domain.Domain))
challenge, err := p.acmeService.GetHTTPChallenge(ctx, domain.Domain) challenge, err := p.acmeService.GetHTTPChallenge(ctx, domain.Domain)
if err != nil { if err != nil {

View File

@@ -20,10 +20,10 @@ import (
"fmt" "fmt"
"time" "time"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
"go.gearno.de/kit/log" "go.gearno.de/kit/log"
"go.gearno.de/kit/pg" "go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher"
) )
type ( type (

View File

@@ -21,9 +21,9 @@ import (
"sync" "sync"
"time" "time"
"go.gearno.de/kit/pg"
"go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/crypto/cipher" "go.probo.inc/probo/pkg/crypto/cipher"
"go.gearno.de/kit/pg"
) )
type ( type (

View File

@@ -634,7 +634,7 @@ func (impl *Implm) runTrustCenterServer(
if certProvisioningInterval == 0 { if certProvisioningInterval == 0 {
certProvisioningInterval = 30 * time.Second certProvisioningInterval = 30 * time.Second
} }
certProvisioner := certmanager.NewProvisioner(pgClient, acmeService, impl.cfg.EncryptionKey, certProvisioningInterval, l) certProvisioner := certmanager.NewProvisioner(pgClient, acmeService, impl.cfg.EncryptionKey, impl.cfg.CustomDomains.CnameTarget, certProvisioningInterval, l)
g, ctx := errgroup.WithContext(ctx) g, ctx := errgroup.WithContext(ctx)