mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-30 11:31:29 +02:00
inject proxy policies on nmdata path
This commit is contained in:
@@ -131,12 +131,12 @@ func (c *Controller) OnPeerDisconnected(ctx context.Context, accountID string, p
|
||||
|
||||
// injectAllProxyPolicies prepares an account for the per-peer network-map
|
||||
// computation. It prepends the in-memory agent-network services synthesised
|
||||
// from the account's current provider/policy state to account.Services so
|
||||
// the existing InjectProxyPolicies + injectPrivateServicePolicies walks pick
|
||||
// them up alongside persisted reverse-proxy services. Synthesised services
|
||||
// are never persisted; the account is loaded fresh per cycle so re-prepending
|
||||
// is safe and idempotent. Accounts without agent-network providers get an
|
||||
// empty synth slice — no behaviour change.
|
||||
// from the account's current provider/policy state to account.Services, so the
|
||||
// twin store built from the account carries them alongside the persisted
|
||||
// reverse-proxy services and synthesises their ACLs. Synthesised services are
|
||||
// never persisted; the account is loaded fresh per cycle so re-prepending is
|
||||
// safe and idempotent. Accounts without agent-network providers get an empty
|
||||
// synth slice — no behaviour change.
|
||||
func (c *Controller) injectAllProxyPolicies(ctx context.Context, account *types.Account) {
|
||||
synth, err := c.repo.SynthesizeAgentNetworkServices(ctx, account.Id)
|
||||
if err != nil {
|
||||
@@ -144,7 +144,26 @@ func (c *Controller) injectAllProxyPolicies(ctx context.Context, account *types.
|
||||
} else if len(synth) > 0 {
|
||||
account.Services = append(synth, account.Services...)
|
||||
}
|
||||
account.InjectProxyPolicies(ctx)
|
||||
}
|
||||
|
||||
// proxyServicesFromRepo is the store-path counterpart of
|
||||
// injectAllProxyPolicies: the network-map store reads the policies table, which
|
||||
// never holds the proxy ACLs, so the twin gets the services they are
|
||||
// synthesised from — the synthesised agent-network ones first, exactly as the
|
||||
// account path orders them.
|
||||
func (c *Controller) proxyServicesFromRepo(ctx context.Context, accountID string) []*nmdata.Service {
|
||||
persisted, err := c.repo.GetAccountServices(ctx, accountID)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to get services for account %s: %v", accountID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
synth, err := c.repo.SynthesizeAgentNetworkServices(ctx, accountID)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Warnf("synthesise agent-network services for account %s: %v", accountID, err)
|
||||
}
|
||||
|
||||
return types.TwinServices(append(synth, persisted...))
|
||||
}
|
||||
|
||||
func (c *Controller) CountStreams() int {
|
||||
@@ -467,6 +486,8 @@ func (c *Controller) getNetworkMapData(ctx context.Context, accountID string) *n
|
||||
return nil
|
||||
}
|
||||
|
||||
nmData.Services = c.proxyServicesFromRepo(ctx, accountID)
|
||||
|
||||
return nmData
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/netbirdio/netbird/management/internals/modules/agentnetwork"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/service"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/zones"
|
||||
"github.com/netbirdio/netbird/management/internals/modules/agentnetwork"
|
||||
"github.com/netbirdio/netbird/management/server/peer"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
@@ -22,6 +22,7 @@ type Repository interface {
|
||||
// services synthesised from the account's agent-network provider/policy
|
||||
// state. Empty for accounts without agent-network providers.
|
||||
SynthesizeAgentNetworkServices(ctx context.Context, accountID string) ([]*service.Service, error)
|
||||
GetAccountServices(ctx context.Context, accountID string) ([]*service.Service, error)
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
@@ -60,6 +61,10 @@ func (r *repository) SynthesizeAgentNetworkServices(ctx context.Context, account
|
||||
return agentnetwork.SynthesizeServices(ctx, r.store, accountID)
|
||||
}
|
||||
|
||||
func (r *repository) GetAccountServices(ctx context.Context, accountID string) ([]*service.Service, error) {
|
||||
return r.store.GetAccountServices(ctx, store.LockingStrengthNone, accountID)
|
||||
}
|
||||
|
||||
func (r *repository) GetAccountZones(ctx context.Context, accountID string) ([]*zones.Zone, error) {
|
||||
return r.store.GetAccountZones(ctx, store.LockingStrengthNone, accountID)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"description": "A reverse-proxy service targeting a domain network resource. The synthesised proxy-access ACL is a resource policy too: on the account path the resource-policy map was built after injection, so the routing peer must carry a route firewall rule sourced from the proxy peer for the resource's domain. The store reads the policies table and ResourcePolicies never holds it, so only the synthesis puts it there.",
|
||||
"peers": [
|
||||
"router-peer",
|
||||
"proxy-peer"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"Network": {"Serial": 32},
|
||||
"AccountSettings": {"RoutingPeerDNSResolutionEnabled": true},
|
||||
"Peers": {
|
||||
"router-peer": {"IP": "100.64.0.9", "Meta": {"WtVersion": "0.60.0"}},
|
||||
"proxy-peer": {
|
||||
"IP": "100.64.0.99",
|
||||
"Meta": {"WtVersion": "0.60.0"},
|
||||
"ProxyMeta": {"Embedded": true, "Cluster": "eu.proxy.netbird.io"}
|
||||
}
|
||||
},
|
||||
"NetworkResources": [
|
||||
{
|
||||
"ID": "res-domain",
|
||||
"NetworkID": "net-1",
|
||||
"Name": "app-domain",
|
||||
"Type": "domain",
|
||||
"Domain": "app.internal",
|
||||
"Enabled": true
|
||||
}
|
||||
],
|
||||
"Routers": {
|
||||
"net-1": {
|
||||
"router-peer": {"PublicID": "router-direct", "Masquerade": true, "Metric": 9999, "Enabled": true}
|
||||
}
|
||||
},
|
||||
"ProxyTargetedDomainResourceIDs": {"res-domain": {}},
|
||||
"Services": [
|
||||
{
|
||||
"ID": "svc-1",
|
||||
"Enabled": true,
|
||||
"Mode": "http",
|
||||
"ProxyCluster": "eu.proxy.netbird.io",
|
||||
"Targets": [
|
||||
{
|
||||
"Enabled": true,
|
||||
"Protocol": "https",
|
||||
"TargetID": "res-domain",
|
||||
"TargetType": "domain"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"description": "A reverse-proxy service targeting a peer. The proxy-access ACL is synthesised from Services, never loaded from the policies table, and is what lets the cluster's embedded proxy peer reach the target on the target's port: proxy-peer gets an OUT rule to app-peer on TCP 8080 and app-peer the matching IN rule. Without the synthesis both maps are empty of each other.",
|
||||
"peers": [
|
||||
"proxy-peer",
|
||||
"app-peer"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"Serial": "30",
|
||||
"peerConfig": {
|
||||
"address": "100.64.0.10/10",
|
||||
"sshConfig": {},
|
||||
"fqdn": "app-peer.netbird.test",
|
||||
"RoutingPeerDnsResolutionEnabled": true,
|
||||
"autoUpdate": {}
|
||||
},
|
||||
"remotePeers": [
|
||||
{
|
||||
"wgPubKey": "MgrwmZOHFZ+i0SXrfbBOcATxBAQsWKllrGL/32GvlxY=",
|
||||
"allowedIps": [
|
||||
"100.64.0.99/32"
|
||||
],
|
||||
"sshConfig": {},
|
||||
"fqdn": "proxy-peer.netbird.test",
|
||||
"agentVersion": "0.60.0"
|
||||
}
|
||||
],
|
||||
"DNSConfig": {
|
||||
"ServiceEnable": true,
|
||||
"CustomZones": [
|
||||
{
|
||||
"Domain": "netbird.test.",
|
||||
"Records": [
|
||||
{
|
||||
"Name": "app-peer.netbird.test",
|
||||
"Type": "1",
|
||||
"Class": "IN",
|
||||
"TTL": "300",
|
||||
"RData": "100.64.0.10"
|
||||
},
|
||||
{
|
||||
"Name": "proxy-peer.netbird.test",
|
||||
"Type": "1",
|
||||
"Class": "IN",
|
||||
"TTL": "300",
|
||||
"RData": "100.64.0.99"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ForwarderPort": "22054"
|
||||
},
|
||||
"FirewallRules": [
|
||||
{
|
||||
"PeerIP": "100.64.0.99",
|
||||
"Protocol": "TCP",
|
||||
"PortInfo": {
|
||||
"range": {
|
||||
"start": 8080,
|
||||
"end": 8080
|
||||
}
|
||||
},
|
||||
"PolicyID": "cHJveHktYWNjZXNzLXN2Yy0xLXByb3h5LXBlZXIt"
|
||||
}
|
||||
],
|
||||
"routesFirewallRulesIsEmpty": true,
|
||||
"sshAuth": {
|
||||
"UserIDClaim": "sub"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"Serial": "30",
|
||||
"peerConfig": {
|
||||
"address": "100.64.0.99/10",
|
||||
"sshConfig": {},
|
||||
"fqdn": "proxy-peer.netbird.test",
|
||||
"RoutingPeerDnsResolutionEnabled": true,
|
||||
"autoUpdate": {}
|
||||
},
|
||||
"remotePeers": [
|
||||
{
|
||||
"wgPubKey": "/wFxrqMtMwWNZak/f0UDddUkCZMTmxNuiuk4/RGGNcY=",
|
||||
"allowedIps": [
|
||||
"100.64.0.10/32"
|
||||
],
|
||||
"sshConfig": {},
|
||||
"fqdn": "app-peer.netbird.test",
|
||||
"agentVersion": "0.60.0"
|
||||
}
|
||||
],
|
||||
"DNSConfig": {
|
||||
"ServiceEnable": true,
|
||||
"CustomZones": [
|
||||
{
|
||||
"Domain": "netbird.test.",
|
||||
"Records": [
|
||||
{
|
||||
"Name": "app-peer.netbird.test",
|
||||
"Type": "1",
|
||||
"Class": "IN",
|
||||
"TTL": "300",
|
||||
"RData": "100.64.0.10"
|
||||
},
|
||||
{
|
||||
"Name": "proxy-peer.netbird.test",
|
||||
"Type": "1",
|
||||
"Class": "IN",
|
||||
"TTL": "300",
|
||||
"RData": "100.64.0.99"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ForwarderPort": "22054"
|
||||
},
|
||||
"FirewallRules": [
|
||||
{
|
||||
"PeerIP": "100.64.0.10",
|
||||
"Direction": "OUT",
|
||||
"Protocol": "TCP",
|
||||
"PortInfo": {
|
||||
"range": {
|
||||
"start": 8080,
|
||||
"end": 8080
|
||||
}
|
||||
},
|
||||
"PolicyID": "cHJveHktYWNjZXNzLXN2Yy0xLXByb3h5LXBlZXIt"
|
||||
}
|
||||
],
|
||||
"routesFirewallRulesIsEmpty": true,
|
||||
"sshAuth": {
|
||||
"UserIDClaim": "sub"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"Network": {"Serial": 30},
|
||||
"AccountSettings": {"RoutingPeerDNSResolutionEnabled": true},
|
||||
"Peers": {
|
||||
"proxy-peer": {
|
||||
"IP": "100.64.0.99",
|
||||
"Meta": {"WtVersion": "0.60.0"},
|
||||
"ProxyMeta": {"Embedded": true, "Cluster": "eu.proxy.netbird.io"}
|
||||
},
|
||||
"app-peer": {"IP": "100.64.0.10", "Meta": {"WtVersion": "0.60.0"}}
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"ID": "svc-1",
|
||||
"Enabled": true,
|
||||
"Mode": "http",
|
||||
"ProxyCluster": "eu.proxy.netbird.io",
|
||||
"Targets": [
|
||||
{
|
||||
"Enabled": true,
|
||||
"Port": 8080,
|
||||
"Protocol": "http",
|
||||
"TargetID": "app-peer",
|
||||
"TargetType": "peer"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"description": "A private reverse-proxy service. The private-access ACL is synthesised from Services, never loaded from the policies table, and is what lets the service's AccessGroups reach the cluster's embedded proxy peer on TCP 80 and 443: user-peer gets OUT rules on both ports and proxy-peer the matching IN rules. Without the synthesis both maps are empty of each other.",
|
||||
"peers": [
|
||||
"user-peer",
|
||||
"proxy-peer"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"Network": {"Serial": 31},
|
||||
"AccountSettings": {"RoutingPeerDNSResolutionEnabled": true},
|
||||
"Peers": {
|
||||
"user-peer": {"IP": "100.64.0.10", "Meta": {"WtVersion": "0.60.0"}},
|
||||
"other-peer": {"IP": "100.64.0.11", "Meta": {"WtVersion": "0.60.0"}},
|
||||
"proxy-peer": {
|
||||
"IP": "100.64.0.99",
|
||||
"Meta": {"WtVersion": "0.60.0"},
|
||||
"ProxyMeta": {"Embedded": true, "Cluster": "eu.proxy.netbird.io"}
|
||||
}
|
||||
},
|
||||
"Groups": {
|
||||
"grp-admins": {"Peers": ["user-peer"]}
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"ID": "svc-1",
|
||||
"Enabled": true,
|
||||
"Private": true,
|
||||
"Mode": "http",
|
||||
"ProxyCluster": "eu.proxy.netbird.io",
|
||||
"AccessGroups": ["grp-admins", "grp-deleted"]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user