[management] validate the proxy cluster an agent network bootstraps onto

The agent network gateway service is synthesised as private: agents reach
it over the WireGuard tunnel and are authorised by ValidateTunnelPeer
against the enabled policies' source groups, and its only target is the
cluster itself with DirectUpstream. Only a proxy running embedded in a
netbird client can serve that, which management already reports per
cluster as the `private` capability.

CreateSettings accepted any hostname as proxy_address, so a labeled
bootstrap could pin the account to a cluster that cannot serve its
gateway — another account's BYOP cluster, or one whose proxies are all
centralised. The endpoint assigned at bootstrap is immutable, so the
account is then stuck with a dead gateway until someone deletes and
re-bootstraps the settings row.

Validate the cluster before allocating an endpoint beneath it: a cluster
whose live proxies have reported their capabilities must be one the
account may route through and must be private-capable. A cluster nothing
is connected to is left alone, so claiming an address ahead of the
proxy's first connection keeps working — the same address-first order the
dedicated (self-addressed) path documents, and the one the e2e suite and
self-hosted setups follow.

The e2e coverage drives the real thing: one combined server and two
proxies in the same cluster — a centralised one that makes the cluster
live but unusable, then an embedded one that makes it usable — so both
the refusal and the acceptance are exercised against the same account and
cluster address, with the domains endpoint (the list the dashboard picks
from) as the barrier between starting a proxy and asserting on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-09-01 22:56:07 +00:00
parent 11733fd718
commit 083906b84d
6 changed files with 382 additions and 0 deletions
@@ -89,6 +89,7 @@ func TestAgentNetwork_UpdateSettings_PreservesImmutableAndTogglesCollection(t *t
// Bootstrap is an explicit settings create; providers have no settings
// side effects anymore.
seedEmbeddedProxyCluster(t, am.Store, clusterAddr)
before, err := mgr.CreateSettings(ctx, adminUserID, agenttypes.DefaultSettings(accountID), clusterAddr, "")
require.NoError(t, err, "CreateSettings must bootstrap the row")
require.Equal(t, clusterAddr, before.ProxyAddress, "proxy address pinned at bootstrap")