carlos / platform Public

edge: door ACL tripwire — cert material never transits the fleet door

Permanent guard for the multi-region ingress design's central promise:
control/certs/**, control/edge-mesh-key and the housekeeper's own lease
object are absent from aclRead's allowlist, so no fleet box can read a
private key, ACME account key, challenge token or the housekeeper's
coordination lock through the store door however it authenticates.

Runs as an authenticated fleet client across GET/PUT/DELETE plus the
list/dirs verbs, and folds seeded and unseeded keys into the same
byte-identical-refusal check TestStoreDoorRefusalsAreByteIdentical uses,
so an existence oracle on cert material fails the same way any other
shape mismatch would. Verified as a real tripwire by locally widening
aclRead to admit control/certs/ (watched the test fail), then reverting
before commit — the revert is confirmed clean in this commit's diff.
Paul Campbell pushed by paul@keymail.dev 8e439896c2e1457fc63ef2b060a05260ee51bab9 parent eb6332a
1 file changed, +94 −0
  • internal/edge/storedoor_test.go +94 −0
diff --git a/internal/edge/storedoor_test.go b/internal/edge/storedoor_test.go
index 3a0df9c7a..0d3f8d50c 100644
--- a/internal/edge/storedoor_test.go
+++ b/internal/edge/storedoor_test.go
@@ -512,6 +512,100 @@ func TestStoreDoorRefusalsAreByteIdentical(t *testing.T) {
}
}
+// TestDoorNeverServesCertMaterial is the permanent tripwire for the
+// multi-region ingress design's central promise (bucket-writer-audit.md):
+// control/certs/**, control/edge-mesh-key and the housekeeper's own lease
+// object are NOT in aclRead's allowlist (compare the doc comment above
+// aclRead — control/serial, bootstrap/carlos, domains/, accounts/<sqid>/,
+// apps/<sqid>/, fleets/<fleet>/, and nothing else), so no fleet box can ever
+// read a private key, an ACME account key, a challenge token or the
+// housekeeper's coordination lock through this door, however it authenticates.
+//
+// It runs as an AUTHENTICATED fleet client (own sqid/fleet, real bearer
+// token) — an unauthenticated 404 would prove nothing about the ACL — across
+// all three verbs the door exposes on a single object (GET/PUT/DELETE) plus
+// both listing verbs, and it proves the refusal is byte-identical whether the
+// key exists in the backing store or not: two of the seven keys below are
+// seeded with plausible cert bytes before the loop runs, the rest are left
+// absent, and every response — seeded or not — is folded into the same
+// byte-identical comparison TestStoreDoorRefusalsAreByteIdentical uses, so an
+// existence oracle on cert material would fail exactly the same way a status
+// mismatch would.
+func TestDoorNeverServesCertMaterial(t *testing.T) {
+ d, store := newTestDoor(t)
+
+ // The real Task 4/5 key shapes (certsync.go's certKey naming: bare host,
+ // the autocert account key, an HTTP-01 token response, a tls-alpn-01
+ // token cert, a wildcard account key) plus the two other control/
+ // entries the multi-region design reserves for the housekeeper alone
+ // (bucket-writer-audit.md, "Not yet built" table): the mesh pairing key
+ // and the housekeeper's own election lock.
+ certKeys := []string{
+ "control/certs/example.com",
+ "control/certs/acme_account+key",
+ "control/certs/wildcard-account.key",
+ "control/certs/tok+http-01",
+ "control/certs/example.com+token",
+ "control/edge-mesh-key",
+ "control/housekeeper-lease/lock.json",
+ }
+ // Seed two of the seven with plausible-looking secret bytes: if the ACL
+ // ever let a Get through, these are the ones that would leak real
+ // material instead of a "not found" — and mixing seeded with unseeded
+ // keys through the identical-shape check below is what proves the door
+ // isn't just refusing absent keys, it's refusing to distinguish "exists"
+ // from "doesn't" at all for this whole prefix.
+ seedObject(t, store, "control/certs/example.com", "-----BEGIN CERTIFICATE-----\nfake\n-----END CERTIFICATE-----")
+ seedObject(t, store, "control/edge-mesh-key", "fake-mesh-shared-secret")
+
+ type shape struct {
+ code int
+ header string
+ body string
+ }
+ var want *shape
+ var wantName string
+ check := func(name string, w *httptest.ResponseRecorder) {
+ t.Helper()
+ if w.Code != http.StatusNotFound {
+ t.Errorf("%s: status = %d, want 404 — cert material must never transit the door", name, w.Code)
+ return
+ }
+ if strings.Contains(w.Body.String(), "BEGIN CERTIFICATE") || strings.Contains(w.Body.String(), "fake-mesh-shared-secret") {
+ t.Errorf("%s: response body carries seeded secret bytes", name)
+ }
+ got := shape{w.Code, fmt.Sprintf("%v", w.Header()), w.Body.String()}
+ if want == nil {
+ g := got
+ want, wantName = &g, name
+ return
+ }
+ if got != *want {
+ t.Errorf("%q answers %+v but %q answers %+v — cert refusal is distinguishable from an ordinary refusal (existence oracle)", name, got, wantName, *want)
+ }
+ }
+
+ for _, key := range certKeys {
+ check("GET "+key, doorDo(d, "GET", "/store/o/"+key, "", nil))
+ check("DELETE "+key, doorDo(d, "DELETE", "/store/o/"+key, "", nil))
+ check("PUT "+key, doorDo(d, "PUT", "/store/o/"+key, "x", map[string]string{"If-None-Match": "*"}))
+ }
+ // The listing verbs: a fleet box must never enumerate the cert prefix
+ // either, whether asking for objects (list) or child directories (dirs).
+ check("list prefix=control/certs/", doorDo(d, "GET", "/store/list?prefix=control/certs/", "", nil))
+ check("dirs prefix=control/certs/", doorDo(d, "GET", "/store/dirs?prefix=control/certs/", "", nil))
+
+ // The seeded keys must still be untouched in the backing store — a
+ // refused DELETE that quietly deleted anyway would be worse than a
+ // refused DELETE that didn't.
+ if _, _, err := store.Get(context.Background(), "control/certs/example.com"); err != nil {
+ t.Errorf("the refused DELETE removed control/certs/example.com anyway: %v", err)
+ }
+ if _, _, err := store.Get(context.Background(), "control/edge-mesh-key"); err != nil {
+ t.Errorf("the refused DELETE removed control/edge-mesh-key anyway: %v", err)
+ }
+}
+
// TestStoreDoorListScopeStripsOtherTenants: a listing is the easiest place to
// leak a neighbour, so every listing route is checked against a store that
// holds another account's and another fleet's objects.