feat: Fix HAProxy ACL ordering + Subdomains field
Rewrite HAProxy config generation with correct ACL ordering: 1. L7 HTTP exact matches first (central, wild-cloud app) 2. L4 exact matches (payne.io, civilsociety.dev) 3. L4 wildcard matches (*.cloud.payne.io) — only when subdomains:true 4. Default → L7 termination Key changes: - InstanceRoute: removed ExtraDomains, added Subdomains bool - GenerateOpts: removed CentralDomain (Central is now just another HTTPRoute injected by reconciliation), renamed WildcardCert→CertsDir - Central's domain comes from config, injected as HTTPRoute with the actual running port (no more hardcoded 5055) - Added API.SetPort() so reconciliation knows the running port - subdomains:false → exact match only (no *.domain shadowing) New tests: TestGenerate_WithSubdomains, TestGenerate_ACLOrdering (verifies L7 exact matches come before L4 wildcards). Fixes: BUG 1 (central routing to wrong port), BUG 2 (wild-cloud getting traefik cert), BUG 3 (*.payne.io too broad). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,19 +55,18 @@ func (api *API) reconcileNetworking() {
|
||||
}
|
||||
}
|
||||
|
||||
// Determine central domain for HAProxy — only if its cert exists
|
||||
centralDomain := ""
|
||||
// Inject Central's own domain as an HTTP route (from config, not registration).
|
||||
// Central is just another L7 service from HAProxy's perspective.
|
||||
if d := globalCfg.Cloud.Central.Domain; d != "" {
|
||||
if _, err := os.Stat(certbot.HAProxyCertPath(d)); err == nil {
|
||||
centralDomain = d
|
||||
} else {
|
||||
slog.Debug("reconcile: skipping central domain in HAProxy (no cert)", "domain", d)
|
||||
}
|
||||
centralPort := api.getRunningPort()
|
||||
httpRoutes = append([]haproxy.HTTPRoute{{
|
||||
Name: "wild-central",
|
||||
Domain: d,
|
||||
Backend: fmt.Sprintf("127.0.0.1:%d", centralPort),
|
||||
}}, httpRoutes...)
|
||||
}
|
||||
|
||||
// Only include L7 HTTP routes for services that have a cert.
|
||||
// HAProxy uses a cert directory — each service needs its own <domain>.pem
|
||||
// or be covered by a wildcard cert in the same directory.
|
||||
certsDir := "/etc/haproxy/certs/"
|
||||
var activeHTTPRoutes []haproxy.HTTPRoute
|
||||
for _, route := range httpRoutes {
|
||||
@@ -80,9 +79,8 @@ func (api *API) reconcileNetworking() {
|
||||
|
||||
// Generate and write HAProxy config
|
||||
haproxyCfg := api.haproxy.GenerateWithOpts(instanceRoutes, nil, haproxy.GenerateOpts{
|
||||
CentralDomain: centralDomain,
|
||||
HTTPRoutes: activeHTTPRoutes,
|
||||
WildcardCert: certsDir,
|
||||
HTTPRoutes: activeHTTPRoutes,
|
||||
CertsDir: certsDir,
|
||||
})
|
||||
|
||||
if err := api.haproxy.WriteConfig(haproxyCfg); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user