route-proxy: serve a route that names only its internal host
Since ADR 0138 an endpoint that reaches only the private network gets an internal-name and no name, and the proxy skipped it as naming nothing, so every internal-only module was unreachable by name (novox/hq issue 191).
This commit is contained in:
@@ -716,6 +716,12 @@ func boolByte(b bool) byte {
|
||||
// routesFrom reads what the mesh wrote and turns it into host → the rules for that host, and
|
||||
// which of those hosts is a public name — the second is `name`, ACME-eligible; a host reached
|
||||
// only through `internal-name` never appears there.
|
||||
//
|
||||
// **A route may carry either name, or both** (novox/hq ADR 0138). How far an endpoint reaches
|
||||
// decides which names the mesh composes, so an endpoint that reaches only the private network
|
||||
// arrives with an `internal-name` and no `name`. That is a whole route, not a malformed one: it is
|
||||
// served under its internal name and certified by the internal authority. Only a route with
|
||||
// neither name has nothing to be served under (novox/hq issue 191).
|
||||
func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -730,12 +736,18 @@ func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
public := map[string]bool{}
|
||||
for _, c := range said.Given {
|
||||
name, _ := c.Values["name"].(string)
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(name)
|
||||
internal, _ := c.Values["internal-name"].(string)
|
||||
internal = strings.TrimSpace(internal)
|
||||
if name == "" && internal == "" {
|
||||
log.Printf("%s on %s asked for a route and named nothing; skipped", c.From, c.Node)
|
||||
continue
|
||||
}
|
||||
host := strings.ToLower(name)
|
||||
public[host] = true
|
||||
// What the route is called in a log line: its public name when it has one.
|
||||
called := name
|
||||
if called == "" {
|
||||
called = internal
|
||||
}
|
||||
|
||||
made := rule{path: asPath(c.Values["path"])}
|
||||
if p, ok := asWhole(c.Values["priority"]); ok {
|
||||
@@ -752,7 +764,7 @@ func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
if looksLikeACredential(named) {
|
||||
log.Printf("%s on %s declared route %q with a credential in the declaration rather "+
|
||||
"than the name of a secret; the whole route is refused (novox/hq ADR 0108)",
|
||||
c.From, c.Node, name)
|
||||
c.From, c.Node, called)
|
||||
continue
|
||||
}
|
||||
users, err := usersFrom(named)
|
||||
@@ -770,7 +782,7 @@ func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
port, ok := asPort(c.Values["port"])
|
||||
if !ok {
|
||||
log.Printf("%s on %s asked for route %q and gave no usable port; skipped",
|
||||
c.From, c.Node, name)
|
||||
c.From, c.Node, called)
|
||||
continue
|
||||
}
|
||||
// Where the mesh says that machine is. Empty means it is this one — a workload beside
|
||||
@@ -791,7 +803,7 @@ func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
}
|
||||
if scheme != "http" && scheme != "https" {
|
||||
log.Printf("%s on %s asked for route %q with scheme %q, which is neither http "+
|
||||
"nor https; skipped", c.From, c.Node, name, scheme)
|
||||
"nor https; skipped", c.From, c.Node, called, scheme)
|
||||
continue
|
||||
}
|
||||
made.insecure, _ = c.Values["insecure"].(bool)
|
||||
@@ -802,7 +814,7 @@ func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
bytes, whole := asWhole(asked)
|
||||
if !whole || bytes <= 0 {
|
||||
log.Printf("%s on %s asked for route %q with a max-request-body of %v, which is "+
|
||||
"not a whole positive number of bytes; skipped", c.From, c.Node, name, asked)
|
||||
"not a whole positive number of bytes; skipped", c.From, c.Node, called, asked)
|
||||
continue
|
||||
}
|
||||
made.maxRequestBody = int64(bytes)
|
||||
@@ -810,15 +822,20 @@ func routesFrom(path string) (map[string][]rule, map[string]bool, error) {
|
||||
made.target = fmt.Sprintf("%s://%s:%d", scheme, at, port)
|
||||
}
|
||||
|
||||
out[host] = append(out[host], made)
|
||||
if name != "" {
|
||||
host := strings.ToLower(name)
|
||||
out[host] = append(out[host], made)
|
||||
public[host] = true
|
||||
}
|
||||
|
||||
// The internal-network alias, the same rule under a second host — a predecessor proxy
|
||||
// The internal-network name, the same rule under a second host — a predecessor proxy
|
||||
// answered both for one route, as a convenience (reaching a service over the VPN without a
|
||||
// public TLS round trip), not as an access boundary; composing it here restores exactly
|
||||
// that, nothing more. Absent whenever the node composed no internal name (novox/hq ADR
|
||||
// 0056's internalDomain half) — the same "nothing to join a label to" case the public name
|
||||
// already has.
|
||||
if internal, _ := c.Values["internal-name"].(string); strings.TrimSpace(internal) != "" {
|
||||
// already has. And the only name, when the endpoint reaches no further than the private
|
||||
// network.
|
||||
if internal != "" {
|
||||
out[strings.ToLower(internal)] = append(out[strings.ToLower(internal)], made)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user