diff --git a/management/internals/modules/reverseproxy/interface.go b/management/internals/modules/reverseproxy/interface.go index 949640417..93ed19e0f 100644 --- a/management/internals/modules/reverseproxy/interface.go +++ b/management/internals/modules/reverseproxy/interface.go @@ -12,4 +12,9 @@ type Manager interface { DeleteReverseProxy(ctx context.Context, accountID, userID, reverseProxyID string) error SetCertificateIssuedAt(ctx context.Context, accountID, reverseProxyID string) error SetStatus(ctx context.Context, accountID, reverseProxyID string, status ProxyStatus) error + ReloadAllReverseProxiesForAccount(ctx context.Context, accountID string) error + ReloadReverseProxy(ctx context.Context, accountID, reverseProxyID string) error + GetGlobalReverseProxies(ctx context.Context) ([]*ReverseProxy, error) + GetProxyByID(ctx context.Context, accountID, reverseProxyID string) (*ReverseProxy, error) + GetAccountReverseProxies(ctx context.Context, accountID string) ([]*ReverseProxy, error) } diff --git a/management/internals/modules/reverseproxy/manager/manager.go b/management/internals/modules/reverseproxy/manager/manager.go index 8e98738de..e0ebb5864 100644 --- a/management/internals/modules/reverseproxy/manager/manager.go +++ b/management/internals/modules/reverseproxy/manager/manager.go @@ -54,7 +54,43 @@ func (m *managerImpl) GetAllReverseProxies(ctx context.Context, accountID, userI return nil, status.NewPermissionDeniedError() } - return m.store.GetAccountReverseProxies(ctx, store.LockingStrengthNone, accountID) + proxies, err := m.store.GetAccountReverseProxies(ctx, store.LockingStrengthNone, accountID) + if err != nil { + return nil, fmt.Errorf("failed to get reverse proxies: %w", err) + } + + for _, proxy := range proxies { + err = m.replaceHostByLookup(ctx, accountID, proxy) + if err != nil { + return nil, fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + } + + return proxies, nil +} + +func (m *managerImpl) replaceHostByLookup(ctx context.Context, accountID string, proxy *reverseproxy.ReverseProxy) error { + for _, target := range proxy.Targets { + switch target.TargetType { + case reverseproxy.TargetTypePeer: + peer, err := m.store.GetPeerByID(ctx, store.LockingStrengthNone, accountID, target.TargetId) + if err != nil { + return fmt.Errorf("failed to get peer by id: %w", err) + } + target.Host = peer.IP.String() + case reverseproxy.TargetTypeHost, reverseproxy.TargetTypeDomain: + resource, err := m.store.GetNetworkResourceByID(ctx, store.LockingStrengthNone, accountID, target.TargetId) + if err != nil { + return fmt.Errorf("failed to get resource by id: %w", err) + } + target.Host = resource.Address + case reverseproxy.TargetTypeSubnet: + // For subnets we do not do any lookups on the resource + default: + return fmt.Errorf("unknown target type: %s", target.TargetType) + } + } + return nil } func (m *managerImpl) GetReverseProxy(ctx context.Context, accountID, userID, reverseProxyID string) (*reverseproxy.ReverseProxy, error) { @@ -66,7 +102,16 @@ func (m *managerImpl) GetReverseProxy(ctx context.Context, accountID, userID, re return nil, status.NewPermissionDeniedError() } - return m.store.GetReverseProxyByID(ctx, store.LockingStrengthNone, accountID, reverseProxyID) + proxy, err := m.store.GetReverseProxyByID(ctx, store.LockingStrengthNone, accountID, reverseProxyID) + if err != nil { + return nil, fmt.Errorf("failed to get reverse proxy: %w", err) + } + + err = m.replaceHostByLookup(ctx, accountID, proxy) + if err != nil { + return nil, fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + return proxy, nil } func (m *managerImpl) CreateReverseProxy(ctx context.Context, accountID, userID string, reverseProxy *reverseproxy.ReverseProxy) (*reverseproxy.ReverseProxy, error) { @@ -149,6 +194,7 @@ func (m *managerImpl) UpdateReverseProxy(ctx context.Context, accountID, userID var oldCluster string var domainChanged bool + var reverseProxyEnabledChanged bool err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error { existingReverseProxy, err := transaction.GetReverseProxyByID(ctx, store.LockingStrengthUpdate, accountID, reverseProxy.ID) @@ -184,6 +230,7 @@ func (m *managerImpl) UpdateReverseProxy(ctx context.Context, accountID, userID reverseProxy.Meta = existingReverseProxy.Meta reverseProxy.SessionPrivateKey = existingReverseProxy.SessionPrivateKey reverseProxy.SessionPublicKey = existingReverseProxy.SessionPublicKey + reverseProxyEnabledChanged = existingReverseProxy.Enabled != reverseProxy.Enabled if err = validateTargetReferences(ctx, transaction, accountID, reverseProxy.Targets); err != nil { return err @@ -201,12 +248,19 @@ func (m *managerImpl) UpdateReverseProxy(ctx context.Context, accountID, userID m.accountManager.StoreEvent(ctx, userID, reverseProxy.ID, accountID, activity.ReverseProxyUpdated, reverseProxy.EventMeta()) + token, err := m.tokenStore.GenerateToken(accountID, reverseProxy.ID, 5*time.Minute) + if err != nil { + return nil, fmt.Errorf("failed to generate authentication token: %w", err) + } + switch { case domainChanged && oldCluster != reverseProxy.ProxyCluster: m.proxyGRPCServer.SendReverseProxyUpdateToCluster(reverseProxy.ToProtoMapping(reverseproxy.Delete, "", m.proxyGRPCServer.GetOIDCValidationConfig()), oldCluster) - m.proxyGRPCServer.SendReverseProxyUpdateToCluster(reverseProxy.ToProtoMapping(reverseproxy.Create, "", m.proxyGRPCServer.GetOIDCValidationConfig()), reverseProxy.ProxyCluster) - case !reverseProxy.Enabled: + m.proxyGRPCServer.SendReverseProxyUpdateToCluster(reverseProxy.ToProtoMapping(reverseproxy.Create, token, m.proxyGRPCServer.GetOIDCValidationConfig()), reverseProxy.ProxyCluster) + case !reverseProxy.Enabled && reverseProxyEnabledChanged: m.proxyGRPCServer.SendReverseProxyUpdateToCluster(reverseProxy.ToProtoMapping(reverseproxy.Delete, "", m.proxyGRPCServer.GetOIDCValidationConfig()), reverseProxy.ProxyCluster) + case reverseProxy.Enabled && reverseProxyEnabledChanged: + m.proxyGRPCServer.SendReverseProxyUpdateToCluster(reverseProxy.ToProtoMapping(reverseproxy.Create, token, m.proxyGRPCServer.GetOIDCValidationConfig()), reverseProxy.ProxyCluster) default: m.proxyGRPCServer.SendReverseProxyUpdateToCluster(reverseProxy.ToProtoMapping(reverseproxy.Update, "", m.proxyGRPCServer.GetOIDCValidationConfig()), reverseProxy.ProxyCluster) @@ -217,7 +271,7 @@ func (m *managerImpl) UpdateReverseProxy(ctx context.Context, accountID, userID } // validateTargetReferences checks that all target IDs reference existing peers or resources in the account. -func validateTargetReferences(ctx context.Context, transaction store.Store, accountID string, targets []reverseproxy.Target) error { +func validateTargetReferences(ctx context.Context, transaction store.Store, accountID string, targets []*reverseproxy.Target) error { for _, target := range targets { switch target.TargetType { case reverseproxy.TargetTypePeer: @@ -311,3 +365,86 @@ func (m *managerImpl) SetStatus(ctx context.Context, accountID, reverseProxyID s return nil }) } + +func (m *managerImpl) ReloadReverseProxy(ctx context.Context, accountID, reverseProxyID string) error { + proxy, err := m.store.GetReverseProxyByID(ctx, store.LockingStrengthNone, accountID, reverseProxyID) + if err != nil { + return fmt.Errorf("failed to get reverse proxy: %w", err) + } + + err = m.replaceHostByLookup(ctx, accountID, proxy) + if err != nil { + return fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + + m.proxyGRPCServer.SendReverseProxyUpdateToCluster(proxy.ToProtoMapping(reverseproxy.Update, "", m.proxyGRPCServer.GetOIDCValidationConfig()), proxy.ProxyCluster) + + m.accountManager.UpdateAccountPeers(ctx, accountID) + + return nil +} + +func (m *managerImpl) ReloadAllReverseProxiesForAccount(ctx context.Context, accountID string) error { + proxies, err := m.store.GetAccountReverseProxies(ctx, store.LockingStrengthNone, accountID) + if err != nil { + return fmt.Errorf("failed to get reverse proxies: %w", err) + } + + for _, proxy := range proxies { + err = m.replaceHostByLookup(ctx, accountID, proxy) + if err != nil { + return fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + m.proxyGRPCServer.SendReverseProxyUpdateToCluster(proxy.ToProtoMapping(reverseproxy.Update, "", m.proxyGRPCServer.GetOIDCValidationConfig()), proxy.ProxyCluster) + } + + m.accountManager.UpdateAccountPeers(ctx, accountID) + + return nil +} + +func (m *managerImpl) GetGlobalReverseProxies(ctx context.Context) ([]*reverseproxy.ReverseProxy, error) { + proxies, err := m.store.GetReverseProxies(ctx, store.LockingStrengthNone) + if err != nil { + return nil, fmt.Errorf("failed to get reverse proxies: %w", err) + } + + for _, proxy := range proxies { + err = m.replaceHostByLookup(ctx, proxy.AccountID, proxy) + if err != nil { + return nil, fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + } + + return proxies, nil +} + +func (m *managerImpl) GetProxyByID(ctx context.Context, accountID, reverseProxyID string) (*reverseproxy.ReverseProxy, error) { + proxy, err := m.store.GetReverseProxyByID(ctx, store.LockingStrengthNone, accountID, reverseProxyID) + if err != nil { + return nil, fmt.Errorf("failed to get reverse proxy: %w", err) + } + + err = m.replaceHostByLookup(ctx, accountID, proxy) + if err != nil { + return nil, fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + + return proxy, nil +} + +func (m *managerImpl) GetAccountReverseProxies(ctx context.Context, accountID string) ([]*reverseproxy.ReverseProxy, error) { + proxies, err := m.store.GetAccountReverseProxies(ctx, store.LockingStrengthNone, accountID) + if err != nil { + return nil, fmt.Errorf("failed to get reverse proxies: %w", err) + } + + for _, proxy := range proxies { + err = m.replaceHostByLookup(ctx, accountID, proxy) + if err != nil { + return nil, fmt.Errorf("failed to replace host by lookup for proxy %s: %w", proxy.ID, err) + } + } + + return proxies, nil +} diff --git a/management/internals/modules/reverseproxy/reverseproxy.go b/management/internals/modules/reverseproxy/reverseproxy.go index 26828ceee..6ab6d0828 100644 --- a/management/internals/modules/reverseproxy/reverseproxy.go +++ b/management/internals/modules/reverseproxy/reverseproxy.go @@ -43,7 +43,7 @@ const ( type Target struct { Path *string `json:"path,omitempty"` - Host string `json:"host"` + Host string `json:"host"` // the Host field is only used for subnet targets, otherwise ignored Port int `json:"port"` Protocol string `json:"protocol"` TargetId string `json:"target_id"` @@ -92,9 +92,9 @@ type ReverseProxy struct { ID string `gorm:"primaryKey"` AccountID string `gorm:"index"` Name string - Domain string `gorm:"index"` - ProxyCluster string `gorm:"index"` - Targets []Target `gorm:"serializer:json"` + Domain string `gorm:"index"` + ProxyCluster string `gorm:"index"` + Targets []*Target `gorm:"serializer:json"` Enabled bool PassHostHeader bool RewriteRedirects bool @@ -104,7 +104,7 @@ type ReverseProxy struct { SessionPublicKey string `gorm:"column:session_public_key"` } -func NewReverseProxy(accountID, name, domain, proxyCluster string, targets []Target, enabled bool) *ReverseProxy { +func NewReverseProxy(accountID, name, domain, proxyCluster string, targets []*Target, enabled bool) *ReverseProxy { rp := &ReverseProxy{ AccountID: accountID, Name: name, @@ -157,7 +157,7 @@ func (r *ReverseProxy) ToAPIResponse() *api.ReverseProxy { for _, target := range r.Targets { apiTargets = append(apiTargets, api.ReverseProxyTarget{ Path: target.Path, - Host: target.Host, + Host: &target.Host, Port: target.Port, Protocol: api.ReverseProxyTargetProtocol(target.Protocol), TargetId: target.TargetId, @@ -280,19 +280,22 @@ func (r *ReverseProxy) FromAPIRequest(req *api.ReverseProxyRequest, accountID st r.Domain = req.Domain r.AccountID = accountID - targets := make([]Target, 0, len(req.Targets)) + targets := make([]*Target, 0, len(req.Targets)) for _, apiTarget := range req.Targets { accessLocal := apiTarget.AccessLocal != nil && *apiTarget.AccessLocal - targets = append(targets, Target{ + target := &Target{ Path: apiTarget.Path, - Host: apiTarget.Host, Port: apiTarget.Port, Protocol: string(apiTarget.Protocol), TargetId: apiTarget.TargetId, TargetType: string(apiTarget.TargetType), Enabled: apiTarget.Enabled, AccessLocal: accessLocal, - }) + } + if apiTarget.Host != nil { + target.Host = *apiTarget.Host + } + targets = append(targets, target) } r.Targets = targets @@ -349,8 +352,14 @@ func (r *ReverseProxy) Validate() error { for i, target := range r.Targets { switch target.TargetType { - case TargetTypePeer, TargetTypeHost, TargetTypeSubnet, TargetTypeDomain: - // valid resource types + case TargetTypePeer, TargetTypeHost, TargetTypeDomain: + if target.Host != "" { + return fmt.Errorf("target %d has host specified but target_type is %q", i, target.TargetType) + } + case TargetTypeSubnet: + if target.Host == "" { + return fmt.Errorf("target %d has empty host but target_type is %q", i, target.TargetType) + } default: return fmt.Errorf("target %d has invalid target_type %q", i, target.TargetType) } @@ -367,7 +376,7 @@ func (r *ReverseProxy) EventMeta() map[string]any { } func (r *ReverseProxy) Copy() *ReverseProxy { - targets := make([]Target, len(r.Targets)) + targets := make([]*Target, len(r.Targets)) copy(targets, r.Targets) return &ReverseProxy{ diff --git a/management/internals/server/boot.go b/management/internals/server/boot.go index 7de4591d0..c01d7b316 100644 --- a/management/internals/server/boot.go +++ b/management/internals/server/boot.go @@ -163,7 +163,7 @@ func (s *BaseServer) GRPCServer() *grpc.Server { func (s *BaseServer) ReverseProxyGRPCServer() *nbgrpc.ProxyServiceServer { return Create(s, func() *nbgrpc.ProxyServiceServer { - proxyService := nbgrpc.NewProxyServiceServer(s.Store(), s.AccessLogsManager(), s.ProxyTokenStore(), s.proxyOIDCConfig(), s.PeersManager()) + proxyService := nbgrpc.NewProxyServiceServer(s.AccessLogsManager(), s.ProxyTokenStore(), s.proxyOIDCConfig(), s.PeersManager()) s.AfterInit(func(s *BaseServer) { proxyService.SetProxyManager(s.ReverseProxyManager()) }) diff --git a/management/internals/server/modules.go b/management/internals/server/modules.go index 0755c50cb..1ff409289 100644 --- a/management/internals/server/modules.go +++ b/management/internals/server/modules.go @@ -157,7 +157,7 @@ func (s *BaseServer) GroupsManager() groups.Manager { func (s *BaseServer) ResourcesManager() resources.Manager { return Create(s, func() resources.Manager { - return resources.NewManager(s.Store(), s.PermissionsManager(), s.GroupsManager(), s.AccountManager()) + return resources.NewManager(s.Store(), s.PermissionsManager(), s.GroupsManager(), s.AccountManager(), s.ReverseProxyManager()) }) } diff --git a/management/internals/shared/grpc/proxy.go b/management/internals/shared/grpc/proxy.go index 83fe6ebb8..f26cab0a1 100644 --- a/management/internals/shared/grpc/proxy.go +++ b/management/internals/shared/grpc/proxy.go @@ -26,7 +26,6 @@ import ( "github.com/netbirdio/netbird/management/internals/modules/reverseproxy" "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/accesslogs" "github.com/netbirdio/netbird/management/internals/modules/reverseproxy/sessionkey" - "github.com/netbirdio/netbird/management/server/store" proxyauth "github.com/netbirdio/netbird/proxy/auth" "github.com/netbirdio/netbird/shared/management/proto" ) @@ -42,17 +41,6 @@ type ProxyOIDCConfig struct { KeysLocation string } -type reverseProxyStore interface { - GetReverseProxies(ctx context.Context, lockStrength store.LockingStrength) ([]*reverseproxy.ReverseProxy, error) - GetAccountReverseProxies(ctx context.Context, lockStrength store.LockingStrength, accountID string) ([]*reverseproxy.ReverseProxy, error) - GetReverseProxyByID(ctx context.Context, lockStrength store.LockingStrength, accountID string, serviceID string) (*reverseproxy.ReverseProxy, error) -} - -type reverseProxyManager interface { - SetCertificateIssuedAt(ctx context.Context, accountID, reverseProxyID string) error - SetStatus(ctx context.Context, accountID, reverseProxyID string, status reverseproxy.ProxyStatus) error -} - // ClusterInfo contains information about a proxy cluster. type ClusterInfo struct { Address string @@ -72,14 +60,11 @@ type ProxyServiceServer struct { // Channel for broadcasting reverse proxy updates to all proxies updatesChan chan *proto.ProxyMapping - // Store of reverse proxies - reverseProxyStore reverseProxyStore - // Manager for access logs accessLogManager accesslogs.Manager // Manager for reverse proxy operations - reverseProxyManager reverseProxyManager + reverseProxyManager reverseproxy.Manager // Manager for peers peersManager peers.Manager @@ -106,18 +91,17 @@ type proxyConnection struct { } // NewProxyServiceServer creates a new proxy service server -func NewProxyServiceServer(store reverseProxyStore, accessLogMgr accesslogs.Manager, tokenStore *OneTimeTokenStore, oidcConfig ProxyOIDCConfig, peersManager peers.Manager) *ProxyServiceServer { +func NewProxyServiceServer(accessLogMgr accesslogs.Manager, tokenStore *OneTimeTokenStore, oidcConfig ProxyOIDCConfig, peersManager peers.Manager) *ProxyServiceServer { return &ProxyServiceServer{ - updatesChan: make(chan *proto.ProxyMapping, 100), - reverseProxyStore: store, - accessLogManager: accessLogMgr, - oidcConfig: oidcConfig, - tokenStore: tokenStore, - peersManager: peersManager, + updatesChan: make(chan *proto.ProxyMapping, 100), + accessLogManager: accessLogMgr, + oidcConfig: oidcConfig, + tokenStore: tokenStore, + peersManager: peersManager, } } -func (s *ProxyServiceServer) SetProxyManager(manager reverseProxyManager) { +func (s *ProxyServiceServer) SetProxyManager(manager reverseproxy.Manager) { s.reverseProxyManager = manager } @@ -189,7 +173,7 @@ func (s *ProxyServiceServer) GetMappingUpdate(req *proto.GetMappingUpdateRequest // sendSnapshot sends the initial snapshot of reverse proxies to the connecting proxy. // Only reverse proxies matching the proxy's cluster address are sent. func (s *ProxyServiceServer) sendSnapshot(ctx context.Context, conn *proxyConnection) error { - reverseProxies, err := s.reverseProxyStore.GetReverseProxies(ctx, store.LockingStrengthNone) + reverseProxies, err := s.reverseProxyManager.GetGlobalReverseProxies(ctx) if err != nil { return fmt.Errorf("get reverse proxies from store: %w", err) } @@ -434,7 +418,7 @@ func (s *ProxyServiceServer) GetAvailableClusters() []ClusterInfo { } func (s *ProxyServiceServer) Authenticate(ctx context.Context, req *proto.AuthenticateRequest) (*proto.AuthenticateResponse, error) { - proxy, err := s.reverseProxyStore.GetReverseProxyByID(ctx, store.LockingStrengthNone, req.GetAccountId(), req.GetId()) + proxy, err := s.reverseProxyManager.GetProxyByID(ctx, req.GetAccountId(), req.GetId()) if err != nil { // TODO: log the error return nil, status.Errorf(codes.FailedPrecondition, "failed to get reverse proxy from store: %v", err) @@ -613,7 +597,7 @@ func (s *ProxyServiceServer) GetOIDCURL(ctx context.Context, req *proto.GetOIDCU return nil, status.Errorf(codes.InvalidArgument, "failed to parse redirect url: %v", err) } // Validate redirectURL against known proxy endpoints to avoid abuse of OIDC redirection. - proxies, err := s.reverseProxyStore.GetAccountReverseProxies(ctx, store.LockingStrengthNone, req.GetAccountId()) + proxies, err := s.reverseProxyManager.GetAccountReverseProxies(ctx, req.GetAccountId()) if err != nil { // TODO: log return nil, status.Errorf(codes.FailedPrecondition, "failed to get reverse proxy from store: %v", err) @@ -719,7 +703,7 @@ func (s *ProxyServiceServer) ValidateState(state string) (verifier, redirectURL // GenerateSessionToken creates a signed session JWT for the given domain and user. func (s *ProxyServiceServer) GenerateSessionToken(ctx context.Context, domain, userID string, method proxyauth.Method) (string, error) { // Find the proxy by domain to get its signing key - proxies, err := s.reverseProxyStore.GetReverseProxies(ctx, store.LockingStrengthNone) + proxies, err := s.reverseProxyManager.GetGlobalReverseProxies(ctx) if err != nil { return "", fmt.Errorf("get reverse proxies: %w", err) } diff --git a/management/server/account.go b/management/server/account.go index a9f59773a..a0f68452a 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -15,6 +15,7 @@ import ( "sync" "time" + "github.com/netbirdio/netbird/management/internals/modules/reverseproxy" "github.com/netbirdio/netbird/management/server/job" "github.com/netbirdio/netbird/shared/auth" @@ -82,8 +83,9 @@ type DefaultAccountManager struct { requestBuffer *AccountRequestBuffer - proxyController port_forwarding.Controller - settingsManager settings.Manager + proxyController port_forwarding.Controller + settingsManager settings.Manager + reverseProxyManager reverseproxy.Manager // config contains the management server configuration config *nbconfig.Config @@ -321,6 +323,9 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco if err = am.reallocateAccountPeerIPs(ctx, transaction, accountID, newSettings.NetworkRange); err != nil { return err } + if err = am.reverseProxyManager.ReloadAllReverseProxiesForAccount(ctx, accountID); err != nil { + log.WithContext(ctx).Warnf("failed to reload all reverse proxy for account %s: %v", accountID, err) + } updateAccountPeers = true } diff --git a/management/server/networks/resources/manager.go b/management/server/networks/resources/manager.go index 66484d120..7497aa26e 100644 --- a/management/server/networks/resources/manager.go +++ b/management/server/networks/resources/manager.go @@ -5,6 +5,9 @@ import ( "errors" "fmt" + log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/management/internals/modules/reverseproxy" "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/groups" @@ -30,21 +33,23 @@ type Manager interface { } type managerImpl struct { - store store.Store - permissionsManager permissions.Manager - groupsManager groups.Manager - accountManager account.Manager + store store.Store + permissionsManager permissions.Manager + groupsManager groups.Manager + accountManager account.Manager + reverseProxyManager reverseproxy.Manager } type mockManager struct { } -func NewManager(store store.Store, permissionsManager permissions.Manager, groupsManager groups.Manager, accountManager account.Manager) Manager { +func NewManager(store store.Store, permissionsManager permissions.Manager, groupsManager groups.Manager, accountManager account.Manager, reverseproxyManager reverseproxy.Manager) Manager { return &managerImpl{ - store: store, - permissionsManager: permissionsManager, - groupsManager: groupsManager, - accountManager: accountManager, + store: store, + permissionsManager: permissionsManager, + groupsManager: groupsManager, + accountManager: accountManager, + reverseProxyManager: reverseproxyManager, } } @@ -257,6 +262,14 @@ func (m *managerImpl) UpdateResource(ctx context.Context, userID string, resourc event() } + // TODO: optimize to only reload reverse proxies that are affected by the resource update instead of all of them + go func() { + err := m.reverseProxyManager.ReloadAllReverseProxiesForAccount(ctx, resource.AccountID) + if err != nil { + log.WithContext(ctx).Warnf("failed to reload all proxies for account: %v", err) + } + }() + go m.accountManager.UpdateAccountPeers(ctx, resource.AccountID) return resource, nil diff --git a/shared/management/http/api/openapi.yml b/shared/management/http/api/openapi.yml index f74950760..c29e06635 100644 --- a/shared/management/http/api/openapi.yml +++ b/shared/management/http/api/openapi.yml @@ -2972,7 +2972,6 @@ components: - target_id - target_type - protocol - - host - port - enabled ReverseProxyAuthConfig: diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index eb51d823e..865a5dd80 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -2084,12 +2084,12 @@ type ReverseProxyTarget struct { Enabled bool `json:"enabled"` // Host Backend ip or domain for this target - Host string `json:"host"` + Host *string `json:"host,omitempty"` // Path URL path prefix for this target Path *string `json:"path,omitempty"` - // Port Backend port for this target + // Port Backend port for this target. Use 0 or omit to use the scheme default (80 for http, 443 for https). Port int `json:"port"` // Protocol Protocol to use when connecting to the backend