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:
parent
d19542233a
commit
63014e493f
@ -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) {
|
func CreateAcmeClient(cfg config.ACMEConfig, enableHTTPServer bool, challengeCache cache.ICache) (*certificates.AcmeClient, error) {
|
||||||
// check config
|
// check config
|
||||||
if (!cfg.AcceptTerms || (cfg.DNSProvider == "" && !cfg.NoDNS01)) && cfg.APIEndpoint != "https://acme.mock.directory" {
|
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 https://acme.mock.directory", ErrAcmeMissConfig)
|
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 == "" {
|
if cfg.EAB_HMAC != "" && cfg.EAB_KID == "" {
|
||||||
return nil, fmt.Errorf("%w: ACME_EAB_HMAC also needs ACME_EAB_KID to be set", ErrAcmeMissConfig)
|
return nil, fmt.Errorf("%w: ACME_EAB_HMAC also needs ACME_EAB_KID to be set", ErrAcmeMissConfig)
|
||||||
|
@ -35,37 +35,49 @@ func NewAcmeClient(cfg config.ACMEConfig, enableHTTPServer bool, challengeCache
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeClient, err := lego.NewClient(acmeConfig)
|
// Check if this is a mock directory
|
||||||
if err != nil {
|
isMockDirectory := cfg.APIEndpoint == MockDirectory
|
||||||
log.Fatal().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
|
|
||||||
} else {
|
|
||||||
err = acmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{challengeCache})
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Can't create TLS-ALPN-01 provider")
|
|
||||||
}
|
|
||||||
if enableHTTPServer {
|
|
||||||
err = acmeClient.Challenge.SetHTTP01Provider(AcmeHTTPChallengeProvider{challengeCache})
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Can't create HTTP-01 provider")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mainDomainAcmeClient, err := lego.NewClient(acmeConfig)
|
var acmeClient *lego.Client
|
||||||
if err != nil {
|
var mainDomainAcmeClient *lego.Client
|
||||||
log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
|
|
||||||
|
if isMockDirectory {
|
||||||
|
log.Info().Msg("Using mock ACME directory, skipping ACME client creation")
|
||||||
|
acmeClient = nil
|
||||||
|
mainDomainAcmeClient = nil
|
||||||
} else {
|
} else {
|
||||||
if cfg.DNSProvider == "" {
|
acmeClient, err = lego.NewClient(acmeConfig)
|
||||||
// using mock wildcard certs
|
if err != nil {
|
||||||
mainDomainAcmeClient = nil
|
log.Fatal().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
|
||||||
} else {
|
} else {
|
||||||
// use DNS-Challenge https://go-acme.github.io/lego/dns/
|
err = acmeClient.Challenge.SetTLSALPN01Provider(AcmeTLSChallengeProvider{challengeCache})
|
||||||
provider, err := dns.NewDNSChallengeProviderByName(cfg.DNSProvider)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can not create DNS Challenge provider: %w", err)
|
log.Error().Err(err).Msg("Can't create TLS-ALPN-01 provider")
|
||||||
}
|
}
|
||||||
if err := mainDomainAcmeClient.Challenge.SetDNS01Provider(provider); err != nil {
|
if enableHTTPServer {
|
||||||
return nil, fmt.Errorf("can not create DNS-01 provider: %w", err)
|
err = acmeClient.Challenge.SetHTTP01Provider(AcmeHTTPChallengeProvider{challengeCache})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Can't create HTTP-01 provider")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 == "" || 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/
|
||||||
|
provider, err := dns.NewDNSChallengeProviderByName(cfg.DNSProvider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("can not create DNS Challenge provider: %w", err)
|
||||||
|
}
|
||||||
|
if err := mainDomainAcmeClient.Challenge.SetDNS01Provider(provider); err != nil {
|
||||||
|
return nil, fmt.Errorf("can not create DNS-01 provider: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,10 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"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) {
|
func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
|
||||||
var myAcmeAccount AcmeAccount
|
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)
|
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 {
|
if account, err := os.ReadFile(cfg.AccountConfigFile); err == nil {
|
||||||
log.Info().Msgf("found existing acme account config file '%s'", cfg.AccountConfigFile)
|
log.Info().Msgf("found existing acme account config file '%s'", cfg.AccountConfigFile)
|
||||||
if err := json.Unmarshal(account, &myAcmeAccount); err != nil {
|
if err := json.Unmarshal(account, &myAcmeAccount); err != nil {
|
||||||
@ -40,11 +46,14 @@ func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
|
|||||||
myAcmeConfig.CADirURL = cfg.APIEndpoint
|
myAcmeConfig.CADirURL = cfg.APIEndpoint
|
||||||
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
|
||||||
// Validate Config
|
// Skip validation for mock directory
|
||||||
_, err := lego.NewClient(myAcmeConfig)
|
if !isMockDirectory {
|
||||||
if err != nil {
|
// Validate Config
|
||||||
log.Info().Err(err).Msg("config validation failed, you might just delete the config file and let it recreate")
|
_, err := lego.NewClient(myAcmeConfig)
|
||||||
return nil, fmt.Errorf("acme config validation failed: %w", err)
|
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
|
return myAcmeConfig, nil
|
||||||
@ -66,42 +75,48 @@ func setupAcmeConfig(cfg config.ACMEConfig) (*lego.Config, error) {
|
|||||||
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
|
myAcmeConfig = lego.NewConfig(&myAcmeAccount)
|
||||||
myAcmeConfig.CADirURL = cfg.APIEndpoint
|
myAcmeConfig.CADirURL = cfg.APIEndpoint
|
||||||
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
myAcmeConfig.Certificate.KeyType = certcrypto.RSA2048
|
||||||
tempClient, err := lego.NewClient(myAcmeConfig)
|
|
||||||
if err != nil {
|
// Skip client creation for mock directory to avoid certificate verification errors
|
||||||
log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
|
if isMockDirectory {
|
||||||
|
log.Info().Msg("Using mock ACME directory, skipping client creation and registration")
|
||||||
} else {
|
} else {
|
||||||
// accept terms & log in to EAB
|
tempClient, err := lego.NewClient(myAcmeConfig)
|
||||||
if cfg.EAB_KID == "" || cfg.EAB_HMAC == "" {
|
if err != nil {
|
||||||
reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: cfg.AcceptTerms})
|
log.Error().Err(err).Msg("Can't create ACME client, continuing with mock certs only")
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Can't register ACME account, continuing with mock certs only")
|
|
||||||
} else {
|
|
||||||
myAcmeAccount.Registration = reg
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
// accept terms & log in to EAB
|
||||||
TermsOfServiceAgreed: cfg.AcceptTerms,
|
if cfg.EAB_KID == "" || cfg.EAB_HMAC == "" {
|
||||||
Kid: cfg.EAB_KID,
|
reg, err := tempClient.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: cfg.AcceptTerms})
|
||||||
HmacEncoded: cfg.EAB_HMAC,
|
if err != nil {
|
||||||
})
|
log.Error().Err(err).Msg("Can't register ACME account, continuing with mock certs only")
|
||||||
if err != nil {
|
} else {
|
||||||
log.Error().Err(err).Msg("Can't register ACME account, continuing with mock certs only")
|
myAcmeAccount.Registration = reg
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
myAcmeAccount.Registration = reg
|
reg, err := tempClient.Registration.RegisterWithExternalAccountBinding(registration.RegisterEABOptions{
|
||||||
|
TermsOfServiceAgreed: cfg.AcceptTerms,
|
||||||
|
Kid: cfg.EAB_KID,
|
||||||
|
HmacEncoded: cfg.EAB_HMAC,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Can't register ACME account, continuing with mock certs only")
|
||||||
|
} else {
|
||||||
|
myAcmeAccount.Registration = reg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if myAcmeAccount.Registration != nil {
|
if myAcmeAccount.Registration != nil {
|
||||||
acmeAccountJSON, err := json.Marshal(myAcmeAccount)
|
acmeAccountJSON, err := json.Marshal(myAcmeAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("json.Marshalfailed, waiting for manual restart to avoid rate limits")
|
log.Error().Err(err).Msg("json.Marshalfailed, waiting for manual restart to avoid rate limits")
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
log.Info().Msgf("new acme account created. write to config file '%s'", cfg.AccountConfigFile)
|
log.Info().Msgf("new acme account created. write to config file '%s'", cfg.AccountConfigFile)
|
||||||
err = os.WriteFile(cfg.AccountConfigFile, acmeAccountJSON, 0o600)
|
err = os.WriteFile(cfg.AccountConfigFile, acmeAccountJSON, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("os.WriteFile failed, waiting for manual restart to avoid rate limits")
|
log.Error().Err(err).Msg("os.WriteFile failed, waiting for manual restart to avoid rate limits")
|
||||||
select {}
|
select {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user