mirror of
https://github.com/gravitl/netmaker.git
synced 2025-09-15 01:24:41 +08:00
Merge pull request #3168 from gravitl/NET-1615-ext
NET-1615: ExtClients Acls
This commit is contained in:
commit
505f31e7e9
9 changed files with 216 additions and 9 deletions
|
@ -452,6 +452,7 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
extclient.OwnerID = userName
|
||||
extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
|
||||
extclient.IngressGatewayID = nodeid
|
||||
extclient.Network = node.Network
|
||||
extclient.Tags = make(map[models.TagID]struct{})
|
||||
extclient.Tags[models.TagID(fmt.Sprintf("%s.%s", extclient.Network,
|
||||
models.RemoteAccessTagName))] = struct{}{}
|
||||
|
@ -459,8 +460,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
|
|||
if (extclient.DNS == "") && (node.IngressDNS != "") {
|
||||
extclient.DNS = node.IngressDNS
|
||||
}
|
||||
|
||||
extclient.Network = node.Network
|
||||
host, err := logic.GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
|
|
|
@ -590,6 +590,7 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|||
if err := mq.NodeUpdate(&node); err != nil {
|
||||
slog.Error("error publishing node update to node", "node", node.ID, "error", err)
|
||||
}
|
||||
mq.PublishPeerUpdate(false)
|
||||
}()
|
||||
}
|
||||
|
||||
|
@ -634,6 +635,7 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
|||
if err := mq.PublishSingleHostPeerUpdate(host, allNodes, nil, removedClients[:], false, nil); err != nil {
|
||||
slog.Error("publishSingleHostUpdate", "host", host.Name, "error", err)
|
||||
}
|
||||
mq.PublishPeerUpdate(false)
|
||||
if err := mq.NodeUpdate(&node); err != nil {
|
||||
slog.Error(
|
||||
"error publishing node update to node",
|
||||
|
@ -749,6 +751,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||
logger.Log(0, "error during node ACL update for node", newNode.ID.String())
|
||||
}
|
||||
}
|
||||
mq.PublishPeerUpdate(false)
|
||||
if servercfg.IsDNSMode() {
|
||||
logic.SetDNS()
|
||||
}
|
||||
|
|
|
@ -451,6 +451,7 @@ func createUser(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
logic.DeleteUserInvite(user.UserName)
|
||||
logic.DeletePendingUser(user.UserName)
|
||||
go mq.PublishPeerUpdate(false)
|
||||
slog.Info("user was created", "username", user.UserName)
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(user))
|
||||
}
|
||||
|
@ -590,6 +591,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
go mq.PublishPeerUpdate(false)
|
||||
logger.Log(1, username, "was updated")
|
||||
json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
|
||||
}
|
||||
|
@ -692,6 +694,7 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
}
|
||||
mq.PublishPeerUpdate(false)
|
||||
if servercfg.IsDNSMode() {
|
||||
logic.SetDNS()
|
||||
}
|
||||
|
|
|
@ -441,16 +441,26 @@ func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} {
|
|||
|
||||
// IsUserAllowedToCommunicate - check if user is allowed to communicate with peer
|
||||
func IsUserAllowedToCommunicate(userName string, peer models.Node) bool {
|
||||
acl, _ := GetDefaultPolicy(models.NetworkID(peer.Network), models.UserPolicy)
|
||||
if acl.Enabled {
|
||||
return true
|
||||
}
|
||||
user, err := GetUser(userName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if peer.IsStatic {
|
||||
peer = peer.StaticNode.ConvertToStaticNode()
|
||||
}
|
||||
policies := listPoliciesOfUser(*user, models.NetworkID(peer.Network))
|
||||
for _, policy := range policies {
|
||||
if !policy.Enabled {
|
||||
continue
|
||||
}
|
||||
dstMap := convAclTagToValueMap(policy.Dst)
|
||||
if _, ok := dstMap["*"]; ok {
|
||||
return true
|
||||
}
|
||||
for tagID := range peer.Tags {
|
||||
if _, ok := dstMap[tagID.String()]; ok {
|
||||
return true
|
||||
|
@ -470,6 +480,12 @@ func IsNodeAllowedToCommunicate(node, peer models.Node) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
if node.IsStatic {
|
||||
node = node.StaticNode.ConvertToStaticNode()
|
||||
}
|
||||
if peer.IsStatic {
|
||||
peer = peer.StaticNode.ConvertToStaticNode()
|
||||
}
|
||||
// list device policies
|
||||
policies := listDevicePolicies(models.NetworkID(peer.Network))
|
||||
for _, policy := range policies {
|
||||
|
|
|
@ -136,6 +136,12 @@ func DeleteExtClientAndCleanup(extClient models.ExtClient) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//TODO - enforce extclient-to-extclient on ingress gw
|
||||
/* 1. fetch all non-user static nodes
|
||||
a. check against each user node, if allowed add rule
|
||||
|
||||
*/
|
||||
|
||||
// GetNetworkExtClients - gets the ext clients of given network
|
||||
func GetNetworkExtClients(network string) ([]models.ExtClient, error) {
|
||||
var extclients []models.ExtClient
|
||||
|
@ -396,6 +402,124 @@ func ToggleExtClientConnectivity(client *models.ExtClient, enable bool) (models.
|
|||
return newClient, nil
|
||||
}
|
||||
|
||||
func GetStaticNodeIps(node models.Node) (ips []net.IP) {
|
||||
extclients := GetStaticNodesByNetwork(models.NetworkID(node.Network), false)
|
||||
for _, extclient := range extclients {
|
||||
if extclient.StaticNode.Address != "" {
|
||||
ips = append(ips, extclient.StaticNode.AddressIPNet4().IP)
|
||||
}
|
||||
if extclient.StaticNode.Address6 != "" {
|
||||
ips = append(ips, extclient.StaticNode.AddressIPNet6().IP)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
|
||||
// fetch user access to static clients via policies
|
||||
|
||||
nodes, _ := GetNetworkNodes(node.Network)
|
||||
nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...)
|
||||
userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network))
|
||||
for _, userNodeI := range userNodes {
|
||||
for _, peer := range nodes {
|
||||
if peer.IsUserNode {
|
||||
continue
|
||||
}
|
||||
if IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, peer) {
|
||||
if peer.IsStatic {
|
||||
if userNodeI.StaticNode.Address != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: userNodeI.StaticNode.AddressIPNet4().IP,
|
||||
DstIP: peer.StaticNode.AddressIPNet4().IP,
|
||||
Allow: true,
|
||||
})
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: peer.StaticNode.AddressIPNet4().IP,
|
||||
DstIP: userNodeI.StaticNode.AddressIPNet4().IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
if userNodeI.StaticNode.Address6 != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: userNodeI.StaticNode.AddressIPNet6().IP,
|
||||
DstIP: peer.StaticNode.AddressIPNet6().IP,
|
||||
Allow: true,
|
||||
})
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: peer.StaticNode.AddressIPNet6().IP,
|
||||
DstIP: userNodeI.StaticNode.AddressIPNet6().IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if userNodeI.StaticNode.Address != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: userNodeI.StaticNode.AddressIPNet4().IP,
|
||||
DstIP: peer.Address.IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
if userNodeI.StaticNode.Address6 != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: userNodeI.StaticNode.AddressIPNet6().IP,
|
||||
DstIP: peer.Address6.IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, nodeI := range nodes {
|
||||
if !nodeI.IsStatic || nodeI.IsUserNode {
|
||||
continue
|
||||
}
|
||||
for _, peer := range nodes {
|
||||
if peer.StaticNode.ClientID == nodeI.StaticNode.ClientID || peer.IsUserNode {
|
||||
continue
|
||||
}
|
||||
if IsNodeAllowedToCommunicate(nodeI, peer) {
|
||||
if peer.IsStatic {
|
||||
if nodeI.StaticNode.Address != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: nodeI.StaticNode.AddressIPNet4().IP,
|
||||
DstIP: peer.StaticNode.AddressIPNet4().IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
if nodeI.StaticNode.Address6 != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: nodeI.StaticNode.AddressIPNet6().IP,
|
||||
DstIP: peer.StaticNode.AddressIPNet6().IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if nodeI.StaticNode.Address != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: nodeI.StaticNode.AddressIPNet4().IP,
|
||||
DstIP: peer.Address.IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
if nodeI.StaticNode.Address6 != "" {
|
||||
rules = append(rules, models.FwRule{
|
||||
SrcIp: nodeI.StaticNode.AddressIPNet6().IP,
|
||||
DstIP: peer.Address6.IP,
|
||||
Allow: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) {
|
||||
var peers []wgtypes.PeerConfig
|
||||
var idsAndAddr []models.IDandAddr
|
||||
|
@ -503,6 +627,9 @@ func getExtpeersExtraRoutes(node models.Node, network string) (egressRoutes []mo
|
|||
if len(extPeer.ExtraAllowedIPs) == 0 {
|
||||
continue
|
||||
}
|
||||
if !IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), node) {
|
||||
continue
|
||||
}
|
||||
egressRoutes = append(egressRoutes, getExtPeerEgressRoute(node, extPeer)...)
|
||||
}
|
||||
return
|
||||
|
@ -540,13 +667,37 @@ func GetExtclientAllowedIPs(client models.ExtClient) (allowedIPs []string) {
|
|||
return
|
||||
}
|
||||
|
||||
func GetStaticNodesByNetwork(network models.NetworkID) (staticNode []models.Node) {
|
||||
func GetStaticUserNodesByNetwork(network models.NetworkID) (staticNode []models.Node) {
|
||||
extClients, err := GetAllExtClients()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, extI := range extClients {
|
||||
if extI.Network == network.String() {
|
||||
if extI.RemoteAccessClientID != "" {
|
||||
n := models.Node{
|
||||
IsStatic: true,
|
||||
StaticNode: extI,
|
||||
IsUserNode: extI.RemoteAccessClientID != "",
|
||||
}
|
||||
staticNode = append(staticNode, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GetStaticNodesByNetwork(network models.NetworkID, onlyWg bool) (staticNode []models.Node) {
|
||||
extClients, err := GetAllExtClients()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, extI := range extClients {
|
||||
if extI.Network == network.String() {
|
||||
if onlyWg && extI.RemoteAccessClientID != "" {
|
||||
continue
|
||||
}
|
||||
n := models.Node{
|
||||
IsStatic: true,
|
||||
StaticNode: extI,
|
||||
|
|
|
@ -385,7 +385,7 @@ func AddStaticNodestoList(nodes []models.Node) []models.Node {
|
|||
continue
|
||||
}
|
||||
if node.IsIngressGateway {
|
||||
nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network))...)
|
||||
nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), false)...)
|
||||
netMap[node.Network] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
|
|||
ServerVersion: servercfg.GetVersion(),
|
||||
ServerAddrs: []models.ServerAddr{},
|
||||
FwUpdate: models.FwUpdate{
|
||||
EgressInfo: make(map[string]models.EgressInfo),
|
||||
EgressInfo: make(map[string]models.EgressInfo),
|
||||
IngressInfo: make(map[string]models.IngressInfo),
|
||||
},
|
||||
PeerIDs: make(models.PeerMap, 0),
|
||||
Peers: []wgtypes.PeerConfig{},
|
||||
|
@ -288,8 +289,22 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
|
|||
var extPeerIDAndAddrs []models.IDandAddr
|
||||
var egressRoutes []models.EgressNetworkRoutes
|
||||
if node.IsIngressGateway {
|
||||
hostPeerUpdate.FwUpdate.IsIngressGw = true
|
||||
extPeers, extPeerIDAndAddrs, egressRoutes, err = GetExtPeers(&node, &node)
|
||||
if err == nil {
|
||||
defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
|
||||
defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
|
||||
if !defaultDevicePolicy.Enabled || !defaultUserPolicy.Enabled {
|
||||
ingFwUpdate := models.IngressInfo{
|
||||
IngressID: node.ID.String(),
|
||||
Network: node.NetworkRange,
|
||||
Network6: node.NetworkRange6,
|
||||
AllowAll: defaultDevicePolicy.Enabled && defaultUserPolicy.Default,
|
||||
StaticNodeIps: GetStaticNodeIps(node),
|
||||
Rules: GetFwRulesOnIngressGateway(node),
|
||||
}
|
||||
hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = ingFwUpdate
|
||||
}
|
||||
hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...)
|
||||
hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...)
|
||||
for _, extPeerIdAndAddr := range extPeerIDAndAddrs {
|
||||
|
|
|
@ -26,10 +26,20 @@ type HostPeerUpdate struct {
|
|||
EndpointDetection bool `json:"endpoint_detection"`
|
||||
}
|
||||
|
||||
type FwRule struct {
|
||||
SrcIp net.IP
|
||||
DstIP net.IP
|
||||
Allow bool
|
||||
}
|
||||
|
||||
// IngressInfo - struct for ingress info
|
||||
type IngressInfo struct {
|
||||
ExtPeers map[string]ExtClientInfo `json:"ext_peers" yaml:"ext_peers"`
|
||||
EgressRanges []string `json:"egress_ranges" yaml:"egress_ranges"`
|
||||
IngressID string `json:"ingress_id"`
|
||||
Network net.IPNet `json:"network"`
|
||||
Network6 net.IPNet `json:"network6"`
|
||||
StaticNodeIps []net.IP `json:"static_node_ips"`
|
||||
Rules []FwRule `json:"rules"`
|
||||
AllowAll bool `json:"allow_all"`
|
||||
}
|
||||
|
||||
// EgressInfo - struct for egress info
|
||||
|
@ -77,8 +87,10 @@ type KeyUpdate struct {
|
|||
|
||||
// FwUpdate - struct for firewall updates
|
||||
type FwUpdate struct {
|
||||
IsEgressGw bool `json:"is_egress_gw"`
|
||||
EgressInfo map[string]EgressInfo `json:"egress_info"`
|
||||
IsEgressGw bool `json:"is_egress_gw"`
|
||||
IsIngressGw bool `json:"is_ingress_gw"`
|
||||
EgressInfo map[string]EgressInfo `json:"egress_info"`
|
||||
IngressInfo map[string]IngressInfo `json:"ingress_info"`
|
||||
}
|
||||
|
||||
// FailOverMeReq - struct for failover req
|
||||
|
|
|
@ -519,6 +519,14 @@ func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
if user.IsAdmin || user.IsSuperAdmin {
|
||||
for _, node := range nodes {
|
||||
if node.IsIngressGateway {
|
||||
gws[node.ID.String()] = node
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
tagNodesMap := logic.GetTagMapWithNodes()
|
||||
accessPolices := logic.ListUserPolicies(user)
|
||||
for _, policyI := range accessPolices {
|
||||
|
|
Loading…
Add table
Reference in a new issue