Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Path Check

type = "path" matches the request path, so a rule can be about what is being asked for as well as who is asking.

[filter.check.public-paths]
type  = "path"
allow = ["/crl"]

[filter.rule.public]
when = "public-paths"
then = "allow"

Connection stage only. By the identifier stage the path is always /newOrder or /finalize/{id}, so a rule combining this with a name check would be asking a question with a constant answer.

The /crl and /ca.pem trap

Both are served by the profile router, which means they sit behind the filter policy exactly like /newOrder does. Turn on an address-based check without accounting for them and two things break quietly:

  • every relying party outside your allowlist loses revocation checking, and relying parties are precisely not the ACME clients you allowlisted;
  • a host that has not installed the root yet cannot fetch it — which is the one moment it needs to, and the refusal looks like the CA being down.

So any address-based policy wants a companion rule:

[filter]
rules = ["public", "mgmt-only"]

[filter.check.public-paths]
type  = "path"
allow = ["/crl", "/ca.pem"]

[filter.check.mgmt-net]
type  = "allowed_ip"
allow = ["10.0.0.0/8"]

[filter.rule.public]
when = "public-paths"
then = "allow"

[filter.rule.mgmt-only]
when = "mgmt-net"
then = "allow"

Because public comes first and first match wins, both are served to anyone while everything else still requires the management network.

Server-level routes — GET /health, GET /, and the http-01 responder — are served by the root router, which no profile’s policy ever sees. They are already unfiltered and need no entry here.

Paths are profile-stripped

Matching is against the path with the /profile/<name> prefix removed, so /directory — not /profile/default/directory — is the value to list, and one check covers every endpoint the process serves.

Globs

* matches one or more characters other than /, i.e. one path segment:

GlobMatchesDoes not match
/crl/crl/crl/extra
/renewalInfo/*/renewalInfo/abc123/renewalInfo/a/b, /renewalInfo/
/*/directory, /newOrder/renewalInfo/abc

Everything else in a glob is literal, so a path containing regex syntax cannot smuggle a pattern in. allow/deny follow the shared rule described in Checks: deny wins, an empty allow imposes no constraint.

A check with both lists empty is a startup error — it would match every request, which is a check that does nothing.

Combining with other checks

The reason this is a check rather than the flat filter.exempt_paths list it replaces is that a path is rarely the whole answer:

# Only the operator network may revoke.
[filter.check.revocation]
type  = "path"
allow = ["/revokeCert"]

[filter.rule.no-remote-revocation]
when    = "revocation and not mgmt-net"
then    = "deny"
message = "revocation is restricted to the management network"

The old list could only say “skip the connection stage entirely for this exact string”, and could not express /renewalInfo/* at all.