diff --git a/.gitignore b/.gitignore index d8128f54..4b8dc489 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ vendor # goreleaser artifacts dist caddy-build -caddy-dist \ No newline at end of file +caddy-dist diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index cecb3d4b..2b6b111e 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -31,8 +31,9 @@ func init() { RegisterGlobalOption("experimental_http3", parseOptTrue) RegisterGlobalOption("storage", parseOptStorage) RegisterGlobalOption("acme_ca", parseOptSingleString) - RegisterGlobalOption("acme_dns", parseOptSingleString) RegisterGlobalOption("acme_ca_root", parseOptSingleString) + RegisterGlobalOption("acme_dns", parseOptSingleString) + RegisterGlobalOption("acme_eab", parseOptACMEEAB) RegisterGlobalOption("email", parseOptSingleString) RegisterGlobalOption("admin", parseOptAdmin) RegisterGlobalOption("on_demand_tls", parseOptOnDemand) @@ -180,6 +181,34 @@ func parseOptStorage(d *caddyfile.Dispenser) (interface{}, error) { return storage, nil } +func parseOptACMEEAB(d *caddyfile.Dispenser) (interface{}, error) { + eab := new(caddytls.ExternalAccountBinding) + for d.Next() { + if d.NextArg() { + return nil, d.ArgErr() + } + for nesting := d.Nesting(); d.NextBlock(nesting); { + switch d.Val() { + case "key_id": + if !d.NextArg() { + return nil, d.ArgErr() + } + eab.KeyID = d.Val() + + case "hmac": + if !d.NextArg() { + return nil, d.ArgErr() + } + eab.HMAC = d.Val() + + default: + return nil, d.Errf("unrecognized parameter '%s'", d.Val()) + } + } + } + return eab, nil +} + func parseOptSingleString(d *caddyfile.Dispenser) (interface{}, error) { d.Next() // consume parameter name if !d.Next() { diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index 90b4e71c..8f642915 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -348,13 +348,15 @@ func (st ServerType) buildTLSApp( // true, a non-nil value will always be returned (unless there is an error). func newBaseAutomationPolicy(options map[string]interface{}, warnings []caddyconfig.Warning, always bool) (*caddytls.AutomationPolicy, error) { acmeCA, hasACMECA := options["acme_ca"] - acmeDNS, hasACMEDNS := options["acme_dns"] acmeCARoot, hasACMECARoot := options["acme_ca_root"] + acmeDNS, hasACMEDNS := options["acme_dns"] + acmeEAB, hasACMEEAB := options["acme_eab"] + email, hasEmail := options["email"] localCerts, hasLocalCerts := options["local_certs"] keyType, hasKeyType := options["key_type"] - hasGlobalAutomationOpts := hasACMECA || hasACMEDNS || hasACMECARoot || hasEmail || hasLocalCerts || hasKeyType + hasGlobalAutomationOpts := hasACMECA || hasACMECARoot || hasACMEDNS || hasACMEEAB || hasEmail || hasLocalCerts || hasKeyType // if there are no global options related to automation policies // set, then we can just return right away @@ -396,6 +398,9 @@ func newBaseAutomationPolicy(options map[string]interface{}, warnings []caddycon if acmeCARoot != nil { mgr.TrustedRootsPEMFiles = []string{acmeCARoot.(string)} } + if acmeEAB != nil { + mgr.ExternalAccount = acmeEAB.(*caddytls.ExternalAccountBinding) + } if keyType != nil { ap.KeyType = keyType.(string) } diff --git a/caddytest/integration/caddyfile_adapt/global_options.txt b/caddytest/integration/caddyfile_adapt/global_options.txt index 33836ff7..7e850a39 100644 --- a/caddytest/integration/caddyfile_adapt/global_options.txt +++ b/caddytest/integration/caddyfile_adapt/global_options.txt @@ -9,6 +9,7 @@ } acme_ca https://example.com acme_ca_root /path/to/ca.crt + email test@example.com admin off on_demand_tls { @@ -68,4 +69,4 @@ } } } -} \ No newline at end of file +} diff --git a/caddytest/integration/caddyfile_adapt/global_options_acme.txt b/caddytest/integration/caddyfile_adapt/global_options_acme.txt new file mode 100644 index 00000000..edb52778 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/global_options_acme.txt @@ -0,0 +1,85 @@ +{ + debug + http_port 8080 + https_port 8443 + default_sni localhost + order root first + storage file_system { + root /data + } + acme_ca https://example.com + acme_eab { + key_id 4K2scIVbBpNd-78scadB2g + hmac abcdefghijklmnopqrstuvwx-abcdefghijklnopqrstuvwxyz12ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh + } + acme_ca_root /path/to/ca.crt + email test@example.com + admin off + on_demand_tls { + ask https://example.com + interval 30s + burst 20 + } + + key_type ed25519 +} + +:80 +---------- +{ + "admin": { + "disabled": true + }, + "logging": { + "logs": { + "default": { + "level": "DEBUG" + } + } + }, + "storage": { + "module": "file_system", + "root": "/data" + }, + "apps": { + "http": { + "http_port": 8080, + "https_port": 8443, + "servers": { + "srv0": { + "listen": [ + ":80" + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "issuer": { + "ca": "https://example.com", + "email": "test@example.com", + "external_account": { + "hmac": "abcdefghijklmnopqrstuvwx-abcdefghijklnopqrstuvwxyz12ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh", + "key_id": "4K2scIVbBpNd-78scadB2g" + }, + "module": "acme", + "trusted_roots_pem_files": [ + "/path/to/ca.crt" + ] + }, + "key_type": "ed25519" + } + ], + "on_demand": { + "rate_limit": { + "interval": 30000000000, + "burst": 20 + }, + "ask": "https://example.com" + } + } + } + } +}