carlos / platform Public

domains: cert-expiry wildcard fallback covers static + delegated parents

hostCertExpiry's fallback now strips a generic one label off host to find
its covering wildcard-<parent>.pem, instead of gating on the appsDomain
shape via wildcardParent. Closes the pre-existing hole where a host under
a static parent (go.tito.io) or a delegated customer domain (woodstar.app)
reported certless while the edge served a valid wildcard. wildcardParent
existed solely to compute the parent, so it's deleted along with
TestWildcardParent; the apex-non-match and appsDomain-derived behaviors
are covered by TestCertExpiryWildcardFallback.
Paul Campbell 2bab40f6c1bf54e7cda49dc2d6b7db3739a31d0c parent 3e42910
2 files changed, +35 −51
  • internal/domains/reconcile.go +21 −32
  • internal/domains/reconcile_internal_test.go +14 −19
diff --git a/internal/domains/reconcile.go b/internal/domains/reconcile.go
index c5d4f72f5..235b09a5e 100644
--- a/internal/domains/reconcile.go
+++ b/internal/domains/reconcile.go
@@ -721,42 +721,31 @@ func mintedRoute(host, app, account string, src registry.Route) registry.Route {
return rt
}
-// wildcardParent returns the parent domain whose per-account wildcard cert
-// would cover host — host exactly two labels under appsDomain
-// (<app>.<acct>.<appsDomain>) → <acct>.<appsDomain> — or "" when no wildcard
-// could cover it (canary depth, a parent apex, a foreign domain, no apps
-// domain configured).
-func wildcardParent(host, appsDomain string) string {
- if appsDomain == "" {
- return ""
- }
- suffix := "." + strings.ToLower(appsDomain)
- rest, ok := strings.CutSuffix(strings.ToLower(host), suffix)
- if !ok {
- return ""
- }
- if labels := strings.Split(rest, "."); len(labels) == 2 {
- return labels[1] + suffix
- }
- return ""
-}
-
// hostCertExpiry resolves host's cert expiry from the acme cache dir as the
-// LATER of the per-host autocert entry and the covering per-account
-// wildcard's PEM (wildcard-<parent>.pem). Two reasons a bare per-host lookup
-// isn't enough: a wildcard-covered host never gets a per-host entry at all
-// (without the wildcard fallback status would call it certless forever), and
-// a host GRANDFATHERED onto a per-host cert from before its wildcard existed
-// keeps that file on disk forever — autocert stops renewing it once the
-// wildcard starts serving the host, so the stale file's expiry would
-// shadow the wildcard's and status would cry "expiring" over a cert the edge
-// no longer serves. The edge always serves whichever cert is actually valid,
-// so the max of the two is the only truthful answer. 0 = unknown, never a
-// guess.
+// LATER of the per-host autocert entry and the covering wildcard's PEM
+// (wildcard-<parent>.pem). Two reasons a bare per-host lookup isn't enough: a
+// wildcard-covered host never gets a per-host entry at all (without the
+// wildcard fallback status would call it certless forever), and a host
+// GRANDFATHERED onto a per-host cert from before its wildcard existed keeps
+// that file on disk forever — autocert stops renewing it once the wildcard
+// starts serving the host, so the stale file's expiry would shadow the
+// wildcard's and status would cry "expiring" over a cert the edge no longer
+// serves. The edge always serves whichever cert is actually valid, so the max
+// of the two is the only truthful answer. 0 = unknown, never a guess.
+//
+// The wildcard parent is host's generic one-label strip, not an
+// appsDomain-shaped derivation (appsDomain is otherwise unused here): one
+// label folds into "*.", so any host's covering wildcard is its one-label
+// parent's, whether that parent is an <acct>.<apps-domain> derivation, a
+// static domain (go.tito.io), or a delegated customer domain (woodstar.app).
+// Trying the read is cheaper than knowing which — a miss is a miss. An apex
+// host's own strip lands one label short of the parent that names ITS
+// covering wildcard file, so the apex never matches its own wildcard.
func hostCertExpiry(acmeDir, host, appsDomain string) int64 {
perHost := certExpiry(filepath.Join(acmeDir, host))
wildcard := int64(0)
- if parent := wildcardParent(host, appsDomain); parent != "" {
+ if i := strings.IndexByte(host, '.'); i > 0 {
+ parent := strings.ToLower(host[i+1:])
wildcard = certExpiry(filepath.Join(acmeDir, "wildcard-"+parent+".pem"))
}
if wildcard > perHost {
diff --git a/internal/domains/reconcile_internal_test.go b/internal/domains/reconcile_internal_test.go
index a354f3d1c..4075fd2a9 100644
--- a/internal/domains/reconcile_internal_test.go
+++ b/internal/domains/reconcile_internal_test.go
@@ -1,6 +1,6 @@
package domains
-// Internal-package tests for wildcardParent/hostCertExpiry: reconcile_test.go
+// Internal-package tests for hostCertExpiry: reconcile_test.go
// is package domains_test and cannot reach these unexported helpers, so this
// file follows slugname_test.go's existing convention of a same-package test
// file living alongside it.
@@ -58,24 +58,6 @@ func writeWildcardPEM(t *testing.T, path, name string, notAfter time.Time) {
}
}
-func TestWildcardParent(t *testing.T) {
- cases := []struct {
- host, appsDomain, want string
- }{
- {"kass.abs.oncarlos.com", "oncarlos.com", "abs.oncarlos.com"},
- {"canary.kass.abs.oncarlos.com", "oncarlos.com", ""}, // canary depth: not covered
- {"abs.oncarlos.com", "oncarlos.com", ""}, // apex of a parent
- {"custom.example.com", "oncarlos.com", ""}, // foreign domain
- {"kass.abs.oncarlos.com", "", ""}, // no apps domain configured
- {"Kass.ABS.oncarlos.com", "oncarlos.com", "abs.oncarlos.com"},
- }
- for _, c := range cases {
- if got := wildcardParent(c.host, c.appsDomain); got != c.want {
- t.Errorf("wildcardParent(%q, %q) = %q, want %q", c.host, c.appsDomain, got, c.want)
- }
- }
-}
-
// A wildcard-covered host has no per-host acme cache entry — its expiry must
// come from the covering wildcard-<parent>.pem instead of reporting 0
// (certless) forever.
@@ -113,6 +95,19 @@ func TestCertExpiryWildcardFallback(t *testing.T) {
if got := hostCertExpiry(dir, "kass.zzz.oncarlos.com", "oncarlos.com"); got != 0 {
t.Fatalf("hostCertExpiry with no files = %d, want 0", got)
}
+
+ // A host under a NON-apps-domain wildcard parent (static go.tito.io /
+ // delegated woodstar.app): the fallback must strip one label and try
+ // the parent's wildcard PEM, not require the apps-domain shape.
+ delegatedNotAfter := time.Now().Add(60 * 24 * time.Hour).Truncate(time.Second)
+ writeWildcardPEM(t, filepath.Join(dir, "wildcard-woodstar.app.pem"), "*.woodstar.app", delegatedNotAfter)
+ if got := hostCertExpiry(dir, "paul.woodstar.app", "oncarlos.com"); got != delegatedNotAfter.Unix() {
+ t.Fatalf("delegated-parent fallback = %d, want %d", got, delegatedNotAfter.Unix())
+ }
+ // The apex itself must NOT match its own wildcard.
+ if got := hostCertExpiry(dir, "woodstar.app", "oncarlos.com"); got != 0 {
+ t.Fatalf("apex must not claim the wildcard: got %d, want 0", got)
+ }
}
// TestMintedRouteCarriesRegionAndDropsSocketWhenFleetPlaced: a minted