Refactored config system again
All checks were successful
Build (artifact) / build (push) Successful in 27s
All checks were successful
Build (artifact) / build (push) Successful in 27s
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"git.nevets.tech/Steven/certman/common"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
@@ -58,6 +59,11 @@ type ACMEManager struct {
|
||||
Client *lego.Client
|
||||
User *fileUser
|
||||
|
||||
// cached DNS-01 provider so we can re-bind it with per-domain recursive nameservers
|
||||
cfProvider *cloudflare.DNSProvider
|
||||
// snapshot of /etc/resolv.conf nameservers taken at manager init
|
||||
defaultNameservers []string
|
||||
|
||||
// root dirs
|
||||
dataRoot string // e.g. /var/local/certman
|
||||
accountRoot string // e.g. /var/local/certman/accounts
|
||||
@@ -143,7 +149,10 @@ func NewACMEManager(config *common.AppConfig) (*ACMEManager, error) {
|
||||
return nil, fmt.Errorf("cloudflare dns provider: %w", err)
|
||||
}
|
||||
|
||||
if err = client.Challenge.SetDNS01Provider(cfProvider); err != nil {
|
||||
mgr.cfProvider = cfProvider
|
||||
mgr.defaultNameservers = dns01.ParseNameservers(readResolvConfNameservers("/etc/resolv.conf"))
|
||||
|
||||
if err = client.Challenge.SetDNS01Provider(cfProvider, dns01.AddRecursiveNameservers(mgr.defaultNameservers)); err != nil {
|
||||
return nil, fmt.Errorf("set dns-01 provider: %w", err)
|
||||
}
|
||||
|
||||
@@ -168,7 +177,9 @@ func NewACMEManager(config *common.AppConfig) (*ACMEManager, error) {
|
||||
}
|
||||
|
||||
// ObtainForDomain obtains a new cert for a configured domain and saves it to disk.
|
||||
func (m *ACMEManager) ObtainForDomain(domainKey string, config *common.AppConfig, domainConfig *common.DomainConfig) (*certificate.Resource, error) {
|
||||
func (m *ACMEManager) ObtainForDomain(config *common.AppConfig, domainConfig *common.ServerDomainConfig) (*certificate.Resource, error) {
|
||||
domainKey := domainConfig.Domain.DomainName
|
||||
|
||||
rcfg, err := buildDomainRuntimeConfig(config, domainConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -187,6 +198,10 @@ func (m *ACMEManager) ObtainForDomain(domainKey string, config *common.AppConfig
|
||||
m.MU.Lock()
|
||||
defer m.MU.Unlock()
|
||||
|
||||
if err := m.applyDNS01ForDomain(domainConfig); err != nil {
|
||||
return nil, fmt.Errorf("apply dns-01 nameservers for %q: %w", domainKey, err)
|
||||
}
|
||||
|
||||
res, err := m.Client.Certificate.Obtain(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("obtain %q: %w", domainKey, err)
|
||||
@@ -200,7 +215,9 @@ func (m *ACMEManager) ObtainForDomain(domainKey string, config *common.AppConfig
|
||||
}
|
||||
|
||||
// RenewForDomain renews an existing stored cert for a domain key.
|
||||
func (m *ACMEManager) RenewForDomain(domainKey string) (*certificate.Resource, error) {
|
||||
func (m *ACMEManager) RenewForDomain(domainConfig *common.ServerDomainConfig) (*certificate.Resource, error) {
|
||||
domainKey := domainConfig.Domain.DomainName
|
||||
|
||||
m.MU.Lock()
|
||||
defer m.MU.Unlock()
|
||||
|
||||
@@ -209,6 +226,10 @@ func (m *ACMEManager) RenewForDomain(domainKey string) (*certificate.Resource, e
|
||||
return nil, fmt.Errorf("load stored resource for %q: %w", domainKey, err)
|
||||
}
|
||||
|
||||
if err := m.applyDNS01ForDomain(domainConfig); err != nil {
|
||||
return nil, fmt.Errorf("apply dns-01 nameservers for %q: %w", domainKey, err)
|
||||
}
|
||||
|
||||
// RenewWithOptions is preferred in newer lego versions.
|
||||
renewed, err := m.Client.Certificate.RenewWithOptions(*existing, &certificate.RenewOptions{
|
||||
Bundle: true,
|
||||
@@ -232,17 +253,55 @@ func (m *ACMEManager) GetCertPaths(domainKey string) (certPEM, keyPEM string) {
|
||||
filepath.Join(dir, base+".key")
|
||||
}
|
||||
|
||||
// applyDNS01ForDomain re-binds the lego DNS-01 provider with recursive nameservers
|
||||
// appropriate for this domain. When ServerDomainCfg.DNSServer is empty or "default", the
|
||||
// resolv.conf snapshot taken at NewACMEManager time is used; otherwise the configured
|
||||
// server is used. Caller must hold m.MU.
|
||||
func (m *ACMEManager) applyDNS01ForDomain(domainConfig *common.ServerDomainConfig) error {
|
||||
ns := m.defaultNameservers
|
||||
cfgDNS := strings.TrimSpace(domainConfig.Domain.DNSServer)
|
||||
if cfgDNS != "" && !strings.EqualFold(cfgDNS, "default") {
|
||||
ns = dns01.ParseNameservers([]string{cfgDNS})
|
||||
}
|
||||
return m.Client.Challenge.SetDNS01Provider(m.cfProvider, dns01.AddRecursiveNameservers(ns))
|
||||
}
|
||||
|
||||
// readResolvConfNameservers parses `nameserver` lines from a resolv.conf-style file.
|
||||
// Returns nil on any error so the caller falls through to lego's own defaults.
|
||||
func readResolvConfNameservers(path string) []string {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var servers []string
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
|
||||
continue
|
||||
}
|
||||
rest, ok := strings.CutPrefix(line, "nameserver")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ns := strings.TrimSpace(rest)
|
||||
if ns != "" {
|
||||
servers = append(servers, ns)
|
||||
}
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
// ---------------------------------------------
|
||||
// Domain runtime config assembly
|
||||
// ---------------------------------------------
|
||||
|
||||
func buildDomainRuntimeConfig(config *common.AppConfig, domainConfig *common.DomainConfig) (*DomainRuntimeConfig, error) {
|
||||
func buildDomainRuntimeConfig(config *common.AppConfig, domainConfig *common.ServerDomainConfig) (*DomainRuntimeConfig, error) {
|
||||
domainName := domainConfig.Domain.DomainName
|
||||
|
||||
email := config.Certificates.Email
|
||||
|
||||
// domain override data_root can be blank -> main fallback
|
||||
dataRoot := common.EffectiveDataRoot(config, domainConfig)
|
||||
dataRoot := common.EffectiveDataRoot(config, domainConfig.Certificates.DataRoot)
|
||||
|
||||
caDirURL := config.Certificates.CADirURL
|
||||
|
||||
|
||||
Reference in New Issue
Block a user