rename reverse proxy to services

This commit is contained in:
pascal
2026-02-11 21:39:51 +01:00
parent ebb1f4007d
commit 08ab1e3478
32 changed files with 1125 additions and 1471 deletions

View File

@@ -100,7 +100,7 @@ type Account struct {
NameServerGroupsG []nbdns.NameServerGroup `json:"-" gorm:"foreignKey:AccountID;references:id"`
DNSSettings DNSSettings `gorm:"embedded;embeddedPrefix:dns_settings_"`
PostureChecks []*posture.Checks `gorm:"foreignKey:AccountID;references:id"`
ReverseProxies []*reverseproxy.ReverseProxy `gorm:"foreignKey:AccountID;references:id"`
Services []*reverseproxy.Service `gorm:"foreignKey:AccountID;references:id"`
// Settings is a dictionary of Account settings
Settings *Settings `gorm:"embedded;embeddedPrefix:settings_"`
Networks []*networkTypes.Network `gorm:"foreignKey:AccountID;references:id"`
@@ -377,7 +377,7 @@ func (a *Account) GetPeerNetworkMap(
// GetProxyConnectionResources returns ACL peers for the proxy-embedded peer based on exposed services.
// No firewall rules are generated here; the proxy peer is always a new on-demand client with a stateful
// firewall, so OUT rules are unnecessary. Inbound rules are handled on the target/router peer side.
func (a *Account) GetProxyConnectionResources(ctx context.Context, exposedServices map[string][]*reverseproxy.ReverseProxy) []*nbpeer.Peer {
func (a *Account) GetProxyConnectionResources(ctx context.Context, exposedServices map[string][]*reverseproxy.Service) []*nbpeer.Peer {
var aclPeers []*nbpeer.Peer
for _, peerServices := range exposedServices {
@@ -406,7 +406,7 @@ func (a *Account) GetProxyConnectionResources(ctx context.Context, exposedServic
// GetPeerProxyResources returns ACL peers and inbound firewall rules for a peer that is targeted by reverse proxy services.
// Only IN rules are generated; OUT rules are omitted since proxy peers are always new clients with stateful firewalls.
// Rules use PortRange only (not the legacy Port field) as this feature only targets current peer versions.
func (a *Account) GetPeerProxyResources(peerID string, services []*reverseproxy.ReverseProxy, proxyPeers []*nbpeer.Peer) ([]*nbpeer.Peer, []*FirewallRule) {
func (a *Account) GetPeerProxyResources(peerID string, services []*reverseproxy.Service, proxyPeers []*nbpeer.Peer) ([]*nbpeer.Peer, []*FirewallRule) {
var aclPeers []*nbpeer.Peer
var firewallRules []*FirewallRule
@@ -1858,7 +1858,7 @@ func (a *Account) GetProxyPeers() map[string][]*nbpeer.Peer {
return proxyPeers
}
func (a *Account) GetPeerProxyRoutes(ctx context.Context, peer *nbpeer.Peer, proxies map[string][]*reverseproxy.ReverseProxy, resourcesMap map[string]*resourceTypes.NetworkResource, routers map[string]map[string]*routerTypes.NetworkRouter, proxyPeers []*nbpeer.Peer) ([]*route.Route, []*RouteFirewallRule, []*nbpeer.Peer) {
func (a *Account) GetPeerProxyRoutes(ctx context.Context, peer *nbpeer.Peer, proxies map[string][]*reverseproxy.Service, resourcesMap map[string]*resourceTypes.NetworkResource, routers map[string]map[string]*routerTypes.NetworkRouter, proxyPeers []*nbpeer.Peer) ([]*route.Route, []*RouteFirewallRule, []*nbpeer.Peer) {
sourceRanges := make([]string, 0, len(proxyPeers))
for _, proxyPeer := range proxyPeers {
sourceRanges = append(sourceRanges, fmt.Sprintf(AllowedIPsFormat, proxyPeer.IP))
@@ -1924,7 +1924,7 @@ func (a *Account) GetResourcesMap() map[string]*resourceTypes.NetworkResource {
}
func (a *Account) InjectProxyPolicies(ctx context.Context) {
if len(a.ReverseProxies) == 0 {
if len(a.Services) == 0 {
return
}
@@ -1933,7 +1933,7 @@ func (a *Account) InjectProxyPolicies(ctx context.Context) {
return
}
for _, service := range a.ReverseProxies {
for _, service := range a.Services {
if !service.Enabled {
continue
}

View File

@@ -1,409 +0,0 @@
package types
import (
"context"
"net"
"net/netip"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy"
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
)
func TestGetProxyConnectionResources_PeerTarget(t *testing.T) {
account := &Account{
Peers: map[string]*nbpeer.Peer{
"target-peer": {ID: "target-peer", IP: net.ParseIP("100.64.0.1")},
},
}
exposedServices := map[string][]*reverseproxy.ReverseProxy{
"target-peer": {
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypePeer,
TargetId: "target-peer",
Port: 8080,
Enabled: true,
},
},
},
},
}
aclPeers := account.GetProxyConnectionResources(context.Background(), exposedServices)
require.Len(t, aclPeers, 1)
assert.Equal(t, "target-peer", aclPeers[0].ID)
}
func TestGetProxyConnectionResources_DisabledService(t *testing.T) {
account := &Account{
Peers: map[string]*nbpeer.Peer{
"target-peer": {ID: "target-peer", IP: net.ParseIP("100.64.0.1")},
},
}
exposedServices := map[string][]*reverseproxy.ReverseProxy{
"target-peer": {
{
ID: "proxy-1",
Enabled: false,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypePeer,
TargetId: "target-peer",
Port: 8080,
Enabled: true,
},
},
},
},
}
aclPeers := account.GetProxyConnectionResources(context.Background(), exposedServices)
assert.Empty(t, aclPeers)
}
func TestGetProxyConnectionResources_ResourceTargetSkipped(t *testing.T) {
account := &Account{
Peers: map[string]*nbpeer.Peer{
"router-peer": {ID: "router-peer", IP: net.ParseIP("100.64.0.2")},
},
}
exposedServices := map[string][]*reverseproxy.ReverseProxy{
"router-peer": {
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-1",
Port: 443,
Enabled: true,
},
},
},
},
}
aclPeers := account.GetProxyConnectionResources(context.Background(), exposedServices)
assert.Empty(t, aclPeers, "resource targets should not add ACL peers via GetProxyConnectionResources")
}
func TestGetPeerProxyResources_PeerTarget(t *testing.T) {
proxyPeers := []*nbpeer.Peer{
{ID: "proxy-peer-1", IP: net.ParseIP("100.64.0.10")},
{ID: "proxy-peer-2", IP: net.ParseIP("100.64.0.11")},
}
services := []*reverseproxy.ReverseProxy{
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypePeer,
TargetId: "target-peer",
Port: 8080,
Enabled: true,
},
},
},
}
account := &Account{}
aclPeers, fwRules := account.GetPeerProxyResources("target-peer", services, proxyPeers)
require.Len(t, aclPeers, 2, "should include all proxy peers")
require.Len(t, fwRules, 2, "should have one IN rule per proxy peer")
for i, rule := range fwRules {
assert.Equal(t, "proxy-proxy-1", rule.PolicyID)
assert.Equal(t, proxyPeers[i].IP.String(), rule.PeerIP)
assert.Equal(t, FirewallRuleDirectionIN, rule.Direction)
assert.Equal(t, "allow", rule.Action)
assert.Equal(t, string(PolicyRuleProtocolTCP), rule.Protocol)
assert.Equal(t, uint16(8080), rule.PortRange.Start)
assert.Equal(t, uint16(8080), rule.PortRange.End)
}
}
func TestGetPeerProxyResources_PeerTargetMismatch(t *testing.T) {
proxyPeers := []*nbpeer.Peer{
{ID: "proxy-peer-1", IP: net.ParseIP("100.64.0.10")},
}
services := []*reverseproxy.ReverseProxy{
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypePeer,
TargetId: "other-peer",
Port: 8080,
Enabled: true,
},
},
},
}
account := &Account{}
aclPeers, fwRules := account.GetPeerProxyResources("target-peer", services, proxyPeers)
require.Len(t, aclPeers, 1, "should still add proxy peers to ACL")
assert.Empty(t, fwRules, "should not generate rules when target doesn't match this peer")
}
func TestGetPeerProxyResources_ResourceAccessLocal(t *testing.T) {
proxyPeers := []*nbpeer.Peer{
{ID: "proxy-peer-1", IP: net.ParseIP("100.64.0.10")},
}
services := []*reverseproxy.ReverseProxy{
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-1",
Port: 443,
Enabled: true,
AccessLocal: true,
},
},
},
}
account := &Account{}
aclPeers, fwRules := account.GetPeerProxyResources("router-peer", services, proxyPeers)
require.Len(t, aclPeers, 1, "should include proxy peers in ACL")
require.Len(t, fwRules, 1, "should generate IN rule for AccessLocal resource")
rule := fwRules[0]
assert.Equal(t, "proxy-proxy-1", rule.PolicyID)
assert.Equal(t, "100.64.0.10", rule.PeerIP)
assert.Equal(t, FirewallRuleDirectionIN, rule.Direction)
assert.Equal(t, uint16(443), rule.PortRange.Start)
}
func TestGetPeerProxyResources_ResourceWithoutAccessLocal(t *testing.T) {
proxyPeers := []*nbpeer.Peer{
{ID: "proxy-peer-1", IP: net.ParseIP("100.64.0.10")},
}
services := []*reverseproxy.ReverseProxy{
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-1",
Port: 443,
Enabled: true,
AccessLocal: false,
},
},
},
}
account := &Account{}
aclPeers, fwRules := account.GetPeerProxyResources("router-peer", services, proxyPeers)
require.Len(t, aclPeers, 1, "should still include proxy peers in ACL")
assert.Empty(t, fwRules, "should not generate peer rules when AccessLocal is false")
}
func TestGetPeerProxyResources_MixedTargets(t *testing.T) {
proxyPeers := []*nbpeer.Peer{
{ID: "proxy-peer-1", IP: net.ParseIP("100.64.0.10")},
}
services := []*reverseproxy.ReverseProxy{
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypePeer,
TargetId: "target-peer",
Port: 8080,
Enabled: true,
},
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-1",
Port: 443,
Enabled: true,
AccessLocal: true,
},
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-2",
Port: 8443,
Enabled: true,
AccessLocal: false,
},
},
},
}
account := &Account{}
aclPeers, fwRules := account.GetPeerProxyResources("target-peer", services, proxyPeers)
require.Len(t, aclPeers, 1)
require.Len(t, fwRules, 2, "should have rules for peer target + AccessLocal resource")
ports := []uint16{fwRules[0].PortRange.Start, fwRules[1].PortRange.Start}
assert.Contains(t, ports, uint16(8080), "should include peer target port")
assert.Contains(t, ports, uint16(443), "should include AccessLocal resource port")
}
func newProxyRoutesTestAccount() *Account {
return &Account{
Peers: map[string]*nbpeer.Peer{
"router-peer": {ID: "router-peer", Key: "router-key", IP: net.ParseIP("100.64.0.2")},
"proxy-peer": {ID: "proxy-peer", Key: "proxy-key", IP: net.ParseIP("100.64.0.10")},
},
}
}
func TestGetPeerProxyRoutes_ResourceWithoutAccessLocal(t *testing.T) {
account := newProxyRoutesTestAccount()
proxyPeers := []*nbpeer.Peer{account.Peers["proxy-peer"]}
resourcesMap := map[string]*resourceTypes.NetworkResource{
"resource-1": {
ID: "resource-1",
AccountID: "accountID",
NetworkID: "net-1",
Name: "web-service",
Type: resourceTypes.Host,
Prefix: netip.MustParsePrefix("192.168.1.100/32"),
Enabled: true,
},
}
routers := map[string]map[string]*routerTypes.NetworkRouter{
"net-1": {
"router-peer": {ID: "router-1", NetworkID: "net-1", Peer: "router-peer", Masquerade: true, Metric: 100},
},
}
exposedServices := map[string][]*reverseproxy.ReverseProxy{
"router-peer": {
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-1",
Port: 443,
Enabled: true,
AccessLocal: false,
},
},
},
},
}
routes, routeFwRules, aclPeers := account.GetPeerProxyRoutes(context.Background(), account.Peers["proxy-peer"], exposedServices, resourcesMap, routers, proxyPeers)
require.NotEmpty(t, routes, "should generate routes for non-AccessLocal resource")
require.NotEmpty(t, routeFwRules, "should generate route firewall rules for non-AccessLocal resource")
require.NotEmpty(t, aclPeers, "should include router peer in ACL")
assert.Equal(t, uint16(443), routeFwRules[0].PortRange.Start)
assert.Equal(t, "192.168.1.100/32", routeFwRules[0].Destination)
}
func TestGetPeerProxyRoutes_ResourceWithAccessLocal(t *testing.T) {
account := newProxyRoutesTestAccount()
proxyPeers := []*nbpeer.Peer{account.Peers["proxy-peer"]}
resourcesMap := map[string]*resourceTypes.NetworkResource{
"resource-1": {
ID: "resource-1",
AccountID: "accountID",
NetworkID: "net-1",
Name: "local-service",
Type: resourceTypes.Host,
Prefix: netip.MustParsePrefix("192.168.1.100/32"),
Enabled: true,
},
}
routers := map[string]map[string]*routerTypes.NetworkRouter{
"net-1": {
"router-peer": {ID: "router-1", NetworkID: "net-1", Peer: "router-peer", Masquerade: true, Metric: 100},
},
}
exposedServices := map[string][]*reverseproxy.ReverseProxy{
"router-peer": {
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypeResource,
TargetId: "resource-1",
Port: 443,
Enabled: true,
AccessLocal: true,
},
},
},
},
}
routes, routeFwRules, aclPeers := account.GetPeerProxyRoutes(context.Background(), account.Peers["proxy-peer"], exposedServices, resourcesMap, routers, proxyPeers)
require.NotEmpty(t, routes, "should generate routes for AccessLocal resource")
require.NotEmpty(t, routeFwRules, "should generate route firewall rules for AccessLocal resource")
require.NotEmpty(t, aclPeers, "should include router peer in ACL for AccessLocal resource")
assert.Equal(t, uint16(443), routeFwRules[0].PortRange.Start)
assert.Equal(t, "192.168.1.100/32", routeFwRules[0].Destination)
}
func TestGetPeerProxyRoutes_PeerTargetSkipped(t *testing.T) {
account := newProxyRoutesTestAccount()
proxyPeers := []*nbpeer.Peer{account.Peers["proxy-peer"]}
exposedServices := map[string][]*reverseproxy.ReverseProxy{
"router-peer": {
{
ID: "proxy-1",
Enabled: true,
Targets: []reverseproxy.Target{
{
TargetType: reverseproxy.TargetTypePeer,
TargetId: "target-peer",
Port: 8080,
Enabled: true,
},
},
},
},
}
routes, routeFwRules, aclPeers := account.GetPeerProxyRoutes(context.Background(), account.Peers["proxy-peer"], exposedServices, nil, nil, proxyPeers)
assert.Empty(t, routes, "should NOT generate routes for peer targets")
assert.Empty(t, routeFwRules, "should NOT generate route firewall rules for peer targets")
assert.Empty(t, aclPeers)
}