@marcel91200 / caddy Mirror · read-only / commits / 0188ef2e
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 16:00 UTC

acmeserver: warn when policy rules unset (#7469)

Oleh Konko | trust infra security audit & contribution | deterministic ai-augmented pipeline · human-verified committed Feb 11, 2026 at 18:54 UTC 0188ef2e62e772be30ef01344e6103ecf7a57db0
2 files changed +111
modules/caddypki/acmeserver/acmeserver.go
+17
@@ -140,6 +140,8 @@ func (ash *Handler) Provision(ctx caddy.Context) error {
140 }
141 }
142
143 + ash.warnIfPolicyAllowsAll()
144 +
145 // get a reference to the configured CA
146 appModule, err := ctx.App("pki")
147 if err != nil {
@@ -214,6 +216,21 @@ func (ash *Handler) Provision(ctx caddy.Context) error {
216 return nil
217 }
218
219 +func (ash *Handler) warnIfPolicyAllowsAll() {
220 + allow := ash.Policy.normalizeAllowRules()
221 + deny := ash.Policy.normalizeDenyRules()
222 + if allow != nil || deny != nil {
223 + return
224 + }
225 +
226 + allowWildcardNames := ash.Policy != nil && ash.Policy.AllowWildcardNames
227 + ash.logger.Warn(
228 + "acme_server policy has no allow/deny rules; order identifiers are unrestricted (allow-all)",
229 + zap.String("ca", ash.CA),
230 + zap.Bool("allow_wildcard_names", allowWildcardNames),
231 + )
232 +}
233 +
234 func (ash Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
235 if strings.HasPrefix(r.URL.Path, ash.PathPrefix) {
236 acmeCtx := acme.NewContext(
modules/caddypki/acmeserver/acmeserver_test.go new
+94
@@ -0,0 +1,94 @@
1 +package acmeserver
2 +
3 +import (
4 + "strings"
5 + "testing"
6 +
7 + "go.uber.org/zap"
8 + "go.uber.org/zap/zaptest/observer"
9 +)
10 +
11 +func TestHandler_warnIfPolicyAllowsAll(t *testing.T) {
12 + tests := []struct {
13 + name string
14 + policy *Policy
15 + wantWarns int
16 + wantAllowWildcard bool
17 + }{
18 + {
19 + name: "warns when policy is nil",
20 + policy: nil,
21 + wantWarns: 1,
22 + wantAllowWildcard: false,
23 + },
24 + {
25 + name: "warns when allow/deny rules are empty",
26 + policy: &Policy{},
27 + wantWarns: 1,
28 + wantAllowWildcard: false,
29 + },
30 + {
31 + name: "warns when only allow_wildcard_names is true",
32 + policy: &Policy{
33 + AllowWildcardNames: true,
34 + },
35 + wantWarns: 1,
36 + wantAllowWildcard: true,
37 + },
38 + {
39 + name: "does not warn when allow rules are configured",
40 + policy: &Policy{
41 + Allow: &RuleSet{
42 + Domains: []string{"example.com"},
43 + },
44 + },
45 + wantWarns: 0,
46 + wantAllowWildcard: false,
47 + },
48 + {
49 + name: "does not warn when deny rules are configured",
50 + policy: &Policy{
51 + Deny: &RuleSet{
52 + Domains: []string{"bad.example.com"},
53 + },
54 + },
55 + wantWarns: 0,
56 + wantAllowWildcard: false,
57 + },
58 + }
59 +
60 + for _, tt := range tests {
61 + t.Run(tt.name, func(t *testing.T) {
62 + core, logs := observer.New(zap.WarnLevel)
63 + ash := &Handler{
64 + CA: "local",
65 + Policy: tt.policy,
66 + logger: zap.New(core),
67 + }
68 +
69 + ash.warnIfPolicyAllowsAll()
70 + if logs.Len() != tt.wantWarns {
71 + t.Fatalf("expected %d warning logs, got %d", tt.wantWarns, logs.Len())
72 + }
73 +
74 + if tt.wantWarns == 0 {
75 + return
76 + }
77 +
78 + entry := logs.All()[0]
79 + if entry.Level != zap.WarnLevel {
80 + t.Fatalf("expected warn level, got %v", entry.Level)
81 + }
82 + if !strings.Contains(entry.Message, "policy has no allow/deny rules") {
83 + t.Fatalf("unexpected log message: %q", entry.Message)
84 + }
85 + ctx := entry.ContextMap()
86 + if ctx["ca"] != "local" {
87 + t.Fatalf("expected ca=local, got %v", ctx["ca"])
88 + }
89 + if ctx["allow_wildcard_names"] != tt.wantAllowWildcard {
90 + t.Fatalf("expected allow_wildcard_names=%v, got %v", tt.wantAllowWildcard, ctx["allow_wildcard_names"])
91 + }
92 + })
93 + }
94 +}