summaryrefslogtreecommitdiff
path: root/caddyconfig/httpcaddyfile
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-09-30 09:11:30 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-09-30 09:11:30 -0600
commit1e662262179d326586d2beb849f842b82b7324c4 (patch)
tree1b2e79e4e27e7b4812f6566104568092bc7bcd7d /caddyconfig/httpcaddyfile
parent7b4aa108c7d67416bf68574da6c5a43899715b3d (diff)
httpcaddyfile: Add acme_ca and email global options
Also add ability to access options from individual unmarshalers through the Helper values
Diffstat (limited to 'caddyconfig/httpcaddyfile')
-rw-r--r--caddyconfig/httpcaddyfile/builtins.go12
-rw-r--r--caddyconfig/httpcaddyfile/directives.go6
-rw-r--r--caddyconfig/httpcaddyfile/handlers.go56
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go84
-rw-r--r--caddyconfig/httpcaddyfile/options.go24
5 files changed, 112 insertions, 70 deletions
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go
index ff93b11..ec3740c 100644
--- a/caddyconfig/httpcaddyfile/builtins.go
+++ b/caddyconfig/httpcaddyfile/builtins.go
@@ -86,6 +86,14 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
var mgr caddytls.ACMEManagerMaker
var off bool
+ // fill in global defaults, if configured
+ if email := h.Option("email"); email != nil {
+ mgr.Email = email.(string)
+ }
+ if acmeCA := h.Option("acme_ca"); acmeCA != nil {
+ mgr.CA = acmeCA.(string)
+ }
+
for h.Next() {
// file certificate loader
firstLine := h.RemainingArgs()
@@ -112,7 +120,6 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
hasBlock = true
switch h.Val() {
-
// connection policy
case "protocols":
args := h.RemainingArgs()
@@ -164,7 +171,8 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
}
mgr.CA = arg[0]
- // TODO: other properties for automation manager
+ default:
+ return nil, h.Errf("unknown subdirective: %s", h.Val())
}
}
diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go
index 2f89f6d..0d7e0e4 100644
--- a/caddyconfig/httpcaddyfile/directives.go
+++ b/caddyconfig/httpcaddyfile/directives.go
@@ -80,11 +80,17 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
// Caddyfile tokens.
type Helper struct {
*caddyfile.Dispenser
+ options map[string]interface{}
warnings *[]caddyconfig.Warning
matcherDefs map[string]map[string]json.RawMessage
parentBlock caddyfile.ServerBlock
}
+// Option gets the option keyed by name.
+func (h Helper) Option(name string) interface{} {
+ return h.options[name]
+}
+
// Caddyfiles returns the list of config files from
// which tokens in the current server block were loaded.
func (h Helper) Caddyfiles() []string {
diff --git a/caddyconfig/httpcaddyfile/handlers.go b/caddyconfig/httpcaddyfile/handlers.go
deleted file mode 100644
index e133028..0000000
--- a/caddyconfig/httpcaddyfile/handlers.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 Matthew Holt and The Caddy Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package httpcaddyfile
-
-import (
- "encoding/json"
- "fmt"
-
- "github.com/caddyserver/caddy/v2"
- "github.com/caddyserver/caddy/v2/caddyconfig"
- "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
- "github.com/caddyserver/caddy/v2/modules/caddyhttp"
-)
-
-func (st *ServerType) parseMatcherDefinitions(d *caddyfile.Dispenser) (map[string]map[string]json.RawMessage, error) {
- matchers := make(map[string]map[string]json.RawMessage)
- for d.Next() {
- definitionName := d.Val()
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- matcherName := d.Val()
- mod, err := caddy.GetModule("http.matchers." + matcherName)
- if err != nil {
- return nil, fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
- }
- unm, ok := mod.New().(caddyfile.Unmarshaler)
- if !ok {
- return nil, fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
- }
- err = unm.UnmarshalCaddyfile(d.NewFromNextTokens())
- if err != nil {
- return nil, err
- }
- rm, ok := unm.(caddyhttp.RequestMatcher)
- if !ok {
- return nil, fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
- }
- if _, ok := matchers[definitionName]; !ok {
- matchers[definitionName] = make(map[string]json.RawMessage)
- }
- matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
- }
- }
- return matchers, nil
-}
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index 265cf73..794919c 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -58,6 +58,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
var val interface{}
var err error
disp := caddyfile.NewDispenser(segment)
+ // TODO: make this switch into a map
switch dir {
case "http_port":
val, err = parseOptHTTPPort(disp)
@@ -69,6 +70,10 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
val, err = parseOptExperimentalHTTP3(disp)
case "storage":
val, err = parseOptStorage(disp)
+ case "acme_ca":
+ val, err = parseOptACMECA(disp)
+ case "email":
+ val, err = parseOptEmail(disp)
default:
return nil, warnings, fmt.Errorf("unrecognized parameter name: %s", dir)
}
@@ -108,7 +113,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
// extract matcher definitions
d := sb.block.DispenseDirective("matcher")
- matcherDefs, err := st.parseMatcherDefinitions(d)
+ matcherDefs, err := parseMatcherDefinitions(d)
if err != nil {
return nil, warnings, err
}
@@ -122,6 +127,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
if dirFunc, ok := registeredDirectives[dir]; ok {
results, err := dirFunc(Helper{
Dispenser: caddyfile.NewDispenser(segment),
+ options: options,
warnings: &warnings,
matcherDefs: matcherDefs,
parentBlock: sb.block,
@@ -166,7 +172,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
// now for the TLS app! (TODO: refactor into own func)
tlsApp := caddytls.TLS{Certificates: make(map[string]json.RawMessage)}
for _, p := range pairings {
- for _, sblock := range p.serverBlocks {
+ for i, sblock := range p.serverBlocks {
// tls automation policies
if mmVals, ok := sblock.pile["tls.automation_manager"]; ok {
for _, mmVal := range mmVals {
@@ -175,10 +181,16 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
if err != nil {
return nil, warnings, err
}
- tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
- Hosts: sblockHosts,
- ManagementRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID(), &warnings),
- })
+ if len(sblockHosts) > 0 {
+ tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
+ Hosts: sblockHosts,
+ ManagementRaw: caddyconfig.JSONModuleObject(mm, "module", mm.(caddy.Module).CaddyModule().ID(), &warnings),
+ })
+ } else {
+ warnings = append(warnings, caddyconfig.Warning{
+ Message: fmt.Sprintf("Server block %d %v has no names that qualify for automatic HTTPS, so no TLS automation policy will be added.", i, sblock.block.Keys),
+ })
+ }
}
}
@@ -192,8 +204,25 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
}
}
}
- // consolidate automation policies that are the exact same
- tlsApp.Automation.Policies = consolidateAutomationPolicies(tlsApp.Automation.Policies)
+ // if global ACME CA or email were set, append a catch-all automation
+ // policy that ensures they will be used if no tls directive was used
+ acmeCA, hasACMECA := options["acme_ca"]
+ email, hasEmail := options["email"]
+ if hasACMECA || hasEmail {
+ if tlsApp.Automation == nil {
+ tlsApp.Automation = new(caddytls.AutomationConfig)
+ }
+ tlsApp.Automation.Policies = append(tlsApp.Automation.Policies, caddytls.AutomationPolicy{
+ ManagementRaw: caddyconfig.JSONModuleObject(caddytls.ACMEManagerMaker{
+ CA: acmeCA.(string),
+ Email: email.(string),
+ }, "module", "acme", &warnings),
+ })
+ }
+ if tlsApp.Automation != nil {
+ // consolidate automation policies that are the exact same
+ tlsApp.Automation.Policies = consolidateAutomationPolicies(tlsApp.Automation.Policies)
+ }
// if experimental HTTP/3 is enabled, enable it on each server
if enableH3, ok := options["experimental_http3"].(bool); ok && enableH3 {
@@ -207,7 +236,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
if !reflect.DeepEqual(httpApp, caddyhttp.App{}) {
cfg.AppsRaw["http"] = caddyconfig.JSON(httpApp, &warnings)
}
- if !reflect.DeepEqual(tlsApp, caddytls.TLS{}) {
+ if !reflect.DeepEqual(tlsApp, caddytls.TLS{Certificates: make(map[string]json.RawMessage)}) {
cfg.AppsRaw["tls"] = caddyconfig.JSON(tlsApp, &warnings)
}
if storageCvtr, ok := options["storage"].(caddy.StorageConverter); ok {
@@ -415,10 +444,10 @@ func consolidateAutomationPolicies(aps []caddytls.AutomationPolicy) []caddytls.A
}
if reflect.DeepEqual(aps[i].ManagementRaw, aps[j].ManagementRaw) {
aps[i].Hosts = append(aps[i].Hosts, aps[j].Hosts...)
+ aps = append(aps[:j], aps[j+1:]...)
+ i--
+ break
}
- aps = append(aps[:j], aps[j+1:]...)
- i--
- break
}
}
return aps
@@ -531,6 +560,37 @@ func (st *ServerType) compileEncodedMatcherSets(sblock caddyfile.ServerBlock) ([
return matcherSetsEnc, nil
}
+func parseMatcherDefinitions(d *caddyfile.Dispenser) (map[string]map[string]json.RawMessage, error) {
+ matchers := make(map[string]map[string]json.RawMessage)
+ for d.Next() {
+ definitionName := d.Val()
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ matcherName := d.Val()
+ mod, err := caddy.GetModule("http.matchers." + matcherName)
+ if err != nil {
+ return nil, fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
+ }
+ unm, ok := mod.New().(caddyfile.Unmarshaler)
+ if !ok {
+ return nil, fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
+ }
+ err = unm.UnmarshalCaddyfile(d.NewFromNextTokens())
+ if err != nil {
+ return nil, err
+ }
+ rm, ok := unm.(caddyhttp.RequestMatcher)
+ if !ok {
+ return nil, fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
+ }
+ if _, ok := matchers[definitionName]; !ok {
+ matchers[definitionName] = make(map[string]json.RawMessage)
+ }
+ matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
+ }
+ }
+ return matchers, nil
+}
+
func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcher) (map[string]json.RawMessage, error) {
msEncoded := make(map[string]json.RawMessage)
for matcherName, val := range matchers {
diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go
index dadde28..a60d060 100644
--- a/caddyconfig/httpcaddyfile/options.go
+++ b/caddyconfig/httpcaddyfile/options.go
@@ -108,3 +108,27 @@ func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
}
return storage, nil
}
+
+func parseOptACMECA(d *caddyfile.Dispenser) (string, error) {
+ d.Next() // consume parameter name
+ if !d.Next() {
+ return "", d.ArgErr()
+ }
+ val := d.Val()
+ if d.Next() {
+ return "", d.ArgErr()
+ }
+ return val, nil
+}
+
+func parseOptEmail(d *caddyfile.Dispenser) (string, error) {
+ d.Next() // consume parameter name
+ if !d.Next() {
+ return "", d.ArgErr()
+ }
+ val := d.Val()
+ if d.Next() {
+ return "", d.ArgErr()
+ }
+ return val, nil
+}