mirror of
https://github.com/caddyserver/caddy.git
synced 2025-04-24 05:44:04 +08:00
Apply global DNS module to ACME challenges
This allows DNS challenges to be enabled without locally-configured DNS modules
This commit is contained in:
parent
a9a65a7833
commit
9ce7fa7f2a
@ -99,7 +99,7 @@ func parseBind(h Helper) ([]ConfigValue, error) {
|
||||
// ca <acme_ca_endpoint>
|
||||
// ca_root <pem_file>
|
||||
// key_type [ed25519|p256|p384|rsa2048|rsa4096]
|
||||
// dns <provider_name> [...]
|
||||
// dns [<provider_name> [...]] (required, though, if DNS is not configured as global option)
|
||||
// propagation_delay <duration>
|
||||
// propagation_timeout <duration>
|
||||
// resolvers <dns_servers...>
|
||||
@ -312,10 +312,6 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
||||
certManagers = append(certManagers, certManager)
|
||||
|
||||
case "dns":
|
||||
if !h.NextArg() {
|
||||
return nil, h.ArgErr()
|
||||
}
|
||||
provName := h.Val()
|
||||
if acmeIssuer == nil {
|
||||
acmeIssuer = new(caddytls.ACMEIssuer)
|
||||
}
|
||||
@ -325,12 +321,19 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
||||
if acmeIssuer.Challenges.DNS == nil {
|
||||
acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
|
||||
}
|
||||
modID := "dns.providers." + provName
|
||||
unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// DNS provider configuration optional, since it may be configured globally via the TLS app with global options
|
||||
if h.NextArg() {
|
||||
provName := h.Val()
|
||||
modID := "dns.providers." + provName
|
||||
unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
|
||||
} else if h.Option("dns") == nil {
|
||||
// if DNS is omitted locally, it needs to be configured globally
|
||||
return nil, h.ArgErr()
|
||||
}
|
||||
acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
|
||||
|
||||
case "resolvers":
|
||||
args := h.RemainingArgs()
|
||||
|
@ -577,7 +577,8 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e
|
||||
if globalPreferredChains != nil && acmeIssuer.PreferredChains == nil {
|
||||
acmeIssuer.PreferredChains = globalPreferredChains.(*caddytls.ChainPreference)
|
||||
}
|
||||
if globalHTTPPort != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.HTTP == nil || acmeIssuer.Challenges.HTTP.AlternatePort == 0) {
|
||||
// only configure alt HTTP and TLS-ALPN ports if the DNS challenge is not enabled (wouldn't hurt, but isn't necessary since the DNS challenge is exclusive of others)
|
||||
if globalHTTPPort != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.DNS == nil) && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.HTTP == nil || acmeIssuer.Challenges.HTTP.AlternatePort == 0) {
|
||||
if acmeIssuer.Challenges == nil {
|
||||
acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
|
||||
}
|
||||
@ -586,7 +587,7 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e
|
||||
}
|
||||
acmeIssuer.Challenges.HTTP.AlternatePort = globalHTTPPort.(int)
|
||||
}
|
||||
if globalHTTPSPort != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.TLSALPN == nil || acmeIssuer.Challenges.TLSALPN.AlternatePort == 0) {
|
||||
if globalHTTPSPort != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.DNS == nil) && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.TLSALPN == nil || acmeIssuer.Challenges.TLSALPN.AlternatePort == 0) {
|
||||
if acmeIssuer.Challenges == nil {
|
||||
acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
|
||||
}
|
||||
|
12
context.go
12
context.go
@ -385,6 +385,17 @@ func (ctx Context) LoadModuleByID(id string, rawMsg json.RawMessage) (any, error
|
||||
return nil, fmt.Errorf("module value cannot be null")
|
||||
}
|
||||
|
||||
// if this is an app module, keep a reference to it,
|
||||
// since submodules may need to reference it during
|
||||
// provisioning (even though the parent app module
|
||||
// may not be fully provisioned yet; this is the case
|
||||
// with the tls app's automation policies, which may
|
||||
// refer to the tls app to check if a global DNS
|
||||
// module has been configured for DNS challenges)
|
||||
if appModule, ok := val.(App); ok {
|
||||
ctx.cfg.apps[id] = appModule
|
||||
}
|
||||
|
||||
ctx.ancestry = append(ctx.ancestry, val)
|
||||
|
||||
if prov, ok := val.(Provisioner); ok {
|
||||
@ -471,7 +482,6 @@ func (ctx Context) App(name string) (any, error) {
|
||||
if appRaw != nil {
|
||||
ctx.cfg.AppsRaw[name] = nil // allow GC to deallocate
|
||||
}
|
||||
ctx.cfg.apps[name] = modVal.(App)
|
||||
return modVal, nil
|
||||
}
|
||||
|
||||
|
@ -146,15 +146,30 @@ func (iss *ACMEIssuer) Provision(ctx caddy.Context) error {
|
||||
iss.AccountKey = accountKey
|
||||
}
|
||||
|
||||
// DNS providers
|
||||
if iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.ProviderRaw != nil {
|
||||
val, err := ctx.LoadModule(iss.Challenges.DNS, "ProviderRaw")
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading DNS provider module: %v", err)
|
||||
// DNS challenge provider
|
||||
if iss.Challenges != nil && iss.Challenges.DNS != nil {
|
||||
var prov certmagic.DNSProvider
|
||||
if iss.Challenges.DNS.ProviderRaw != nil {
|
||||
// a challenge provider has been locally configured - use it
|
||||
val, err := ctx.LoadModule(iss.Challenges.DNS, "ProviderRaw")
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading DNS provider module: %v", err)
|
||||
}
|
||||
prov = val.(certmagic.DNSProvider)
|
||||
} else if tlsAppIface, err := ctx.AppIfConfigured("tls"); err == nil {
|
||||
// no locally configured DNS challenge provider, but if there is
|
||||
// a global DNS module configured with the TLS app, use that
|
||||
tlsApp := tlsAppIface.(*TLS)
|
||||
if tlsApp.dns != nil {
|
||||
prov = tlsApp.dns.(certmagic.DNSProvider)
|
||||
}
|
||||
}
|
||||
if prov == nil {
|
||||
return fmt.Errorf("DNS challenge enabled, but no DNS provider configured")
|
||||
}
|
||||
iss.Challenges.DNS.solver = &certmagic.DNS01Solver{
|
||||
DNSManager: certmagic.DNSManager{
|
||||
DNSProvider: val.(certmagic.DNSProvider),
|
||||
DNSProvider: prov,
|
||||
TTL: time.Duration(iss.Challenges.DNS.TTL),
|
||||
PropagationDelay: time.Duration(iss.Challenges.DNS.PropagationDelay),
|
||||
PropagationTimeout: time.Duration(iss.Challenges.DNS.PropagationTimeout),
|
||||
|
@ -242,6 +242,9 @@ func (t *TLS) publishECHConfigs() error {
|
||||
// if all the (inner) domains have had this ECH config list published
|
||||
// by this publisher, then try the next publication config
|
||||
if len(serverNamesSet) == 0 {
|
||||
logger.Debug("ECH config list already published by publisher for associated domains",
|
||||
zap.Uint8s("config_ids", configIDs),
|
||||
zap.String("publisher", publisherKey))
|
||||
continue
|
||||
}
|
||||
|
||||
@ -252,7 +255,7 @@ func (t *TLS) publishECHConfigs() error {
|
||||
}
|
||||
|
||||
logger.Debug("publishing ECH config list",
|
||||
zap.Strings("inner_names", dnsNamesToPublish),
|
||||
zap.Strings("domains", dnsNamesToPublish),
|
||||
zap.Uint8s("config_ids", configIDs))
|
||||
|
||||
// publish this ECH config list with this publisher
|
||||
@ -1045,22 +1048,6 @@ type echConfigMeta struct {
|
||||
// map of inner name to timestamp
|
||||
type publicationHistory map[string]map[string]time.Time
|
||||
|
||||
func (hist publicationHistory) unpublishedNames(publisherKey string, serverNamesSet map[string]struct{}) map[string]struct{} {
|
||||
innerNamesSet, ok := hist[publisherKey]
|
||||
if !ok {
|
||||
// no history of this publisher publishing this config at all, so publish for entire set of names
|
||||
return serverNamesSet
|
||||
}
|
||||
for innerName := range innerNamesSet {
|
||||
// names in this loop have already had this config published by this publisher,
|
||||
// so delete them from the set of names to publish for
|
||||
//
|
||||
// TODO: Potentially utilize the timestamp (map value) to preserve server name for re-publication if enough time has passed
|
||||
delete(serverNamesSet, innerName)
|
||||
}
|
||||
return serverNamesSet
|
||||
}
|
||||
|
||||
// The key prefix when putting ECH configs in storage. After this
|
||||
// comes the config ID.
|
||||
const echConfigsKey = "ech/configs"
|
||||
|
@ -163,6 +163,7 @@ func (t *TLS) Provision(ctx caddy.Context) error {
|
||||
|
||||
// set up default DNS module, if any, and make sure it implements all the
|
||||
// common libdns interfaces, since it could be used for a variety of things
|
||||
// (do this before provisioning other modules, since they may rely on this)
|
||||
if len(t.DNSRaw) > 0 {
|
||||
dnsMod, err := ctx.LoadModule(t, "DNSRaw")
|
||||
if err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user