route-proxy: a policy refusal is also not-my-token #67

Merged
jschoubben merged 1 commits from fix/a-policy-refusal-is-also-not-my-token into main 2026-09-26 12:26:19 +00:00
2 changed files with 28 additions and 2 deletions
+23
View File
@@ -7,6 +7,8 @@ package main
// three behaviours tokenOrRoute exists for.
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
@@ -73,6 +75,27 @@ func TestASecondAuthorityIsProbedBeforeRouting(t *testing.T) {
}
}
func TestAnAuthorityWhosePolicyRefusesTheNameIsProbedPast(t *testing.T) {
// autocert checks the host policy before the token and answers 403 — the internal authority
// does this for every public name. A policy refusal is as much "not mine" as a missing token:
// the request must still reach plain routing, where the workload's own ACME client answers.
refusing := &autocert.Manager{
Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache(t.TempDir()),
HostPolicy: func(ctx context.Context, host string) error {
return fmt.Errorf("no internal-only route for %q in this mesh", host)
},
}
h := tokenOrRoute(routedTo(t, "the workload answered"), refusing)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "http://mail.example/.well-known/acme-challenge/mailus-token", nil))
if rec.Code != http.StatusOK || rec.Body.String() != "the workload answered" {
t.Fatalf("a policy refusal must fall through to routing; got %d %q", rec.Code, rec.Body.String())
}
}
func TestAnOrdinaryPathNeverTouchesTheChallengeMachinery(t *testing.T) {
m := &autocert.Manager{Prompt: autocert.AcceptTOS, Cache: autocert.DirCache(t.TempDir())}
h := tokenOrRoute(routedTo(t, "routed"), m)
+5 -2
View File
@@ -458,8 +458,11 @@ func tokenOrRoute(routes http.Handler, managers ...*autocert.Manager) http.Handl
for _, probe := range probes {
buffered := &probedResponse{header: make(http.Header)}
probe.ServeHTTP(buffered, r)
if buffered.status == http.StatusNotFound {
continue // not this manager's token
// Two shapes of "not mine": 404, a token this manager is not holding — and 403, a
// name its host policy would never certify at all (autocert checks the policy before
// the token, so the internal authority answers 403 for every public name).
if buffered.status == http.StatusNotFound || buffered.status == http.StatusForbidden {
continue
}
buffered.replayTo(w)
return