diff --git a/combined/cmd/config.go b/combined/cmd/config.go index 4cfc5069d..7181f12e2 100644 --- a/combined/cmd/config.go +++ b/combined/cmd/config.go @@ -116,20 +116,21 @@ type SignalConfig struct { // ManagementConfig contains management service settings type ManagementConfig struct { - Enabled bool `yaml:"enabled"` - LogLevel string `yaml:"logLevel"` - DataDir string `yaml:"dataDir"` - DnsDomain string `yaml:"dnsDomain"` - DisableAnonymousMetrics bool `yaml:"disableAnonymousMetrics"` - DisableGeoliteUpdate bool `yaml:"disableGeoliteUpdate"` - DisableDefaultPolicy bool `yaml:"disableDefaultPolicy"` - Auth AuthConfig `yaml:"auth"` - Stuns []HostConfig `yaml:"stuns"` - Relays RelaysConfig `yaml:"relays"` - SignalURI string `yaml:"signalUri"` - Store StoreConfig `yaml:"store"` - ReverseProxy ReverseProxyConfig `yaml:"reverseProxy"` - SupportedSyncMessageVersions []string `yaml:"supportedSyncMessageVersions"` + Enabled bool `yaml:"enabled"` + LogLevel string `yaml:"logLevel"` + DataDir string `yaml:"dataDir"` + DnsDomain string `yaml:"dnsDomain"` + DisableAnonymousMetrics bool `yaml:"disableAnonymousMetrics"` + DisableGeoliteUpdate bool `yaml:"disableGeoliteUpdate"` + DisableDefaultPolicy bool `yaml:"disableDefaultPolicy"` + Auth AuthConfig `yaml:"auth"` + Stuns []HostConfig `yaml:"stuns"` + Relays RelaysConfig `yaml:"relays"` + SignalURI string `yaml:"signalUri"` + Store StoreConfig `yaml:"store"` + ReverseProxy ReverseProxyConfig `yaml:"reverseProxy"` + SupportedSyncMessageVersions []string `yaml:"supportedSyncMessageVersions"` + PerAccountSupportedSyncMessageVersions map[string][]string `yaml:"perAccountSupportedSyncMessageVersions"` } // AuthConfig contains authentication/identity provider settings diff --git a/combined/cmd/root.go b/combined/cmd/root.go index 499f2f644..e350c29e9 100644 --- a/combined/cmd/root.go +++ b/combined/cmd/root.go @@ -510,6 +510,12 @@ func createManagementServer(cfg *CombinedConfig, mgmtConfig *nbconfig.Config) (m return nil, err } + for accountId, versions := range cfg.Management.PerAccountSupportedSyncMessageVersions { + if err := syncgrpc.ValidateSyncMessageVersions(versions); err != nil { + return nil, fmt.Errorf("unrecognized sync message version in perAccountSupportedSyncMessageVersions for account %s %w", accountId, err) + } + } + mgmtSrv := newServer( &mgmtServer.Config{ NbConfig: mgmtConfig, diff --git a/management/cmd/management.go b/management/cmd/management.go index 4703a4078..e885109c9 100644 --- a/management/cmd/management.go +++ b/management/cmd/management.go @@ -159,6 +159,13 @@ func LoadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi return nil, err } + for account, versions := range loadedConfig.PerAccountSupportedSyncMessageVersions { + err := grpc.ValidateSyncMessageVersions(versions) + if err != nil { + return nil, fmt.Errorf("unrecognized sync message version for account %s, %w", account, err) + } + } + // Apply EmbeddedIdP config to HttpConfig if embedded IdP is enabled err = ApplyEmbeddedIdPConfig(ctx, loadedConfig) if err != nil { diff --git a/management/internals/controllers/network_map/controller/controller.go b/management/internals/controllers/network_map/controller/controller.go index b38a43d30..adc8855d5 100644 --- a/management/internals/controllers/network_map/controller/controller.go +++ b/management/internals/controllers/network_map/controller/controller.go @@ -58,6 +58,8 @@ type Controller struct { integratedPeerValidator integrated_validator.IntegratedValidator serverSupportedSyncMessageVersions []grpc.SyncMessageVersion + + perAccountServerSupportedSyncMessageVersions map[string][]grpc.SyncMessageVersion } type bufferUpdate struct { @@ -92,9 +94,10 @@ func NewController(ctx context.Context, store store.Store, metrics telemetry.App dnsDomain: dnsDomain, config: config, - proxyController: proxyController, - EphemeralPeersManager: ephemeralPeersManager, - serverSupportedSyncMessageVersions: grpc.SyncMessageVersionsFromString(config.SupportedSyncMessageVersions), + proxyController: proxyController, + EphemeralPeersManager: ephemeralPeersManager, + serverSupportedSyncMessageVersions: grpc.SyncMessageVersionsFromString(config.SupportedSyncMessageVersions), + perAccountServerSupportedSyncMessageVersions: grpc.SyncMessageVersionsFromMap(config.PerAccountSupportedSyncMessageVersions), } } @@ -230,7 +233,7 @@ func (c *Controller) sendUpdateAccountPeers(ctx context.Context, accountID strin var update *proto.SyncResponse commonSyncMessageVersions := grpc.CommonSyncMessageVersions( - c.serverSupportedSyncMessageVersions, + c.perAccountOrGlobalSupportedSyncMessageVersions(accountID), grpc.SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities)) if commonSyncMessageVersions[0] == grpc.ComponentNetworkMap { @@ -275,6 +278,13 @@ func (c *Controller) sendUpdateAccountPeers(ctx context.Context, accountID strin return nil } +func (c *Controller) perAccountOrGlobalSupportedSyncMessageVersions(accountId string) []grpc.SyncMessageVersion { + if perAccount, ok := c.perAccountServerSupportedSyncMessageVersions[accountId]; ok { + return perAccount + } + return c.serverSupportedSyncMessageVersions +} + // UpdatePeers updates all peers that belong to an account. // Should be called when changes have to be synced to peers. func (c *Controller) UpdateAccountPeers(ctx context.Context, accountID string, reason types.UpdateReason) error { @@ -381,7 +391,7 @@ func (c *Controller) sendUpdateForAffectedPeers(ctx context.Context, accountID s var update *proto.SyncResponse commonSyncMessageVersions := grpc.CommonSyncMessageVersions( - c.serverSupportedSyncMessageVersions, + c.perAccountOrGlobalSupportedSyncMessageVersions(accountID), grpc.SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities)) if commonSyncMessageVersions[0] == grpc.ComponentNetworkMap { @@ -508,7 +518,7 @@ func (c *Controller) UpdateAccountPeer(ctx context.Context, accountId string, pe var update *proto.SyncResponse commonSyncMessageVersions := grpc.CommonSyncMessageVersions( - c.serverSupportedSyncMessageVersions, + c.perAccountOrGlobalSupportedSyncMessageVersions(accountId), grpc.SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities)) if commonSyncMessageVersions[0] == grpc.ComponentNetworkMap { diff --git a/management/internals/server/config/config.go b/management/internals/server/config/config.go index dc8dac1ba..c2c45941d 100644 --- a/management/internals/server/config/config.go +++ b/management/internals/server/config/config.go @@ -63,6 +63,8 @@ type Config struct { EmbeddedIdP *idp.EmbeddedIdPConfig SupportedSyncMessageVersions []string + + PerAccountSupportedSyncMessageVersions map[string][]string } // GetAuthAudiences returns the audience from the http config and device authorization flow config diff --git a/management/internals/shared/grpc/server.go b/management/internals/shared/grpc/server.go index 92387aaa1..7a6a13bec 100644 --- a/management/internals/shared/grpc/server.go +++ b/management/internals/shared/grpc/server.go @@ -86,8 +86,6 @@ type Server struct { reverseProxyManager rpservice.Manager reverseProxyMu sync.RWMutex - - supportedSyncMessageVersions []SyncMessageVersion } // NewServer creates a new Management server @@ -132,8 +130,6 @@ func NewServer( } } - syncMessageVersions := SyncMessageVersionsFromString(config.SupportedSyncMessageVersions) - return &Server{ jobManager: jobManager, accountManager: accountManager, @@ -153,8 +149,6 @@ func NewServer( syncLim: syncLim, syncLimEnabled: syncLimEnabled, - - supportedSyncMessageVersions: syncMessageVersions, }, nil } @@ -1028,7 +1022,7 @@ func (s *Server) sendInitialSync(ctx context.Context, peerKey wgtypes.Key, peer var plainResp *proto.SyncResponse commonSyncMessageVersions := CommonSyncMessageVersions( - SyncMessageVersionsFromString(s.config.SupportedSyncMessageVersions), + SyncMessageVersionsFromString(s.perAccountOrGlobalSyncMessageVersions(peer.AccountID)), SyncMessageVersionsFromProtoEnums(peer.Meta.Capabilities)) if commonSyncMessageVersions[0] == ComponentNetworkMap { @@ -1077,6 +1071,13 @@ func (s *Server) sendInitialSync(ctx context.Context, peerKey wgtypes.Key, peer return nil } +func (s *Server) perAccountOrGlobalSyncMessageVersions(accountId string) []string { + if versions, ok := s.config.PerAccountSupportedSyncMessageVersions[accountId]; ok { + return versions + } + return s.config.SupportedSyncMessageVersions +} + // GetDeviceAuthorizationFlow returns a device authorization flow information // This is used for initiating an Oauth 2 device authorization grant flow // which will be used by our clients to Login diff --git a/management/internals/shared/grpc/sync_message_versions.go b/management/internals/shared/grpc/sync_message_versions.go index 026767a55..bc87dd995 100644 --- a/management/internals/shared/grpc/sync_message_versions.go +++ b/management/internals/shared/grpc/sync_message_versions.go @@ -74,6 +74,27 @@ func SyncMessageVersionsFromString(toconvert []string) []SyncMessageVersion { return toret } +// convert per-account human-readable versions to enums +// please note no validation on versions strings is done, misses are silently discarded +// the assumption is ValidateSyncMessageVersions() has been called before using SyncMessageVersionsFromMap() +func SyncMessageVersionsFromMap(toconvert map[string][]string) map[string][]SyncMessageVersion { + // no per-account overrides + if len(toconvert) == 0 { + return nil + } + + allversions := make(map[string]SyncMessageVersion, len(AllSyncMessageVersions)) + for _, v := range AllSyncMessageVersions { + allversions[v.String()] = v + } + + toret := make(map[string][]SyncMessageVersion, len(toconvert)) + for account, versions := range toconvert { + toret[account] = SyncMessageVersionsFromString(versions) + } + return toret +} + func SyncMessageVersionsFromProtoEnums(peerCapabilities []int32) []SyncMessageVersion { toret := make([]SyncMessageVersion, 0) for _, pc := range peerCapabilities {