mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-01 19:19:07 +02:00
Deleting an account left state behind that DeleteAccount's store associations don't reach. The Agent Network tables outlived the account, keeping its gateway domain claimed and its provider API keys stored. The proxies kept serving its gateway until they next resynced. Cloud-side state, such as managed proxy deployments, had no way to be cleaned up at all. Account deletion now runs registered hooks after the permission check and before any users or data are removed. A failing hook aborts the deletion. Agent Network registers one that tells the proxies to drop the account's gateway mappings. The account's settings, providers, policies, guardrails and budget rules are deleted in the account's transaction. Consumption counters, and the access logs of deleted accounts, are left to the background cleanup; usage records are kept.
255 lines
8.7 KiB
Go
255 lines
8.7 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/netbirdio/management-integrations/integrations"
|
|
|
|
"github.com/netbirdio/netbird/management/internals/modules/peers"
|
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain/manager"
|
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/proxy"
|
|
proxymanager "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/proxy/manager"
|
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/service"
|
|
nbreverseproxy "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/service/manager"
|
|
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
|
zonesManager "github.com/netbirdio/netbird/management/internals/modules/zones/manager"
|
|
"github.com/netbirdio/netbird/management/internals/modules/zones/records"
|
|
recordsManager "github.com/netbirdio/netbird/management/internals/modules/zones/records/manager"
|
|
"github.com/netbirdio/netbird/management/server"
|
|
"github.com/netbirdio/netbird/management/server/account"
|
|
"github.com/netbirdio/netbird/management/internals/modules/agentnetwork"
|
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
|
"github.com/netbirdio/netbird/management/server/groups"
|
|
"github.com/netbirdio/netbird/management/server/idp"
|
|
"github.com/netbirdio/netbird/management/server/networks"
|
|
"github.com/netbirdio/netbird/management/server/networks/resources"
|
|
"github.com/netbirdio/netbird/management/server/networks/routers"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
|
|
"github.com/netbirdio/netbird/management/server/permissions"
|
|
"github.com/netbirdio/netbird/management/server/settings"
|
|
"github.com/netbirdio/netbird/management/server/users"
|
|
)
|
|
|
|
const (
|
|
geolocationDisabledKey = "NB_DISABLE_GEOLOCATION"
|
|
)
|
|
|
|
func (s *BaseServer) GeoLocationManager() geolocation.Geolocation {
|
|
if os.Getenv(geolocationDisabledKey) == "true" {
|
|
log.Info("geolocation service is disabled, skipping initialization")
|
|
return nil
|
|
}
|
|
|
|
return Create(s, func() geolocation.Geolocation {
|
|
geo, err := geolocation.NewGeolocation(context.Background(), s.Config.Datadir, !s.disableGeoliteUpdate)
|
|
if err != nil {
|
|
log.Fatalf("could not initialize geolocation service: %v", err)
|
|
}
|
|
|
|
log.Infof("geolocation service has been initialized from %s", s.Config.Datadir)
|
|
|
|
return geo
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) PermissionsManager() permissions.Manager {
|
|
return Create(s, func() permissions.Manager {
|
|
return permissions.NewManager(s.Store())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) UsersManager() users.Manager {
|
|
return Create(s, func() users.Manager {
|
|
return users.NewManager(s.Store())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) SettingsManager() settings.Manager {
|
|
return Create(s, func() settings.Manager {
|
|
extraSettingsManager := integrations.NewManager(s.EventStore())
|
|
|
|
idpConfig := settings.IdpConfig{}
|
|
if s.Config.EmbeddedIdP != nil && s.Config.EmbeddedIdP.Enabled {
|
|
idpConfig.EmbeddedIdpEnabled = true
|
|
idpConfig.LocalAuthDisabled = s.Config.EmbeddedIdP.LocalAuthDisabled
|
|
}
|
|
|
|
return settings.NewManager(s.Store(), s.UsersManager(), extraSettingsManager, s.PermissionsManager(), idpConfig)
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) PeersManager() peers.Manager {
|
|
return Create(s, func() peers.Manager {
|
|
manager := peers.NewManager(s.Store(), s.PermissionsManager())
|
|
s.AfterInit(func(s *BaseServer) {
|
|
manager.SetNetworkMapController(s.NetworkMapController())
|
|
manager.SetIntegratedPeerValidator(s.IntegratedValidator())
|
|
manager.SetAccountManager(s.AccountManager())
|
|
})
|
|
return manager
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) AccountManager() account.Manager {
|
|
return Create(s, func() account.Manager {
|
|
accountManager, err := server.BuildManager(context.Background(), s.Config, s.Store(), s.NetworkMapController(), s.JobManager(), s.IdpManager(), s.mgmtSingleAccModeDomain, s.EventStore(), s.GeoLocationManager(), s.userDeleteFromIDPEnabled, s.IntegratedValidator(), s.Metrics(), s.ProxyController(), s.SettingsManager(), s.PermissionsManager(), s.Config.DisableDefaultPolicy, s.CacheStore())
|
|
if err != nil {
|
|
log.Fatalf("failed to create account service: %v", err)
|
|
}
|
|
|
|
s.AfterInit(func(s *BaseServer) {
|
|
accountManager.SetServiceManager(s.ServiceManager())
|
|
accountManager.AddAccountDeletionHook(s.AgentNetworkManager().RemoveAccountGateway)
|
|
})
|
|
|
|
return accountManager
|
|
})
|
|
}
|
|
|
|
func isMFAEnabledForAccount(accounts []*types.Account) bool {
|
|
if len(accounts) != 1 {
|
|
return false
|
|
}
|
|
|
|
settings := accounts[0].Settings
|
|
return settings != nil && settings.LocalMfaEnabled
|
|
}
|
|
|
|
func (s *BaseServer) IdpManager() idp.Manager {
|
|
return Create(s, func() idp.Manager {
|
|
// Use embedded IdP service if embedded Dex is configured and enabled.
|
|
// Legacy IdpManager won't be used anymore even if configured.
|
|
embeddedEnabled := s.Config.EmbeddedIdP != nil && s.Config.EmbeddedIdP.Enabled
|
|
if embeddedEnabled {
|
|
embeddedMgr, err := idp.NewEmbeddedIdPManager(context.Background(), s.Config.EmbeddedIdP, s.Metrics())
|
|
if err != nil {
|
|
log.Fatalf("failed to create embedded IDP service: %v", err)
|
|
}
|
|
|
|
if val := isMFAEnabledForAccount(s.Store().GetAllAccounts(context.Background())); val {
|
|
if err := embeddedMgr.SetMFAEnabled(context.Background(), val); err != nil {
|
|
log.Errorf("failed to set MFA enabled on embedded IDP: %v", err)
|
|
}
|
|
}
|
|
|
|
return embeddedMgr
|
|
}
|
|
|
|
// Fall back to external IdP service
|
|
if s.Config.IdpManagerConfig != nil {
|
|
idpManager, err := idp.NewManager(context.Background(), *s.Config.IdpManagerConfig, s.Metrics())
|
|
if err != nil {
|
|
log.Fatalf("failed to create IDP service: %v", err)
|
|
}
|
|
|
|
return idpManager
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// OAuthConfigProvider is only relevant when we have an embedded IdP service. Otherwise must be nil
|
|
func (s *BaseServer) OAuthConfigProvider() idp.OAuthConfigProvider {
|
|
if s.Config.EmbeddedIdP == nil || !s.Config.EmbeddedIdP.Enabled {
|
|
return nil
|
|
}
|
|
|
|
idpManager := s.IdpManager()
|
|
if idpManager == nil {
|
|
return nil
|
|
}
|
|
|
|
// Reuse the EmbeddedIdPManager instance from IdpManager
|
|
// EmbeddedIdPManager implements both idp.Manager and idp.OAuthConfigProvider
|
|
if provider, ok := idpManager.(idp.OAuthConfigProvider); ok {
|
|
return provider
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *BaseServer) GroupsManager() groups.Manager {
|
|
return Create(s, func() groups.Manager {
|
|
return groups.NewManager(s.Store(), s.PermissionsManager(), s.AccountManager())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) ResourcesManager() resources.Manager {
|
|
return Create(s, func() resources.Manager {
|
|
return resources.NewManager(s.Store(), s.PermissionsManager(), s.GroupsManager(), s.AccountManager(), s.ServiceManager())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) RoutesManager() routers.Manager {
|
|
return Create(s, func() routers.Manager {
|
|
return routers.NewManager(s.Store(), s.PermissionsManager(), s.AccountManager())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) NetworksManager() networks.Manager {
|
|
return Create(s, func() networks.Manager {
|
|
return networks.NewManager(s.Store(), s.PermissionsManager(), s.ResourcesManager(), s.RoutesManager(), s.AccountManager())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) AgentNetworkManager() agentnetwork.Manager {
|
|
return Create(s, func() agentnetwork.Manager {
|
|
mgr := agentnetwork.NewManager(
|
|
s.Store(),
|
|
s.PermissionsManager(),
|
|
s.AccountManager(),
|
|
s.ServiceProxyController(),
|
|
)
|
|
// Sweep expired agent-network access logs per account retention,
|
|
// reusing the reverse-proxy cleanup interval config.
|
|
mgr.StartAccessLogCleanup(
|
|
context.Background(),
|
|
s.Config.ReverseProxy.AccessLogCleanupIntervalHours,
|
|
)
|
|
return mgr
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) ZonesManager() zones.Manager {
|
|
return Create(s, func() zones.Manager {
|
|
return zonesManager.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager(), s.DNSDomain())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) RecordsManager() records.Manager {
|
|
return Create(s, func() records.Manager {
|
|
return recordsManager.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) ServiceManager() service.Manager {
|
|
return Create(s, func() service.Manager {
|
|
return nbreverseproxy.NewManager(s.Store(), s.AccountManager(), s.PermissionsManager(), s.ServiceProxyController(), s.ProxyManager(), s.ReverseProxyDomainManager())
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) ProxyManager() proxy.Manager {
|
|
return Create(s, func() proxy.Manager {
|
|
manager, err := proxymanager.NewManager(s.Store(), s.Metrics().GetMeter())
|
|
if err != nil {
|
|
log.Fatalf("failed to create proxy manager: %v", err)
|
|
}
|
|
return manager
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) ReverseProxyDomainManager() *manager.Manager {
|
|
return Create(s, func() *manager.Manager {
|
|
m := manager.NewManager(s.Store(), s.ProxyManager(), s.PermissionsManager(), s.AccountManager())
|
|
return &m
|
|
})
|
|
}
|
|
|
|
func (s *BaseServer) IsValidChildAccount(_ context.Context, _, _, _ string) bool {
|
|
return false
|
|
}
|