diff --git a/management/internals/modules/reverseproxy/domain/manager.go b/management/internals/modules/reverseproxy/domain/manager.go index 427a5386d..8d0498706 100644 --- a/management/internals/modules/reverseproxy/domain/manager.go +++ b/management/internals/modules/reverseproxy/domain/manager.go @@ -58,21 +58,31 @@ func NewManager(store store, proxyURLProvider proxyURLProvider) Manager { } func (m Manager) GetDomains(ctx context.Context, accountID string) ([]*Domain, error) { - account, err := m.store.GetAccount(ctx, accountID) - if err != nil { - return nil, fmt.Errorf("get account: %w", err) - } - free, err := m.store.ListFreeDomains(ctx, accountID) - if err != nil { - return nil, fmt.Errorf("list free domains: %w", err) - } domains, err := m.store.ListCustomDomains(ctx, accountID) if err != nil { return nil, fmt.Errorf("list custom domains: %w", err) } var ret []*Domain - // Populate all fields correctly for custom domains that are retrieved. + + // Add connected proxy clusters as free domains. + // The cluster address itself is the free domain base (e.g., "eu.proxy.netbird.io"). + allowList := m.proxyURLAllowList() + log.WithFields(log.Fields{ + "accountID": accountID, + "proxyAllowList": allowList, + }).Debug("getting domains with proxy allow list") + + for _, cluster := range allowList { + ret = append(ret, &Domain{ + Domain: cluster, + AccountID: accountID, + Type: TypeFree, + Validated: true, + }) + } + + // Add custom domains. for _, domain := range domains { ret = append(ret, &Domain{ ID: domain.ID, @@ -83,19 +93,6 @@ func (m Manager) GetDomains(ctx context.Context, accountID string) ([]*Domain, e }) } - // Prepend each free domain with the account nonce and then add it to the domain - // array to be returned. - // This account nonce is added to free domains to prevent users being able to - // query free domain usage across accounts and simplifies tracking free domain - // usage across accounts. - for _, name := range free { - ret = append(ret, &Domain{ - Domain: account.ReverseProxyFreeDomainNonce + "." + name, - AccountID: accountID, - Type: TypeFree, - Validated: true, - }) - } return ret, nil } @@ -240,8 +237,3 @@ func (m Manager) DeriveClusterFromDomain(ctx context.Context, domain string) (st return "", fmt.Errorf("domain %s does not match any available proxy cluster", domain) } - -// GetAvailableClusters returns a list of available proxy cluster addresses. -func (m Manager) GetAvailableClusters() []string { - return m.proxyURLAllowList() -} diff --git a/management/internals/modules/reverseproxy/manager/api.go b/management/internals/modules/reverseproxy/manager/api.go index 381f296e0..990f775b4 100644 --- a/management/internals/modules/reverseproxy/manager/api.go +++ b/management/internals/modules/reverseproxy/manager/api.go @@ -10,27 +10,20 @@ import ( "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs" accesslogsmanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs/manager" "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain" - nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/shared/management/http/api" "github.com/netbirdio/netbird/shared/management/http/util" "github.com/netbirdio/netbird/shared/management/status" ) -type clusterProvider interface { - GetAvailableClusters() []nbgrpc.ClusterInfo -} - type handler struct { - manager reverseproxy.Manager - clusterProvider clusterProvider + manager reverseproxy.Manager } // RegisterEndpoints registers all reverse proxy HTTP endpoints. -func RegisterEndpoints(manager reverseproxy.Manager, domainManager domain.Manager, accessLogsManager accesslogs.Manager, clusterProvider clusterProvider, router *mux.Router) { +func RegisterEndpoints(manager reverseproxy.Manager, domainManager domain.Manager, accessLogsManager accesslogs.Manager, router *mux.Router) { h := &handler{ - manager: manager, - clusterProvider: clusterProvider, + manager: manager, } domainRouter := router.PathPrefix("/reverse-proxies").Subrouter() @@ -40,7 +33,6 @@ func RegisterEndpoints(manager reverseproxy.Manager, domainManager domain.Manage router.HandleFunc("/reverse-proxies", h.getAllReverseProxies).Methods("GET", "OPTIONS") router.HandleFunc("/reverse-proxies", h.createReverseProxy).Methods("POST", "OPTIONS") - router.HandleFunc("/reverse-proxies/clusters", h.getAvailableClusters).Methods("GET", "OPTIONS") router.HandleFunc("/reverse-proxies/{proxyId}", h.getReverseProxy).Methods("GET", "OPTIONS") router.HandleFunc("/reverse-proxies/{proxyId}", h.updateReverseProxy).Methods("PUT", "OPTIONS") router.HandleFunc("/reverse-proxies/{proxyId}", h.deleteReverseProxy).Methods("DELETE", "OPTIONS") @@ -176,22 +168,3 @@ func (h *handler) deleteReverseProxy(w http.ResponseWriter, r *http.Request) { util.WriteJSONObject(r.Context(), w, util.EmptyObject{}) } - -func (h *handler) getAvailableClusters(w http.ResponseWriter, r *http.Request) { - _, err := nbcontext.GetUserAuthFromContext(r.Context()) - if err != nil { - util.WriteError(r.Context(), err, w) - return - } - - clusters := h.clusterProvider.GetAvailableClusters() - apiClusters := make([]api.ProxyCluster, 0, len(clusters)) - for _, c := range clusters { - apiClusters = append(apiClusters, api.ProxyCluster{ - Address: c.Address, - ConnectedProxies: c.ConnectedProxies, - }) - } - - util.WriteJSONObject(r.Context(), w, apiClusters) -} diff --git a/management/internals/server/boot.go b/management/internals/server/boot.go index 3b25ee7ae..de86ad22a 100644 --- a/management/internals/server/boot.go +++ b/management/internals/server/boot.go @@ -94,7 +94,7 @@ func (s *BaseServer) EventStore() activity.Store { func (s *BaseServer) APIHandler() http.Handler { return Create(s, func() http.Handler { - httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.ZonesManager(), s.RecordsManager(), s.NetworkMapController(), s.IdpManager(), s.ReverseProxyManager(), s.ReverseProxyDomainManager(), s.AccessLogsManager(), s.ReverseProxyGRPCServer()) + httpAPIHandler, err := nbhttp.NewAPIHandler(context.Background(), s.AccountManager(), s.NetworksManager(), s.ResourcesManager(), s.RoutesManager(), s.GroupsManager(), s.GeoLocationManager(), s.AuthManager(), s.Metrics(), s.IntegratedValidator(), s.ProxyController(), s.PermissionsManager(), s.PeersManager(), s.SettingsManager(), s.ZonesManager(), s.RecordsManager(), s.NetworkMapController(), s.IdpManager(), s.ReverseProxyManager(), s.ReverseProxyDomainManager(), s.AccessLogsManager()) if err != nil { log.Fatalf("failed to create API handler: %v", err) } diff --git a/management/internals/shared/grpc/proxy.go b/management/internals/shared/grpc/proxy.go index a97860528..51d2f8499 100644 --- a/management/internals/shared/grpc/proxy.go +++ b/management/internals/shared/grpc/proxy.go @@ -112,13 +112,18 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest return status.Errorf(codes.InvalidArgument, "proxy_id is required") } - log.Infof("Proxy %s connected (version: %s, started: %s)", - proxyID, req.GetVersion(), req.GetStartedAt().AsTime()) + proxyAddress := req.GetAddress() + log.WithFields(log.Fields{ + "proxy_id": proxyID, + "address": proxyAddress, + "version": req.GetVersion(), + "started": req.GetStartedAt().AsTime(), + }).Info("Proxy connected") connCtx, cancel := context.WithCancel(ctx) conn := &proxyConnection{ proxyID: proxyID, - address: req.GetAddress(), + address: proxyAddress, stream: stream, sendChan: make(chan *proto.ProxyMapping, 100), ctx: connCtx, @@ -127,6 +132,12 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest s.connectedProxies.Store(proxyID, conn) s.addToCluster(conn.address, proxyID) + log.WithFields(log.Fields{ + "proxy_id": proxyID, + "address": proxyAddress, + "cluster_addr": extractClusterAddr(proxyAddress), + "total_proxies": len(s.GetConnectedProxies()), + }).Info("Proxy registered in cluster") defer func() { s.connectedProxies.Delete(proxyID) s.removeFromCluster(conn.address, proxyID) @@ -306,14 +317,25 @@ func (s *ProxyServiceServer) GetConnectedProxies() []string { func (s *ProxyServiceServer) GetConnectedProxyURLs() []string { seenUrls := make(map[string]struct{}) var urls []string + var proxyCount int s.connectedProxies.Range(func(key, value interface{}) bool { + proxyCount++ conn := value.(*proxyConnection) + log.WithFields(log.Fields{ + "proxy_id": conn.proxyID, + "address": conn.address, + }).Debug("checking connected proxy for URL") if _, seen := seenUrls[conn.address]; conn.address != "" && !seen { seenUrls[conn.address] = struct{}{} urls = append(urls, conn.address) } return true }) + log.WithFields(log.Fields{ + "total_proxies": proxyCount, + "unique_urls": len(urls), + "connected_urls": urls, + }).Debug("GetConnectedProxyURLs result") return urls } diff --git a/management/server/http/handler.go b/management/server/http/handler.go index 92f349160..011055dd4 100644 --- a/management/server/http/handler.go +++ b/management/server/http/handler.go @@ -16,7 +16,6 @@ import ( "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs" "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain" reverseproxymanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/manager" - nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc" idpmanager "github.com/netbirdio/netbird/management/server/idp" "github.com/netbirdio/management-integrations/integrations" @@ -64,13 +63,8 @@ const ( rateLimitingRPMKey = "NB_API_RATE_LIMITING_RPM" ) -// clusterProvider provides access to available proxy clusters. -type clusterProvider interface { - GetAvailableClusters() []nbgrpc.ClusterInfo -} - // NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints. -func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, zManager zones.Manager, rManager records.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager, reverseProxyManager reverseproxy.Manager, reverseProxyDomainManager *domain.Manager, reverseProxyAccessLogsManager accesslogs.Manager, proxyClusterProvider clusterProvider) (http.Handler, error) { +func NewAPIHandler(ctx context.Context, accountManager account.Manager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager nbgroups.Manager, LocationManager geolocation.Geolocation, authManager auth.Manager, appMetrics telemetry.AppMetrics, integratedValidator integrated_validator.IntegratedValidator, proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, settingsManager settings.Manager, zManager zones.Manager, rManager records.Manager, networkMapController network_map.Controller, idpManager idpmanager.Manager, reverseProxyManager reverseproxy.Manager, reverseProxyDomainManager *domain.Manager, reverseProxyAccessLogsManager accesslogs.Manager) (http.Handler, error) { // Register bypass paths for unauthenticated endpoints if err := bypass.AddBypassPath("/api/instance"); err != nil { @@ -167,7 +161,7 @@ func NewAPIHandler(ctx context.Context, accountManager account.Manager, networks instance.AddEndpoints(instanceManager, router) instance.AddVersionEndpoint(instanceManager, router) if reverseProxyManager != nil && reverseProxyDomainManager != nil { - reverseproxymanager.RegisterEndpoints(reverseProxyManager, *reverseProxyDomainManager, reverseProxyAccessLogsManager, proxyClusterProvider, router) + reverseproxymanager.RegisterEndpoints(reverseProxyManager, *reverseProxyDomainManager, reverseProxyAccessLogsManager, router) } // Mount embedded IdP handler at /oauth2 path if configured diff --git a/management/server/http/testing/testing_tools/channel/channel.go b/management/server/http/testing/testing_tools/channel/channel.go index bdc68e85f..315d1222f 100644 --- a/management/server/http/testing/testing_tools/channel/channel.go +++ b/management/server/http/testing/testing_tools/channel/channel.go @@ -102,7 +102,7 @@ func BuildApiBlackBoxWithDBState(t testing_tools.TB, sqlFile string, expectedPee customZonesManager := zonesManager.NewManager(store, am, permissionsManager, "") zoneRecordsManager := recordsManager.NewManager(store, am, permissionsManager) - apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, nil, nil, nil, nil) + apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, nil, nil, nil) if err != nil { t.Fatalf("Failed to create API handler: %v", err) }