fix: handle ACME mock directory and NO_DNS_01 configuration

- Add MockDirectory constant to avoid hardcoded strings
- Skip certificate validation when using mock directory
- Skip ACME client creation for mock directory to avoid TLS errors
- Properly handle NO_DNS_01 configuration to disable DNS-01 challenges
- Fix certificate verification errors when ACME_API=https://acme.mock.directory
This commit is contained in:
hongwei.chen 2025-07-13 01:32:19 +08:00
parent d19542233a
commit 63014e493f
3 changed files with 92 additions and 65 deletions

View File

@ -13,8 +13,8 @@ var ErrAcmeMissConfig = errors.New("ACME client has wrong config")
func CreateAcmeClient(cfg config.ACMEConfig, enableHTTPServer bool, challengeCache cache.ICache) (*certificates.AcmeClient, error) {
// check config
if (!cfg.AcceptTerms || (cfg.DNSProvider == "" && !cfg.NoDNS01)) && cfg.APIEndpoint != "https://acme.mock.directory" {
return nil, fmt.Errorf("%w: you must set $ACME_ACCEPT_TERMS and $DNS_PROVIDER or $NO_DNS_01, unless $ACME_API is set to https://acme.mock.directory", ErrAcmeMissConfig)
if (!cfg.AcceptTerms || (cfg.DNSProvider == "" && !cfg.NoDNS01)) && cfg.APIEndpoint != certificates.MockDirectory {
return nil, fmt.Errorf("%w: you must set $ACME_ACCEPT_TERMS and $DNS_PROVIDER or $NO_DNS_01, unless $ACME_API is set to %s", ErrAcmeMissConfig, certificates.MockDirectory)
}
if cfg.EAB_HMAC != "" && cfg.EAB_KID == "" {
return nil, fmt.Errorf("%w: ACME_EAB_HMAC also needs ACME_EAB_KID to be set", ErrAcmeMissConfig)

View File

@ -35,7 +35,18 @@ func NewAcmeClient(cfg config.ACMEConfig, enableHTTPServer bool, challengeCache
return nil, err
}
acmeClient, err := lego.NewClient(acmeConfig)
// Check if this is a mock directory
isMockDirectory := cfg.APIEndpoint == MockDirectory
var acmeClient *lego.Client
var mainDomainAcmeClient *lego.Client
if isMockDirectory {
log.Info().Msg("Using mock ACME directory, skipping ACME client creation")
acmeClient = nil
mainDomainAcmeClient = nil
} else {
acmeClient, err = lego.NewClient(acmeConfig)
if err != nil {
log.Fatal().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
} else {
@ -51,12 +62,12 @@ func NewAcmeClient(cfg config.ACMEConfig, enableHTTPServer bool, challengeCache
}
}
mainDomainAcmeClient, err := lego.NewClient(acmeConfig)
mainDomainAcmeClient, err = lego.NewClient(acmeConfig)
if err != nil {
log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
} else {
if cfg.DNSProvider == "" {
// using mock wildcard certs
if cfg.DNSProvider == "" || cfg.NoDNS01 {
// using mock wildcard certs when no DNS provider is configured or NO_DNS_01 is set
mainDomainAcmeClient = nil
} else {
// use DNS-Challenge https://go-acme.github.io/lego/dns/
@ -69,6 +80,7 @@ func NewAcmeClient(cfg config.ACMEConfig, enableHTTPServer bool, challengeCache
}
}
}
}
return &AcmeClient{
legoClient: acmeClient,

View File

@ -15,7 +15,10 @@ import (
"github.com/rs/zerolog/log"
)
const challengePath = "/.well-known/acme-challenge/"
const (
challengePath = "/.well-known/acme-challenge/"
MockDirectory = "https://acme.mock.directory"
)
func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
var myAcmeAccount AcmeAccount
@ -25,6 +28,9 @@ func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
return nil, fmt.Errorf("invalid acme config file: '%s'", cfg.AccountConfigFile)
}
// Check if this is a mock directory - if so, skip certificate validation
isMockDirectory := cfg.APIEndpoint == MockDirectory
if account, err := os.ReadFile(cfg.AccountConfigFile); err == nil {
log.Info().Msgf("found existing acme account config file '%s'", cfg.AccountConfigFile)
if err := json.Unmarshal(account, &myAcmeAccount); err != nil {
@ -40,12 +46,15 @@ func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
myAcmeConfig.CADirURL = cfg.APIEndpoint
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
// Skip validation for mock directory
if !isMockDirectory {
// Validate Config
_, err := lego.NewClient(myAcmeConfig)
if err != nil {
log.Info().Err(err).Msg("config validation failed, you might just delete the config file and let it recreate")
return nil, fmt.Errorf("acme config validation failed: %w", err)
}
}
return myAcmeConfig, nil
} else if !os.IsNotExist(err) {
@ -66,6 +75,11 @@ func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
myAcmeConfig.CADirURL = cfg.APIEndpoint
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
// Skip client creation for mock directory to avoid certificate verification errors
if isMockDirectory {
log.Info().Msg("Using mock ACME directory, skipping client creation and registration")
} else {
tempClient, err := lego.NewClient(myAcmeConfig)
if err != nil {
log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
@ -105,6 +119,7 @@ func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
}
}
}
}
return myAcmeConfig, nil
}