From db4cf1d1fd016bb08c0299074420df312e129a9f Mon Sep 17 00:00:00 2001 From: Max Ma Date: Fri, 6 Sep 2024 16:48:24 +0200 Subject: [PATCH 001/169] NET-1534:upgrade Caddy to v2.8.4 (#3097) * upgrade Caddy to v2.8.4 * add BATCH_PEER_UPDATE in netmaker.env with default values * add comment for emqx for caddy upgrade change --- compose/docker-compose.yml | 2 +- docker/Caddyfile | 8 ++++++-- docker/Caddyfile-pro | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/compose/docker-compose.yml b/compose/docker-compose.yml index 3111f1f5f..e32481393 100644 --- a/compose/docker-compose.yml +++ b/compose/docker-compose.yml @@ -41,7 +41,7 @@ services: restart: always caddy: - image: caddy:2.6.2 + image: caddy:2.8.4 container_name: caddy env_file: ./netmaker.env restart: unless-stopped diff --git a/docker/Caddyfile b/docker/Caddyfile index 1226b72b3..9f5b35652 100644 --- a/docker/Caddyfile +++ b/docker/Caddyfile @@ -25,6 +25,10 @@ https://api.{$NM_DOMAIN} { } # MQ -wss://broker.{$NM_DOMAIN} { - reverse_proxy ws://mq:8883 # For EMQX websockets use `reverse_proxy ws://mq:8083` +broker.{$NM_DOMAIN} { + @ws { + header Connection *Upgrade* + header Upgrade websocket + } + reverse_proxy @ws mq:8883 # For EMQX websockets use `reverse_proxy @ws mq:8083` } diff --git a/docker/Caddyfile-pro b/docker/Caddyfile-pro index e986a8be5..226f61709 100644 --- a/docker/Caddyfile-pro +++ b/docker/Caddyfile-pro @@ -40,6 +40,10 @@ https://api.{$NM_DOMAIN} { } # MQ -wss://broker.{$NM_DOMAIN} { - reverse_proxy ws://mq:8883 +broker.{$NM_DOMAIN} { + @ws { + header Connection *Upgrade* + header Upgrade websocket + } + reverse_proxy @ws mq:8883 } From 3d7569b22bd6db1d22d9d46a4377960734012b8d Mon Sep 17 00:00:00 2001 From: Sayan Mallick Date: Mon, 9 Sep 2024 12:12:00 +0530 Subject: [PATCH 002/169] Updated to go1.23 (#3096) * Updated to go1.23 * Updated the go-version-file to have qoutes * Updated the gravitl/go-builder to 1.23 * versioned tag in Dockerfile * update go-builder workflow --- .github/workflows/docker-builder.yml | 11 ++++++----- .github/workflows/test.yml | 10 +++++----- Dockerfile | 2 +- docker/Dockerfile-go-builder | 2 +- go.mod | 2 +- models/names.go | 4 ++-- pro/types.go | 12 ++++++------ 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/.github/workflows/docker-builder.yml b/.github/workflows/docker-builder.yml index fe2cd4aae..5d401783e 100644 --- a/.github/workflows/docker-builder.yml +++ b/.github/workflows/docker-builder.yml @@ -2,10 +2,11 @@ name: Build go-builder images on: workflow_dispatch: - push: - branches: - - 'develop' - + inputs: + docker_tag: + description: 'Docker tag to use (default: latest)' + required: false + default: 'latest' jobs: go-builder: runs-on: ubuntu-latest @@ -26,4 +27,4 @@ jobs: push: true platforms: linux/amd64, linux/arm64, linux/arm/v7 file: ./docker/Dockerfile-go-builder - tags: gravitl/go-builder:latest + tags: gravitl/go-builder:${{ github.event.inputs.docker_tag || 'latest' }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f9acd2f1a..a9b90a91b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: 1.19 + go-version-file: 'go.mod' - name: Build run: | env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build main.go @@ -29,7 +29,7 @@ jobs: - name: Setup go uses: actions/setup-go@v5 with: - go-version: 1.19 + go-version-file: 'go.mod' - name: Build run: | cd cli @@ -46,7 +46,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: 1.19 + go-version-file: 'go.mod' - name: run tests run: | go vet ./... @@ -66,9 +66,9 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: 1.19 + go-version-file: 'go.mod' - name: run static checks run: | sudo apt update - go install honnef.co/go/tools/cmd/staticcheck@v0.4.7 + go install honnef.co/go/tools/cmd/staticcheck@latest { ~/go/bin/staticcheck -tags=ee ./... ; } diff --git a/Dockerfile b/Dockerfile index 3d80f5b99..47e78d29c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ #first stage - builder -FROM gravitl/go-builder AS builder +FROM gravitl/go-builder:1.23.0 AS builder ARG tags WORKDIR /app COPY . . diff --git a/docker/Dockerfile-go-builder b/docker/Dockerfile-go-builder index 0a19535fe..982f1e6ff 100644 --- a/docker/Dockerfile-go-builder +++ b/docker/Dockerfile-go-builder @@ -1,4 +1,4 @@ -FROM golang:1.20.13-alpine3.19 +FROM golang:1.23.0-alpine3.20 ARG version RUN apk add build-base WORKDIR /app diff --git a/go.mod b/go.mod index b5bcfe909..6802735e5 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gravitl/netmaker -go 1.19 +go 1.23 require ( github.com/eclipse/paho.mqtt.golang v1.4.3 diff --git a/models/names.go b/models/names.go index f5c1301fe..edf9b48cc 100644 --- a/models/names.go +++ b/models/names.go @@ -235,8 +235,8 @@ var logoString = retrieveLogo() // GenerateNodeName - generates a random node name func GenerateNodeName() string { - rand.Seed(time.Now().UnixNano()) - return SMALL_NAMES[rand.Intn(len(SMALL_NAMES))] + "-" + NAMES[seededRand.Intn(len(NAMES))] + rng := rand.New(rand.NewSource(time.Now().UnixNano())) + return SMALL_NAMES[rng.Intn(len(SMALL_NAMES))] + "-" + NAMES[rng.Intn(len(NAMES))] } // RetrieveLogo - retrieves the ascii art logo for Netmaker diff --git a/pro/types.go b/pro/types.go index b4f1fe15b..af1157470 100644 --- a/pro/types.go +++ b/pro/types.go @@ -4,7 +4,7 @@ package pro import ( - "fmt" + "errors" ) // constants for accounts api hosts @@ -23,7 +23,7 @@ const ( server_id_key = "nm-server-id" ) -var errValidation = fmt.Errorf(license_validation_err_msg) +var errValidation = errors.New(license_validation_err_msg) // LicenseKey - the license key struct representation with associated data type LicenseKey struct { @@ -42,14 +42,14 @@ type LicenseKey struct { // ValidatedLicense - the validated license struct type ValidatedLicense struct { - LicenseValue string `json:"license_value" binding:"required"` // license that validation is being requested for + LicenseValue string `json:"license_value" binding:"required"` // license that validation is being requested for EncryptedLicense string `json:"encrypted_license" binding:"required"` // to be decrypted by Netmaker using Netmaker server's private key } // LicenseSecret - the encrypted struct for sending user-id type LicenseSecret struct { AssociatedID string `json:"associated_id" binding:"required"` // UUID for user foreign key to User table - Usage Usage `json:"limits" binding:"required"` + Usage Usage `json:"limits" binding:"required"` } // Usage - struct for license usage @@ -81,9 +81,9 @@ func (l *Usage) SetDefaults() { // ValidateLicenseRequest - used for request to validate license endpoint type ValidateLicenseRequest struct { - LicenseKey string `json:"license_key" binding:"required"` + LicenseKey string `json:"license_key" binding:"required"` NmServerPubKey string `json:"nm_server_pub_key" binding:"required"` // Netmaker server public key used to send data back to Netmaker for the Netmaker server to decrypt (eg output from validating license) - EncryptedPart string `json:"secret" binding:"required"` + EncryptedPart string `json:"secret" binding:"required"` } type licenseResponseCache struct { From 189ac275270cf7e45536baf86544c3df33f1e556 Mon Sep 17 00:00:00 2001 From: Max Ma Date: Thu, 12 Sep 2024 10:19:27 +0200 Subject: [PATCH 003/169] NET-1509:add ingresspersistentkeepalive and ingressmtu for extClient/RAC config (#3107) * add ingresspersistentkeepalive and ingressmtu for extClient/RAC config * add ingressmtu and PKA in api response * add pka and mtu in api/nodes PUT call * add default value for PKA and mtu for extClients --- controllers/ext_client.go | 6 ++++ logic/gateway.go | 8 ++++++ models/api_node.go | 60 +++++++++++++++++++++------------------ models/node.go | 22 +++++++------- models/structs.go | 8 ++++-- 5 files changed, 64 insertions(+), 40 deletions(-) diff --git a/controllers/ext_client.go b/controllers/ext_client.go index b98256927..e9f9fa71c 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -244,6 +244,9 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { if network.DefaultKeepalive != 0 { keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive)) } + if gwnode.IngressPersistentKeepalive != 0 { + keepalive = "PersistentKeepalive = " + strconv.Itoa(int(gwnode.IngressPersistentKeepalive)) + } gwendpoint := "" if preferredIp == "" { @@ -289,6 +292,9 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { if host.MTU != 0 { defaultMTU = host.MTU } + if gwnode.IngressMTU != 0 { + defaultMTU = int(gwnode.IngressMTU) + } postUp := strings.Builder{} if client.PostUp != "" && params["type"] != "qr" { diff --git a/logic/gateway.go b/logic/gateway.go index 87a41105b..b25d3e1d0 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -164,6 +164,14 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq node.IngressGatewayRange = network.AddressRange node.IngressGatewayRange6 = network.AddressRange6 node.IngressDNS = ingress.ExtclientDNS + node.IngressPersistentKeepalive = 20 + if ingress.PersistentKeepalive != 0 { + node.IngressPersistentKeepalive = ingress.PersistentKeepalive + } + node.IngressMTU = 1420 + if ingress.MTU != 0 { + node.IngressMTU = ingress.MTU + } if servercfg.IsPro { if _, exists := FailOverExists(node.Network); exists { ResetFailedOverPeer(&node) diff --git a/models/api_node.go b/models/api_node.go index e7005f327..0c91bbeca 100644 --- a/models/api_node.go +++ b/models/api_node.go @@ -10,33 +10,35 @@ import ( // ApiNode is a stripped down Node DTO that exposes only required fields to external systems type ApiNode struct { - ID string `json:"id,omitempty" validate:"required,min=5,id_unique"` - HostID string `json:"hostid,omitempty" validate:"required,min=5,id_unique"` - Address string `json:"address" validate:"omitempty,cidrv4"` - Address6 string `json:"address6" validate:"omitempty,cidrv6"` - LocalAddress string `json:"localaddress" validate:"omitempty,cidr"` - AllowedIPs []string `json:"allowedips"` - LastModified int64 `json:"lastmodified"` - ExpirationDateTime int64 `json:"expdatetime"` - LastCheckIn int64 `json:"lastcheckin"` - LastPeerUpdate int64 `json:"lastpeerupdate"` - Network string `json:"network"` - NetworkRange string `json:"networkrange"` - NetworkRange6 string `json:"networkrange6"` - IsRelayed bool `json:"isrelayed"` - IsRelay bool `json:"isrelay"` - RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"` - RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"` - IsEgressGateway bool `json:"isegressgateway"` - IsIngressGateway bool `json:"isingressgateway"` - EgressGatewayRanges []string `json:"egressgatewayranges"` - EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled"` - DNSOn bool `json:"dnson"` - IngressDns string `json:"ingressdns"` - Server string `json:"server"` - Connected bool `json:"connected"` - PendingDelete bool `json:"pendingdelete"` - Metadata string `json:"metadata"` + ID string `json:"id,omitempty" validate:"required,min=5,id_unique"` + HostID string `json:"hostid,omitempty" validate:"required,min=5,id_unique"` + Address string `json:"address" validate:"omitempty,cidrv4"` + Address6 string `json:"address6" validate:"omitempty,cidrv6"` + LocalAddress string `json:"localaddress" validate:"omitempty,cidr"` + AllowedIPs []string `json:"allowedips"` + LastModified int64 `json:"lastmodified"` + ExpirationDateTime int64 `json:"expdatetime"` + LastCheckIn int64 `json:"lastcheckin"` + LastPeerUpdate int64 `json:"lastpeerupdate"` + Network string `json:"network"` + NetworkRange string `json:"networkrange"` + NetworkRange6 string `json:"networkrange6"` + IsRelayed bool `json:"isrelayed"` + IsRelay bool `json:"isrelay"` + RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"` + RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"` + IsEgressGateway bool `json:"isegressgateway"` + IsIngressGateway bool `json:"isingressgateway"` + EgressGatewayRanges []string `json:"egressgatewayranges"` + EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled"` + DNSOn bool `json:"dnson"` + IngressDns string `json:"ingressdns"` + IngressPersistentKeepalive int32 `json:"ingresspersistentkeepalive"` + IngressMTU int32 `json:"ingressmtu"` + Server string `json:"server"` + Connected bool `json:"connected"` + PendingDelete bool `json:"pendingdelete"` + Metadata string `json:"metadata"` // == PRO == DefaultACL string `json:"defaultacl,omitempty" validate:"checkyesornoorunset"` IsFailOver bool `json:"is_fail_over"` @@ -72,6 +74,8 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node { convertedNode.IngressGatewayRange6 = currentNode.IngressGatewayRange6 convertedNode.DNSOn = a.DNSOn convertedNode.IngressDNS = a.IngressDns + convertedNode.IngressPersistentKeepalive = a.IngressPersistentKeepalive + convertedNode.IngressMTU = a.IngressMTU convertedNode.IsInternetGateway = a.IsInternetGateway convertedNode.EgressGatewayRequest = currentNode.EgressGatewayRequest convertedNode.EgressGatewayNatEnabled = currentNode.EgressGatewayNatEnabled @@ -162,6 +166,8 @@ func (nm *Node) ConvertToAPINode() *ApiNode { apiNode.EgressGatewayNatEnabled = nm.EgressGatewayNatEnabled apiNode.DNSOn = nm.DNSOn apiNode.IngressDns = nm.IngressDNS + apiNode.IngressPersistentKeepalive = nm.IngressPersistentKeepalive + apiNode.IngressMTU = nm.IngressMTU apiNode.Server = nm.Server apiNode.Connected = nm.Connected apiNode.PendingDelete = nm.PendingDelete diff --git a/models/node.go b/models/node.go index a15bc6c92..e5ea2cfc4 100644 --- a/models/node.go +++ b/models/node.go @@ -77,16 +77,18 @@ type CommonNode struct { // Node - a model of a network node type Node struct { CommonNode - PendingDelete bool `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"` - LastModified time.Time `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"` - LastCheckIn time.Time `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"` - LastPeerUpdate time.Time `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"` - ExpirationDateTime time.Time `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"` - EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"` - EgressGatewayRequest EgressGatewayRequest `json:"egressgatewayrequest" bson:"egressgatewayrequest" yaml:"egressgatewayrequest"` - IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"` - IngressGatewayRange6 string `json:"ingressgatewayrange6" bson:"ingressgatewayrange6" yaml:"ingressgatewayrange6"` - Metadata string `json:"metadata"` + PendingDelete bool `json:"pendingdelete" bson:"pendingdelete" yaml:"pendingdelete"` + LastModified time.Time `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"` + LastCheckIn time.Time `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"` + LastPeerUpdate time.Time `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"` + ExpirationDateTime time.Time `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"` + EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"` + EgressGatewayRequest EgressGatewayRequest `json:"egressgatewayrequest" bson:"egressgatewayrequest" yaml:"egressgatewayrequest"` + IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"` + IngressGatewayRange6 string `json:"ingressgatewayrange6" bson:"ingressgatewayrange6" yaml:"ingressgatewayrange6"` + IngressPersistentKeepalive int32 `json:"ingresspersistentkeepalive" bson:"ingresspersistentkeepalive" yaml:"ingresspersistentkeepalive"` + IngressMTU int32 `json:"ingressmtu" bson:"ingressmtu" yaml:"ingressmtu"` + Metadata string `json:"metadata"` // == PRO == DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"` OwnerID string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"` diff --git a/models/structs.go b/models/structs.go index decb65572..f8dd753f4 100644 --- a/models/structs.go +++ b/models/structs.go @@ -163,9 +163,11 @@ type HostRelayRequest struct { // IngressRequest - ingress request struct type IngressRequest struct { - ExtclientDNS string `json:"extclientdns"` - IsInternetGateway bool `json:"is_internet_gw"` - Metadata string `json:"metadata"` + ExtclientDNS string `json:"extclientdns"` + IsInternetGateway bool `json:"is_internet_gw"` + Metadata string `json:"metadata"` + PersistentKeepalive int32 `json:"persistentkeepalive"` + MTU int32 `json:"mtu"` } // InetNodeReq - exit node request struct From bb8e4e53e94d1a34cb2b994f9d65ecae0566deb3 Mon Sep 17 00:00:00 2001 From: Abhishek K Date: Thu, 12 Sep 2024 12:19:50 +0400 Subject: [PATCH 004/169] NET-1574: Pro install arg, handle enrollment key exists error (#3109) * generalise smtp config * copy over smtp vars * env new line * fix master key api access * comment user tests * fix network and user invite for master key access * remove email sender type * user mgmt commands * check user role on CE * user role nmtcl cmds * user groups commands * fix role and groups command * fix user create cmd * add usage info * rm user role check * fix user update cmd * fix static check * add backwards comptability support for extclient api for mobile * rm debug logs * set frontend url from base domain if empty * add flag to install pro * collect tenant id and license on pro install * collect tenant id and license on pro install * add install log * add pro arg to usage * add pro arg * get token if exists already * trim double quotes from netmaker tag * trim double quotes from netmaker token * use jq -r * copy license and tenant id from previous config * rename used tenant id var in script --- scripts/nm-quick.sh | 54 +++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh index 76fdea56a..17f2600ab 100755 --- a/scripts/nm-quick.sh +++ b/scripts/nm-quick.sh @@ -19,11 +19,13 @@ unset BUILD_TAG unset IMAGE_TAG unset NETMAKER_BASE_DOMAIN unset UPGRADE_FLAG +unset COLLECT_PRO_VARS # usage - displays usage instructions usage() { echo "nm-quick.sh v$NM_QUICK_VERSION" echo "usage: ./nm-quick.sh [-c]" echo " -c if specified, will install netmaker community version" + echo " -p if specified, will install netmaker pro version" echo " -u if specified, will upgrade netmaker to pro version" echo " -d if specified, will downgrade netmaker to community version" exit 1 @@ -236,7 +238,7 @@ save_config() { ( save_config_item UI_IMAGE_TAG "$IMAGE_TAG" # version-specific entries if [ "$INSTALL_TYPE" = "pro" ]; then - save_config_item NETMAKER_TENANT_ID "$TENANT_ID" + save_config_item NETMAKER_TENANT_ID "$NETMAKER_TENANT_ID" save_config_item LICENSE_KEY "$LICENSE_KEY" if [ "$UPGRADE_FLAG" = "yes" ];then save_config_item METRICS_EXPORTER "on" @@ -249,7 +251,7 @@ save_config() { ( save_config_item SERVER_IMAGE_TAG "$IMAGE_TAG" fi # copy entries from the previous config - local toCopy=("SERVER_HOST" "MASTER_KEY" "MQ_USERNAME" "MQ_PASSWORD" + local toCopy=("SERVER_HOST" "MASTER_KEY" "MQ_USERNAME" "MQ_PASSWORD" "LICENSE_KEY" "NETMAKER_TENANT_ID" "INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT" "CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY" "DEBUG_MODE" "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "ALLOWED_EMAIL_DOMAINS" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET" @@ -568,7 +570,17 @@ set_install_vars() { EMAIL="$GET_EMAIL" wait_seconds 1 - + if [ "$COLLECT_PRO_VARS" = "true" ]; then + unset LICENSE_KEY + while [ -z "$LICENSE_KEY" ]; do + read -p "License Key: " LICENSE_KEY + done + unset NETMAKER_TENANT_ID + while [ -z ${NETMAKER_TENANT_ID} ]; do + read -p "Tenant ID: " NETMAKER_TENANT_ID + done + fi + wait_seconds 1 unset GET_MQ_USERNAME unset GET_MQ_PASSWORD unset CONFIRM_MQ_PASSWORD @@ -729,22 +741,27 @@ setup_mesh() { echo "Creating netmaker network (10.101.0.0/16)" # TODO causes "Error Status: 400 Response: {"Code":400,"Message":"could not find any records"}" - nmctl network create --name netmaker --ipv4_addr 10.101.0.0/16 + nmctl network create --name netmaker --ipv4_addr 100.172.188.0/24 wait_seconds 5 fi echo "Obtaining a netmaker enrollment key..." - - local tokenJson=$(nmctl enrollment_key create --tags netmaker --unlimited --networks netmaker) - TOKEN=$(jq -r '.token' <<<${tokenJson}) - if test -z "$TOKEN"; then - echo "Error creating an enrollment key" - exit 1 + local netmakerTag=$(nmctl enrollment_key list | jq -r '.[] | .tags[0]') + if [ ${netmakerTag} = "netmaker" ]; then + # key exists already, fetch token + TOKEN=$(nmctl enrollment_key list | jq -r '.[] | select(.tags[0]=="netmaker") | .token') else - echo "Enrollment key ready" + local tokenJson=$(nmctl enrollment_key create --tags netmaker --unlimited --networks netmaker) + TOKEN=$(jq -r '.token' <<<${tokenJson}) + if test -z "$TOKEN"; then + echo "Error creating an enrollment key" + exit 1 + else + echo "Enrollment key ready" + fi fi - + wait_seconds 3 } @@ -813,9 +830,9 @@ upgrade() { while [ -z "$LICENSE_KEY" ]; do read -p "License Key: " LICENSE_KEY done - unset TENANT_ID - while [ -z ${TENANT_ID} ]; do - read -p "Tenant ID: " TENANT_ID + unset NETMAKER_TENANT_ID + while [ -z ${NETMAKER_TENANT_ID} ]; do + read -p "Tenant ID: " NETMAKER_TENANT_ID done save_config # start docker and rebuild containers / networks @@ -871,7 +888,7 @@ main (){ fi INSTALL_TYPE="pro" - while getopts :cudv flag; do + while getopts :cudpv flag; do case "${flag}" in c) INSTALL_TYPE="ce" @@ -889,6 +906,11 @@ main (){ downgrade exit 0 ;; + p) + echo "installing pro version..." + INSTALL_TYPE="pro" + COLLECT_PRO_VARS="true" + ;; v) usage exit 0 From 32994f69bcbcb3c6bdc287e9cd9b363ae7c22703 Mon Sep 17 00:00:00 2001 From: Max Ma Date: Thu, 12 Sep 2024 10:20:41 +0200 Subject: [PATCH 005/169] NET-1461:update peer info after extClient public key changed (#3088) * update peer info after extClient public key changed * peerUpdate after the extClient public key change --- controllers/ext_client.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/controllers/ext_client.go b/controllers/ext_client.go index e9f9fa71c..09c5f5d52 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -537,6 +537,7 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) { var update models.CustomExtClient //var oldExtClient models.ExtClient var sendPeerUpdate bool + var replacePeers bool err := json.NewDecoder(r.Body).Decode(&update) if err != nil { logger.Log(0, r.Header.Get("user"), "error decoding request body: ", @@ -594,6 +595,11 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) { if update.Enabled != oldExtClient.Enabled { sendPeerUpdate = true } + if update.PublicKey != oldExtClient.PublicKey { + //remove old peer entry + sendPeerUpdate = true + replacePeers = true + } newclient := logic.UpdateExtClient(&oldExtClient, &update) if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil { slog.Error( @@ -633,6 +639,11 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) { if changedID && servercfg.IsDNSMode() { logic.SetDNS() } + if replacePeers { + if err := mq.PublishDeletedClientPeerUpdate(&oldExtClient); err != nil { + slog.Error("error deleting old ext peers", "error", err.Error()) + } + } if sendPeerUpdate { // need to send a peer update to the ingress node as enablement of one of it's clients has changed ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID) if err == nil { From c0c61dd0f2fec09be4b9718b2794e0011b50b6fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 08:25:17 +0000 Subject: [PATCH 006/169] Bump golang.org/x/oauth2 from 0.21.0 to 0.23.0 Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.21.0 to 0.23.0. - [Commits](https://github.com/golang/oauth2/compare/v0.21.0...v0.23.0) --- updated-dependencies: - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6802735e5..448821a38 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/txn2/txeh v1.5.5 golang.org/x/crypto v0.23.0 golang.org/x/net v0.23.0 // indirect - golang.org/x/oauth2 v0.21.0 + golang.org/x/oauth2 v0.23.0 golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb diff --git a/go.sum b/go.sum index 33d5e376a..19387c638 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,7 @@ github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcP github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -107,8 +108,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From a2612f38aa22b9560c925805b7ed96f89258d95b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:29:33 +0400 Subject: [PATCH 007/169] Bump github.com/posthog/posthog-go (#3095) Bumps [github.com/posthog/posthog-go](https://github.com/posthog/posthog-go) from 0.0.0-20211028072449-93c17c49e2b0 to 1.2.21. - [Release notes](https://github.com/posthog/posthog-go/releases) - [Changelog](https://github.com/PostHog/posthog-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/posthog/posthog-go/commits/v1.2.21) --- updated-dependencies: - dependency-name: github.com/posthog/posthog-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 +-- go.sum | 13 +++---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 6802735e5..ea09b3123 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 github.com/c-robinson/iplib v1.0.8 - github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0 + github.com/posthog/posthog-go v1.2.21 ) require ( @@ -53,7 +53,6 @@ require ( github.com/rivo/uniseg v0.2.0 // indirect github.com/seancfoley/bintree v1.3.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect ) diff --git a/go.sum b/go.sum index 33d5e376a..c114fc923 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,10 @@ cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2Qx cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/c-robinson/iplib v1.0.8 h1:exDRViDyL9UBLcfmlxxkY5odWX5092nPsQIykHXhIn4= github.com/c-robinson/iplib v1.0.8/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -21,6 +19,7 @@ github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcP github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= @@ -61,20 +60,18 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0 h1:Y2hUrkfuM0on62KZOci/VLijlkdF/yeWU262BQgvcjE= -github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0/go.mod h1:oa2sAs9tGai3VldabTV0eWejt/O4/OOD7azP8GaikqU= +github.com/posthog/posthog-go v1.2.21 h1:p2ea0l+Qwtk+VC2LCAI87Dz36vwj9i+QHw5s6CpRikA= +github.com/posthog/posthog-go v1.2.21/go.mod h1:uYC2l1Yktc8E+9FAHJ9QZG4vQf/NHJPD800Hsm7DzoM= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa h1:hxMLFbj+F444JAS5nUQxTDZwUxwCRqg3WkNqhiDzXrM= github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seancfoley/bintree v1.3.1 h1:cqmmQK7Jm4aw8gna0bP+huu5leVOgHGSJBEpUx3EXGI= github.com/seancfoley/bintree v1.3.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU= github.com/seancfoley/ipaddress-go v1.6.0 h1:9z7yGmOnV4P2ML/dlR/kCJiv5tp8iHOOetJvxJh/R5w= github.com/seancfoley/ipaddress-go v1.6.0/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= @@ -87,9 +84,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/txn2/txeh v1.5.5 h1:UN4e/lCK5HGw/gGAi2GCVrNKg0GTCUWs7gs5riaZlz4= github.com/txn2/txeh v1.5.5/go.mod h1:qYzGG9kCzeVEI12geK4IlanHWY8X4uy/I3NcW7mk8g4= -github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= -github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -150,7 +144,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 2c11955c5f0af2c5121b6fafb388cf1e7ca6c6fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:30:18 +0400 Subject: [PATCH 008/169] Bump peter-evans/create-pull-request from 6 to 7 (#3118) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6 to 7. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v6...v7) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 66f274b6f..3ecd9feca 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -36,7 +36,7 @@ jobs: run: echo "timestamp=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: "Update documentation ${{ steps.timestamp.outputs.timestamp }}" From dcf15681bac75a567108ccc27583c1c31366aa9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:00:17 +0400 Subject: [PATCH 009/169] Bump alpine from 3.20.2 to 3.20.3 (#3117) Bumps alpine from 3.20.2 to 3.20.3. --- updated-dependencies: - dependency-name: alpine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- Dockerfile-quick | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 47e78d29c..f012ac3fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ COPY . . RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} . # RUN go build -tags=ee . -o netmaker main.go -FROM alpine:3.20.2 +FROM alpine:3.20.3 # add a c lib # set the working directory diff --git a/Dockerfile-quick b/Dockerfile-quick index 328f3a32e..10f4f9808 100644 --- a/Dockerfile-quick +++ b/Dockerfile-quick @@ -1,5 +1,5 @@ #first stage - builder -FROM alpine:3.20.2 +FROM alpine:3.20.3 ARG version WORKDIR /app COPY ./netmaker /root/netmaker From 1ed8e870f4020fce8d7c47e877e5b6f12692e10c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:01:01 +0400 Subject: [PATCH 010/169] Bump golang.org/x/crypto from 0.23.0 to 0.27.0 (#3115) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.23.0 to 0.27.0. - [Commits](https://github.com/golang/crypto/compare/v0.23.0...v0.27.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ce213681d..1fac9c401 100644 --- a/go.mod +++ b/go.mod @@ -16,11 +16,11 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/txn2/txeh v1.5.5 - golang.org/x/crypto v0.23.0 + golang.org/x/crypto v0.27.0 golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.23.0 - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb gopkg.in/yaml.v3 v3.0.1 ) @@ -65,5 +65,5 @@ require ( github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sync v0.7.0 // indirect + golang.org/x/sync v0.8.0 // indirect ) diff --git a/go.sum b/go.sum index 6d831cad3..8a636b020 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -106,8 +106,8 @@ golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -116,8 +116,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -129,8 +129,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From 7b56e24ec681905210437b60d867742d56c35f9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:01:12 +0400 Subject: [PATCH 011/169] Bump github.com/seancfoley/ipaddress-go from 1.6.0 to 1.7.0 (#3071) Bumps [github.com/seancfoley/ipaddress-go](https://github.com/seancfoley/ipaddress-go) from 1.6.0 to 1.7.0. - [Release notes](https://github.com/seancfoley/ipaddress-go/releases) - [Commits](https://github.com/seancfoley/ipaddress-go/compare/v1.6.0...v1.7.0) --- updated-dependencies: - dependency-name: github.com/seancfoley/ipaddress-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1fac9c401..dc839b18e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/lib/pq v1.10.9 github.com/mattn/go-sqlite3 v1.14.22 github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa - github.com/seancfoley/ipaddress-go v1.6.0 + github.com/seancfoley/ipaddress-go v1.7.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/txn2/txeh v1.5.5 diff --git a/go.sum b/go.sum index 8a636b020..4ed81328a 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa/go.mod h1:xF/KoXmr github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seancfoley/bintree v1.3.1 h1:cqmmQK7Jm4aw8gna0bP+huu5leVOgHGSJBEpUx3EXGI= github.com/seancfoley/bintree v1.3.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU= -github.com/seancfoley/ipaddress-go v1.6.0 h1:9z7yGmOnV4P2ML/dlR/kCJiv5tp8iHOOetJvxJh/R5w= -github.com/seancfoley/ipaddress-go v1.6.0/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw= +github.com/seancfoley/ipaddress-go v1.7.0 h1:vWp3SR3k+HkV3aKiNO2vEe6xbVxS0x/Ixw6hgyP238s= +github.com/seancfoley/ipaddress-go v1.7.0/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= From 1903a49768c7adfa92ae1b99eac60516c8e1a53e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:04:57 +0400 Subject: [PATCH 012/169] Bump github.com/eclipse/paho.mqtt.golang from 1.4.3 to 1.5.0 (#3070) Bumps [github.com/eclipse/paho.mqtt.golang](https://github.com/eclipse/paho.mqtt.golang) from 1.4.3 to 1.5.0. - [Release notes](https://github.com/eclipse/paho.mqtt.golang/releases) - [Commits](https://github.com/eclipse/paho.mqtt.golang/compare/v1.4.3...v1.5.0) --- updated-dependencies: - dependency-name: github.com/eclipse/paho.mqtt.golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index dc839b18e..30bd1a001 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/gravitl/netmaker go 1.23 require ( - github.com/eclipse/paho.mqtt.golang v1.4.3 + github.com/eclipse/paho.mqtt.golang v1.5.0 github.com/go-playground/validator/v10 v10.22.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.6.0 @@ -17,7 +17,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/txn2/txeh v1.5.5 golang.org/x/crypto v0.27.0 - golang.org/x/net v0.23.0 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.23.0 golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect diff --git a/go.sum b/go.sum index 4ed81328a..6ee07bf27 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= -github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= +github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= +github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= @@ -99,8 +99,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 19d4fbaa249c4f77a0b8c75ae8474d7e2244786e Mon Sep 17 00:00:00 2001 From: Max Ma Date: Mon, 16 Sep 2024 16:41:11 +0200 Subject: [PATCH 013/169] NET-1497:set node lastcheckin after reboot (#3102) * set node lastcheckin after reboot * set node connected after reboot --- logic/nodes.go | 14 +++++++++----- serverctl/serverctl.go | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/logic/nodes.go b/logic/nodes.go index 75ad16a82..e241c6ccc 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -393,7 +393,7 @@ func GetNetworkByNode(node *models.Node) (models.Network, error) { } // SetNodeDefaults - sets the defaults of a node to avoid empty fields -func SetNodeDefaults(node *models.Node) { +func SetNodeDefaults(node *models.Node, resetConnected bool) { parentNetwork, _ := GetNetworkByNode(node) _, cidr, err := net.ParseCIDR(parentNetwork.AddressRange) @@ -413,8 +413,12 @@ func SetNodeDefaults(node *models.Node) { } node.SetLastModified() - node.SetLastCheckIn() - node.SetDefaultConnected() + if node.LastCheckIn.IsZero() { + node.SetLastCheckIn() + } + if resetConnected { + node.SetDefaultConnected() + } node.SetExpirationDateTime() } @@ -461,7 +465,7 @@ func GetDeletedNodeByID(uuid string) (models.Node, error) { return models.Node{}, err } - SetNodeDefaults(&node) + SetNodeDefaults(&node, true) return node, nil } @@ -531,7 +535,7 @@ func createNode(node *models.Node) error { } } - SetNodeDefaults(node) + SetNodeDefaults(node, true) defaultACLVal := acls.Allowed parentNetwork, err := GetNetwork(node.Network) diff --git a/serverctl/serverctl.go b/serverctl/serverctl.go index 1d445ddf3..3cedf72dd 100644 --- a/serverctl/serverctl.go +++ b/serverctl/serverctl.go @@ -40,7 +40,7 @@ func setNodeDefaults() error { return err } for i := range nodes { - logic.SetNodeDefaults(&nodes[i]) + logic.SetNodeDefaults(&nodes[i], false) logic.UpdateNode(&nodes[i], &nodes[i]) currentNodeACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(nodes[i].Network), nodeacls.NodeID(nodes[i].ID.String())) if (err != nil && (database.IsEmptyRecord(err) || strings.Contains(err.Error(), "no node ACL present"))) || currentNodeACL == nil { From d64f098181fa9297225d4e685741214026d8574f Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 17 Sep 2024 19:34:45 +0400 Subject: [PATCH 014/169] Tag CRUD APIs --- controllers/controller.go | 1 + controllers/tags.go | 80 +++++++++++++++++++++++++++++ database/database.go | 3 ++ logic/hosts.go | 32 ++++++++++++ logic/tags.go | 104 ++++++++++++++++++++++++++++++++++++++ models/host.go | 63 +++++++++++------------ models/tags.go | 26 ++++++++++ 7 files changed, 278 insertions(+), 31 deletions(-) create mode 100644 controllers/tags.go create mode 100644 logic/tags.go create mode 100644 models/tags.go diff --git a/controllers/controller.go b/controllers/controller.go index 75423b6e1..5a1396d3d 100644 --- a/controllers/controller.go +++ b/controllers/controller.go @@ -34,6 +34,7 @@ var HttpHandlers = []interface{}{ loggerHandlers, hostHandlers, enrollmentKeyHandlers, + tagHandlers, legacyHandlers, } diff --git a/controllers/tags.go b/controllers/tags.go new file mode 100644 index 000000000..5fb167b6d --- /dev/null +++ b/controllers/tags.go @@ -0,0 +1,80 @@ +package controller + +import ( + "encoding/json" + "net/http" + + "github.com/gorilla/mux" + "github.com/gravitl/netmaker/logger" + "github.com/gravitl/netmaker/logic" + "github.com/gravitl/netmaker/models" +) + +func tagHandlers(r *mux.Router) { + r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(getAllTags))). + Methods(http.MethodGet) + r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(createTag))). + Methods(http.MethodPost) + r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(updateTag))). + Methods(http.MethodPut) + +} + +// @Summary Get all Tag entries +// @Router /api/v1/tags [get] +// @Tags TAG +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func getAllTags(w http.ResponseWriter, r *http.Request) { + tags, err := logic.ListTagsWithHosts() + if err != nil { + logger.Log(0, r.Header.Get("user"), "failed to get all DNS entries: ", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + logic.SortTagEntrys(tags[:]) + logic.ReturnSuccessResponseWithJson(w, r, tags, "fetched all tags") +} + +// @Summary Create Tag +// @Router /api/v1/tags [post] +// @Tags TAG +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func createTag(w http.ResponseWriter, r *http.Request) { + var tag models.Tag + err := json.NewDecoder(r.Body).Decode(&tag) + if err != nil { + logger.Log(0, "error decoding request body: ", + err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + err = logic.InsertTag(tag) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + logic.ReturnSuccessResponseWithJson(w, r, tag, "created tag successfully") +} + +// @Summary Update Tag +// @Router /api/v1/tags [put] +// @Tags TAG +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func updateTag(w http.ResponseWriter, r *http.Request) { + var updateTag models.UpdateTagReq + err := json.NewDecoder(r.Body).Decode(&updateTag) + if err != nil { + logger.Log(0, "error decoding request body: ", + err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + go logic.UpdateTag(updateTag) + logic.ReturnSuccessResponse(w, r, "updating tags") +} diff --git a/database/database.go b/database/database.go index f8508b3f0..2a950b6c3 100644 --- a/database/database.go +++ b/database/database.go @@ -67,6 +67,8 @@ const ( PENDING_USERS_TABLE_NAME = "pending_users" // USER_INVITES - table for user invites USER_INVITES_TABLE_NAME = "user_invites" + // TAG_TABLE_NAME - table for tags + TAG_TABLE_NAME = "tags" // == ERROR CONSTS == // NO_RECORD - no singular result found NO_RECORD = "no result found" @@ -152,6 +154,7 @@ func createTables() { CreateTable(PENDING_USERS_TABLE_NAME) CreateTable(USER_PERMISSIONS_TABLE_NAME) CreateTable(USER_INVITES_TABLE_NAME) + CreateTable(TAG_TABLE_NAME) } func CreateTable(tableName string) error { diff --git a/logic/hosts.go b/logic/hosts.go index 0fa8887e9..b8a90e8c9 100644 --- a/logic/hosts.go +++ b/logic/hosts.go @@ -572,3 +572,35 @@ func SortApiHosts(unsortedHosts []models.ApiHost) { return unsortedHosts[i].ID < unsortedHosts[j].ID }) } + +func GetTagMapWithHosts() (tagHostMap map[models.TagID][]models.Host) { + tagHostMap = make(map[models.TagID][]models.Host) + hosts, _ := GetAllHosts() + for _, hostI := range hosts { + if hostI.Tags == nil { + continue + } + for hostTagID := range hostI.Tags { + if _, ok := tagHostMap[hostTagID]; ok { + tagHostMap[hostTagID] = append(tagHostMap[hostTagID], hostI) + } else { + tagHostMap[hostTagID] = []models.Host{hostI} + } + } + } + return +} + +func GetHostsWithTag(tagID models.TagID) map[string]models.Host { + hMap := make(map[string]models.Host) + hosts, _ := GetAllHosts() + for _, hostI := range hosts { + if hostI.Tags == nil { + continue + } + if _, ok := hostI.Tags[tagID]; ok { + hMap[hostI.ID.String()] = hostI + } + } + return hMap +} diff --git a/logic/tags.go b/logic/tags.go new file mode 100644 index 000000000..aad6d5cc3 --- /dev/null +++ b/logic/tags.go @@ -0,0 +1,104 @@ +package logic + +import ( + "encoding/json" + "fmt" + "sort" + + "github.com/gravitl/netmaker/database" + "github.com/gravitl/netmaker/models" +) + +func GetTag(tagID string) (models.Tag, error) { + data, err := database.FetchRecord(database.TAG_TABLE_NAME, tagID) + if err != nil && !database.IsEmptyRecord(err) { + return models.Tag{}, err + } + tag := models.Tag{} + err = json.Unmarshal([]byte(data), &tag) + if err != nil { + return tag, err + } + return tag, nil +} + +func InsertTag(tag models.Tag) error { + _, err := database.FetchRecord(database.TAG_TABLE_NAME, tag.ID.String()) + if err == nil { + return fmt.Errorf("tag `%s` exists already", tag.ID) + } + d, err := json.Marshal(tag) + if err != nil { + return err + } + return database.Insert(tag.ID.String(), string(d), database.TAG_TABLE_NAME) +} + +func DeleteTag(tagID string) error { + return database.DeleteRecord(database.TAG_TABLE_NAME, tagID) +} + +func ListTagsWithHosts() ([]models.TagListResp, error) { + tags, err := ListTags() + if err != nil { + return []models.TagListResp{}, err + } + tagsHostMap := GetTagMapWithHosts() + resp := []models.TagListResp{} + for _, tagI := range tags { + tagRespI := models.TagListResp{ + Tag: tagI, + UsedByCnt: len(tagsHostMap[tagI.ID]), + TaggedHosts: tagsHostMap[tagI.ID], + } + resp = append(resp, tagRespI) + } + return resp, nil +} + +func ListTags() ([]models.Tag, error) { + + data, err := database.FetchRecords(database.TAG_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Tag{}, err + } + tags := []models.Tag{} + for _, dataI := range data { + tag := models.Tag{} + err := json.Unmarshal([]byte(dataI), &tag) + if err != nil { + continue + } + tags = append(tags, tag) + } + return tags, nil +} + +func UpdateTag(req models.UpdateTagReq) { + tagHostsMap := GetHostsWithTag(req.ID) + for _, hostI := range req.TaggedHosts { + hostI := hostI + + if _, ok := tagHostsMap[hostI.ID.String()]; !ok { + if hostI.Tags == nil { + hostI.Tags = make(map[models.TagID]struct{}) + } + hostI.Tags[req.ID] = struct{}{} + UpsertHost(&hostI) + } else { + delete(tagHostsMap, hostI.ID.String()) + } + } + for _, deletedTaggedHost := range tagHostsMap { + deletedTaggedHost := deletedTaggedHost + delete(deletedTaggedHost.Tags, req.ID) + UpsertHost(&deletedTaggedHost) + } +} + +// SortTagEntrys - Sorts slice of Tag entries by their id +func SortTagEntrys(tags []models.TagListResp) { + sort.Slice(tags, func(i, j int) bool { + return tags[i].ID < tags[j].ID + }) +} diff --git a/models/host.go b/models/host.go index 2781dee0e..8b336dfad 100644 --- a/models/host.go +++ b/models/host.go @@ -41,37 +41,38 @@ const ( // Host - represents a host on the network type Host struct { - ID uuid.UUID `json:"id" yaml:"id"` - Verbosity int `json:"verbosity" yaml:"verbosity"` - FirewallInUse string `json:"firewallinuse" yaml:"firewallinuse"` - Version string `json:"version" yaml:"version"` - IPForwarding bool `json:"ipforwarding" yaml:"ipforwarding"` - DaemonInstalled bool `json:"daemoninstalled" yaml:"daemoninstalled"` - AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` - HostPass string `json:"hostpass" yaml:"hostpass"` - Name string `json:"name" yaml:"name"` - OS string `json:"os" yaml:"os"` - Interface string `json:"interface" yaml:"interface"` - Debug bool `json:"debug" yaml:"debug"` - ListenPort int `json:"listenport" yaml:"listenport"` - WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` - MTU int `json:"mtu" yaml:"mtu"` - PublicKey wgtypes.Key `json:"publickey" yaml:"publickey"` - MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"` - TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"` - Nodes []string `json:"nodes" yaml:"nodes"` - Interfaces []Iface `json:"interfaces" yaml:"interfaces"` - DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"` - EndpointIP net.IP `json:"endpointip" yaml:"endpointip"` - EndpointIPv6 net.IP `json:"endpointipv6" yaml:"endpointipv6"` - IsDocker bool `json:"isdocker" yaml:"isdocker"` - IsK8S bool `json:"isk8s" yaml:"isk8s"` - IsStaticPort bool `json:"isstaticport" yaml:"isstaticport"` - IsStatic bool `json:"isstatic" yaml:"isstatic"` - IsDefault bool `json:"isdefault" yaml:"isdefault"` - NatType string `json:"nat_type,omitempty" yaml:"nat_type,omitempty"` - TurnEndpoint *netip.AddrPort `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"` - PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"` + ID uuid.UUID `json:"id" yaml:"id"` + Verbosity int `json:"verbosity" yaml:"verbosity"` + FirewallInUse string `json:"firewallinuse" yaml:"firewallinuse"` + Version string `json:"version" yaml:"version"` + IPForwarding bool `json:"ipforwarding" yaml:"ipforwarding"` + DaemonInstalled bool `json:"daemoninstalled" yaml:"daemoninstalled"` + AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` + HostPass string `json:"hostpass" yaml:"hostpass"` + Name string `json:"name" yaml:"name"` + OS string `json:"os" yaml:"os"` + Interface string `json:"interface" yaml:"interface"` + Debug bool `json:"debug" yaml:"debug"` + ListenPort int `json:"listenport" yaml:"listenport"` + WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` + MTU int `json:"mtu" yaml:"mtu"` + PublicKey wgtypes.Key `json:"publickey" yaml:"publickey"` + MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"` + TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"` + Nodes []string `json:"nodes" yaml:"nodes"` + Interfaces []Iface `json:"interfaces" yaml:"interfaces"` + DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"` + EndpointIP net.IP `json:"endpointip" yaml:"endpointip"` + EndpointIPv6 net.IP `json:"endpointipv6" yaml:"endpointipv6"` + IsDocker bool `json:"isdocker" yaml:"isdocker"` + IsK8S bool `json:"isk8s" yaml:"isk8s"` + IsStaticPort bool `json:"isstaticport" yaml:"isstaticport"` + IsStatic bool `json:"isstatic" yaml:"isstatic"` + IsDefault bool `json:"isdefault" yaml:"isdefault"` + NatType string `json:"nat_type,omitempty" yaml:"nat_type,omitempty"` + TurnEndpoint *netip.AddrPort `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"` + PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"` + Tags map[TagID]struct{} `json:"tags" yaml:"tags"` } // FormatBool converts a boolean to a [yes|no] string diff --git a/models/tags.go b/models/tags.go new file mode 100644 index 000000000..ebd396c6c --- /dev/null +++ b/models/tags.go @@ -0,0 +1,26 @@ +package models + +import "time" + +type TagID string + +func (id TagID) String() string { + return string(id) +} + +type Tag struct { + ID TagID `json:"id"` + CreatedBy string `json:"created_by"` + CreatedAt time.Time `json:"created_at"` +} + +type TagListResp struct { + Tag + UsedByCnt int `json:"used_by_count"` + TaggedHosts []Host `json:"tagged_hosts"` +} + +type UpdateTagReq struct { + Tag + TaggedHosts []Host `json:"tagged_hosts"` +} From 99220fddd3845a526a974711cdb88945e0c6e3d6 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 18 Sep 2024 00:35:50 +0400 Subject: [PATCH 015/169] fix update tag handler --- controllers/tags.go | 36 +++++++++++++++++++++++++++++++++--- logic/tags.go | 14 ++++++++------ models/tags.go | 7 ++++++- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index 5fb167b6d..a356a8f2e 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -3,6 +3,7 @@ package controller import ( "encoding/json" "net/http" + "time" "github.com/gorilla/mux" "github.com/gravitl/netmaker/logger" @@ -44,20 +45,44 @@ func getAllTags(w http.ResponseWriter, r *http.Request) { // @Success 200 {array} models.SuccessResponse // @Failure 500 {object} models.ErrorResponse func createTag(w http.ResponseWriter, r *http.Request) { - var tag models.Tag - err := json.NewDecoder(r.Body).Decode(&tag) + var req models.CreateTagReq + err := json.NewDecoder(r.Body).Decode(&req) if err != nil { logger.Log(0, "error decoding request body: ", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + user, err := logic.GetUser(r.Header.Get("user")) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + go func() { + for _, hostID := range req.TaggedHosts { + h, err := logic.GetHost(hostID) + if err != nil { + continue + } + if h.Tags == nil { + h.Tags = make(map[models.TagID]struct{}) + } + h.Tags[req.ID] = struct{}{} + logic.UpsertHost(h) + } + }() + + tag := models.Tag{ + ID: req.ID, + CreatedBy: user.UserName, + CreatedAt: time.Now(), + } err = logic.InsertTag(tag) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - logic.ReturnSuccessResponseWithJson(w, r, tag, "created tag successfully") + logic.ReturnSuccessResponseWithJson(w, r, req, "created tag successfully") } // @Summary Update Tag @@ -75,6 +100,11 @@ func updateTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + _, err = logic.GetTag(updateTag.ID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } go logic.UpdateTag(updateTag) logic.ReturnSuccessResponse(w, r, "updating tags") } diff --git a/logic/tags.go b/logic/tags.go index aad6d5cc3..48efd032c 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -9,8 +9,8 @@ import ( "github.com/gravitl/netmaker/models" ) -func GetTag(tagID string) (models.Tag, error) { - data, err := database.FetchRecord(database.TAG_TABLE_NAME, tagID) +func GetTag(tagID models.TagID) (models.Tag, error) { + data, err := database.FetchRecord(database.TAG_TABLE_NAME, tagID.String()) if err != nil && !database.IsEmptyRecord(err) { return models.Tag{}, err } @@ -76,15 +76,17 @@ func ListTags() ([]models.Tag, error) { func UpdateTag(req models.UpdateTagReq) { tagHostsMap := GetHostsWithTag(req.ID) - for _, hostI := range req.TaggedHosts { - hostI := hostI - + for _, hostID := range req.TaggedHosts { + hostI, err := GetHost(hostID) + if err != nil { + continue + } if _, ok := tagHostsMap[hostI.ID.String()]; !ok { if hostI.Tags == nil { hostI.Tags = make(map[models.TagID]struct{}) } hostI.Tags[req.ID] = struct{}{} - UpsertHost(&hostI) + UpsertHost(hostI) } else { delete(tagHostsMap, hostI.ID.String()) } diff --git a/models/tags.go b/models/tags.go index ebd396c6c..84352f7f0 100644 --- a/models/tags.go +++ b/models/tags.go @@ -14,6 +14,11 @@ type Tag struct { CreatedAt time.Time `json:"created_at"` } +type CreateTagReq struct { + ID TagID `json:"id"` + TaggedHosts []string `json:"tagged_hosts"` +} + type TagListResp struct { Tag UsedByCnt int `json:"used_by_count"` @@ -22,5 +27,5 @@ type TagListResp struct { type UpdateTagReq struct { Tag - TaggedHosts []Host `json:"tagged_hosts"` + TaggedHosts []string `json:"tagged_hosts"` } From ee5d87733bf823422d8dcddbbfc601cbf1e5fbfb Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 18 Sep 2024 10:46:42 +0400 Subject: [PATCH 016/169] guard update tag with mutex --- logic/tags.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/logic/tags.go b/logic/tags.go index 48efd032c..553a14df1 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -4,11 +4,14 @@ import ( "encoding/json" "fmt" "sort" + "sync" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" ) +var tagMutex = &sync.RWMutex{} + func GetTag(tagID models.TagID) (models.Tag, error) { data, err := database.FetchRecord(database.TAG_TABLE_NAME, tagID.String()) if err != nil && !database.IsEmptyRecord(err) { @@ -39,6 +42,8 @@ func DeleteTag(tagID string) error { } func ListTagsWithHosts() ([]models.TagListResp, error) { + tagMutex.RLock() + defer tagMutex.RUnlock() tags, err := ListTags() if err != nil { return []models.TagListResp{}, err @@ -75,6 +80,8 @@ func ListTags() ([]models.Tag, error) { } func UpdateTag(req models.UpdateTagReq) { + tagMutex.Lock() + defer tagMutex.Unlock() tagHostsMap := GetHostsWithTag(req.ID) for _, hostID := range req.TaggedHosts { hostI, err := GetHost(hostID) From 3d392ee9b1b964abfcc097bd946a35ae1aa3a657 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 18 Sep 2024 11:08:47 +0400 Subject: [PATCH 017/169] add delete tag api --- controllers/tags.go | 24 ++++++++++++++++++++++++ logic/tags.go | 22 ++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index a356a8f2e..260305a49 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -2,7 +2,9 @@ package controller import ( "encoding/json" + "errors" "net/http" + "net/url" "time" "github.com/gorilla/mux" @@ -18,6 +20,8 @@ func tagHandlers(r *mux.Router) { Methods(http.MethodPost) r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(updateTag))). Methods(http.MethodPut) + r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(deleteTag))). + Methods(http.MethodDelete) } @@ -108,3 +112,23 @@ func updateTag(w http.ResponseWriter, r *http.Request) { go logic.UpdateTag(updateTag) logic.ReturnSuccessResponse(w, r, "updating tags") } + +// @Summary Delete Tag +// @Router /api/v1/tags [delete] +// @Tags TAG +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func deleteTag(w http.ResponseWriter, r *http.Request) { + tagID, _ := url.QueryUnescape(r.URL.Query().Get("tag_id")) + if tagID == "" { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest")) + return + } + err := logic.DeleteTag(models.TagID(tagID)) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + logic.ReturnSuccessResponse(w, r, "deleted tag "+tagID) +} diff --git a/logic/tags.go b/logic/tags.go index 553a14df1..10841e7fc 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -12,6 +12,7 @@ import ( var tagMutex = &sync.RWMutex{} +// GetTag - fetches tag info func GetTag(tagID models.TagID) (models.Tag, error) { data, err := database.FetchRecord(database.TAG_TABLE_NAME, tagID.String()) if err != nil && !database.IsEmptyRecord(err) { @@ -25,6 +26,7 @@ func GetTag(tagID models.TagID) (models.Tag, error) { return tag, nil } +// InsertTag - creates new tag func InsertTag(tag models.Tag) error { _, err := database.FetchRecord(database.TAG_TABLE_NAME, tag.ID.String()) if err == nil { @@ -37,10 +39,24 @@ func InsertTag(tag models.Tag) error { return database.Insert(tag.ID.String(), string(d), database.TAG_TABLE_NAME) } -func DeleteTag(tagID string) error { - return database.DeleteRecord(database.TAG_TABLE_NAME, tagID) +// DeleteTag - delete tag, will also untag hosts +func DeleteTag(tagID models.TagID) error { + // cleanUp tags on hosts + hosts, err := GetAllHosts() + if err != nil { + return err + } + for _, hostI := range hosts { + hostI := hostI + if _, ok := hostI.Tags[tagID]; ok { + delete(hostI.Tags, tagID) + UpsertHost(&hostI) + } + } + return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String()) } +// ListTagsWithHosts - lists all tags with tagged hosts func ListTagsWithHosts() ([]models.TagListResp, error) { tagMutex.RLock() defer tagMutex.RUnlock() @@ -61,6 +77,7 @@ func ListTagsWithHosts() ([]models.TagListResp, error) { return resp, nil } +// ListTags - lists all tags from DB func ListTags() ([]models.Tag, error) { data, err := database.FetchRecords(database.TAG_TABLE_NAME) @@ -79,6 +96,7 @@ func ListTags() ([]models.Tag, error) { return tags, nil } +// UpdateTag - updates and syncs hosts with tag update func UpdateTag(req models.UpdateTagReq) { tagMutex.Lock() defer tagMutex.Unlock() From 6640b66ac6d42e5f5bdfaabaf7fc193c02d68337 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 18 Sep 2024 11:16:13 +0400 Subject: [PATCH 018/169] add tag to api host --- models/api_host.go | 49 ++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/models/api_host.go b/models/api_host.go index 324bf9f8c..c84317105 100644 --- a/models/api_host.go +++ b/models/api_host.go @@ -8,29 +8,30 @@ import ( // ApiHost - the host struct for API usage type ApiHost struct { - ID string `json:"id"` - Verbosity int `json:"verbosity"` - FirewallInUse string `json:"firewallinuse"` - Version string `json:"version"` - Name string `json:"name"` - OS string `json:"os"` - Debug bool `json:"debug"` - IsStaticPort bool `json:"isstaticport"` - IsStatic bool `json:"isstatic"` - ListenPort int `json:"listenport"` - WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` - MTU int `json:"mtu" yaml:"mtu"` - Interfaces []ApiIface `json:"interfaces" yaml:"interfaces"` - DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"` - EndpointIP string `json:"endpointip" yaml:"endpointip"` - EndpointIPv6 string `json:"endpointipv6" yaml:"endpointipv6"` - PublicKey string `json:"publickey"` - MacAddress string `json:"macaddress"` - Nodes []string `json:"nodes"` - IsDefault bool `json:"isdefault" yaml:"isdefault"` - NatType string `json:"nat_type" yaml:"nat_type"` - PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"` - AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` + ID string `json:"id"` + Verbosity int `json:"verbosity"` + FirewallInUse string `json:"firewallinuse"` + Version string `json:"version"` + Name string `json:"name"` + OS string `json:"os"` + Debug bool `json:"debug"` + IsStaticPort bool `json:"isstaticport"` + IsStatic bool `json:"isstatic"` + ListenPort int `json:"listenport"` + WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` + MTU int `json:"mtu" yaml:"mtu"` + Interfaces []ApiIface `json:"interfaces" yaml:"interfaces"` + DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"` + EndpointIP string `json:"endpointip" yaml:"endpointip"` + EndpointIPv6 string `json:"endpointipv6" yaml:"endpointipv6"` + PublicKey string `json:"publickey"` + MacAddress string `json:"macaddress"` + Nodes []string `json:"nodes"` + IsDefault bool `json:"isdefault" yaml:"isdefault"` + NatType string `json:"nat_type" yaml:"nat_type"` + PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"` + AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` + Tags map[TagID]struct{} `json:"tags"` } // ApiIface - the interface struct for API usage @@ -78,6 +79,7 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost { a.NatType = h.NatType a.PersistentKeepalive = int(h.PersistentKeepalive.Seconds()) a.AutoUpdate = h.AutoUpdate + a.Tags = h.Tags return &a } @@ -123,5 +125,6 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host { h.TurnEndpoint = currentHost.TurnEndpoint h.PersistentKeepalive = time.Duration(a.PersistentKeepalive) * time.Second h.AutoUpdate = a.AutoUpdate + h.Tags = a.Tags return &h } From db2550b7bddf8850550370ac4dd478a2211e47e5 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 18 Sep 2024 12:22:49 +0400 Subject: [PATCH 019/169] add tag groups to enrollment key --- controllers/enrollmentkeys.go | 11 ++++++++++- logic/enrollmentkey.go | 7 ++++--- logic/enrollmentkey_test.go | 26 +++++++++++++------------- models/enrollment_key.go | 2 ++ 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/controllers/enrollmentkeys.go b/controllers/enrollmentkeys.go index dc6669bd6..4ae31e687 100644 --- a/controllers/enrollmentkeys.go +++ b/controllers/enrollmentkeys.go @@ -156,6 +156,7 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) { newTime, enrollmentKeyBody.Networks, enrollmentKeyBody.Tags, + enrollmentKeyBody.Groups, enrollmentKeyBody.Unlimited, relayId, ) @@ -206,7 +207,7 @@ func updateEnrollmentKey(w http.ResponseWriter, r *http.Request) { } } - newEnrollmentKey, err := logic.UpdateEnrollmentKey(keyId, relayId) + newEnrollmentKey, err := logic.UpdateEnrollmentKey(keyId, relayId, enrollmentKeyBody.Groups) if err != nil { slog.Error("failed to update enrollment key", "error", err) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) @@ -307,6 +308,10 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) { return } } + newHost.Tags = make(map[models.TagID]struct{}) + for _, tagI := range enrollmentKey.Groups { + newHost.Tags[tagI] = struct{}{} + } if err = logic.CreateHost(&newHost); err != nil { logger.Log( 0, @@ -337,6 +342,10 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) { return } logic.UpdateHostFromClient(&newHost, currHost) + currHost.Tags = make(map[models.TagID]struct{}) + for _, tagI := range enrollmentKey.Groups { + currHost.Tags[tagI] = struct{}{} + } err = logic.UpsertHost(currHost) if err != nil { slog.Error("failed to update host", "id", currHost.ID, "error", err) diff --git a/logic/enrollmentkey.go b/logic/enrollmentkey.go index d3c48a011..bf811a1a8 100644 --- a/logic/enrollmentkey.go +++ b/logic/enrollmentkey.go @@ -37,7 +37,7 @@ var ( ) // CreateEnrollmentKey - creates a new enrollment key in db -func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, unlimited bool, relay uuid.UUID) (*models.EnrollmentKey, error) { +func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, groups []models.TagID, unlimited bool, relay uuid.UUID) (*models.EnrollmentKey, error) { newKeyID, err := getUniqueEnrollmentID() if err != nil { return nil, err @@ -51,6 +51,7 @@ func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string Tags: []string{}, Type: models.Undefined, Relay: relay, + Groups: groups, } if uses > 0 { k.UsesRemaining = uses @@ -89,7 +90,7 @@ func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string } // UpdateEnrollmentKey - updates an existing enrollment key's associated relay -func UpdateEnrollmentKey(keyId string, relayId uuid.UUID) (*models.EnrollmentKey, error) { +func UpdateEnrollmentKey(keyId string, relayId uuid.UUID, groups []models.TagID) (*models.EnrollmentKey, error) { key, err := GetEnrollmentKey(keyId) if err != nil { return nil, err @@ -109,7 +110,7 @@ func UpdateEnrollmentKey(keyId string, relayId uuid.UUID) (*models.EnrollmentKey } key.Relay = relayId - + key.Groups = groups if err = upsertEnrollmentKey(&key); err != nil { return nil, err } diff --git a/logic/enrollmentkey_test.go b/logic/enrollmentkey_test.go index 677c47141..5e63df167 100644 --- a/logic/enrollmentkey_test.go +++ b/logic/enrollmentkey_test.go @@ -14,35 +14,35 @@ func TestCreateEnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() t.Run("Can_Not_Create_Key", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, false, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, false, uuid.Nil) assert.Nil(t, newKey) assert.NotNil(t, err) assert.ErrorIs(t, err, models.ErrInvalidEnrollmentKey) }) t.Run("Can_Create_Key_Uses", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(1, time.Time{}, nil, nil, false, uuid.Nil) + newKey, err := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil) assert.Nil(t, err) assert.Equal(t, 1, newKey.UsesRemaining) assert.True(t, newKey.IsValid()) }) t.Run("Can_Create_Key_Time", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Now().Add(time.Minute), nil, nil, false, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Now().Add(time.Minute), nil, nil, nil, false, uuid.Nil) assert.Nil(t, err) assert.True(t, newKey.IsValid()) }) t.Run("Can_Create_Key_Unlimited", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, true, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, true, uuid.Nil) assert.Nil(t, err) assert.True(t, newKey.IsValid()) }) t.Run("Can_Create_Key_WithNetworks", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) assert.Nil(t, err) assert.True(t, newKey.IsValid()) assert.True(t, len(newKey.Networks) == 2) }) t.Run("Can_Create_Key_WithTags", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, []string{"tag1", "tag2"}, true, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, []string{"tag1", "tag2"}, nil, true, uuid.Nil) assert.Nil(t, err) assert.True(t, newKey.IsValid()) assert.True(t, len(newKey.Tags) == 2) @@ -62,7 +62,7 @@ func TestCreateEnrollmentKey(t *testing.T) { func TestDelete_EnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil) + newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) t.Run("Can_Delete_Key", func(t *testing.T) { assert.True(t, newKey.IsValid()) err := DeleteEnrollmentKey(newKey.Value) @@ -83,7 +83,7 @@ func TestDelete_EnrollmentKey(t *testing.T) { func TestDecrement_EnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, false, uuid.Nil) + newKey, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil) t.Run("Check_initial_uses", func(t *testing.T) { assert.True(t, newKey.IsValid()) assert.Equal(t, newKey.UsesRemaining, 1) @@ -107,9 +107,9 @@ func TestDecrement_EnrollmentKey(t *testing.T) { func TestUsability_EnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - key1, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, false, uuid.Nil) - key2, _ := CreateEnrollmentKey(0, time.Now().Add(time.Minute<<4), nil, nil, false, uuid.Nil) - key3, _ := CreateEnrollmentKey(0, time.Time{}, nil, nil, true, uuid.Nil) + key1, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil) + key2, _ := CreateEnrollmentKey(0, time.Now().Add(time.Minute<<4), nil, nil, nil, false, uuid.Nil) + key3, _ := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, true, uuid.Nil) t.Run("Check if valid use key can be used", func(t *testing.T) { assert.Equal(t, key1.UsesRemaining, 1) ok := TryToUseEnrollmentKey(key1) @@ -145,7 +145,7 @@ func removeAllEnrollments() { func TestTokenize_EnrollmentKeys(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil) + newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) const defaultValue = "MwE5MwE5MwE5MwE5MwE5MwE5MwE5MwE5" const b64value = "eyJzZXJ2ZXIiOiJhcGkubXlzZXJ2ZXIuY29tIiwidmFsdWUiOiJNd0U1TXdFNU13RTVNd0U1TXdFNU13RTVNd0U1TXdFNSJ9" const serverAddr = "api.myserver.com" @@ -178,7 +178,7 @@ func TestTokenize_EnrollmentKeys(t *testing.T) { func TestDeTokenize_EnrollmentKeys(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, true, uuid.Nil) + newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) const b64Value = "eyJzZXJ2ZXIiOiJhcGkubXlzZXJ2ZXIuY29tIiwidmFsdWUiOiJNd0U1TXdFNU13RTVNd0U1TXdFNU13RTVNd0U1TXdFNSJ9" const serverAddr = "api.myserver.com" diff --git a/models/enrollment_key.go b/models/enrollment_key.go index e775344df..5aa89c8a7 100644 --- a/models/enrollment_key.go +++ b/models/enrollment_key.go @@ -52,6 +52,7 @@ type EnrollmentKey struct { Token string `json:"token,omitempty"` // B64 value of EnrollmentToken Type KeyType `json:"type"` Relay uuid.UUID `json:"relay"` + Groups []TagID `json:"groups"` } // APIEnrollmentKey - used to create enrollment keys via API @@ -63,6 +64,7 @@ type APIEnrollmentKey struct { Tags []string `json:"tags" validate:"required,dive,min=3,max=32"` Type KeyType `json:"type"` Relay string `json:"relay"` + Groups []TagID `json:"groups"` } // RegisterResponse - the response to a successful enrollment register From db224ba2d918420b0cb14c8d5db6edd275370d36 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 19 Sep 2024 15:59:38 +0400 Subject: [PATCH 020/169] allow tag name update --- controllers/tags.go | 12 +++++++++++- logic/tags.go | 12 ++++++++++++ models/tags.go | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/controllers/tags.go b/controllers/tags.go index 260305a49..a2682ac81 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -5,6 +5,7 @@ import ( "errors" "net/http" "net/url" + "strings" "time" "github.com/gorilla/mux" @@ -104,11 +105,20 @@ func updateTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - _, err = logic.GetTag(updateTag.ID) + tag, err := logic.GetTag(updateTag.ID) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + updateTag.NewID = models.TagID(strings.TrimSpace(updateTag.NewID.String())) + if updateTag.NewID.String() != "" { + tag.ID = updateTag.NewID + err = logic.InsertTag(tag) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + } go logic.UpdateTag(updateTag) logic.ReturnSuccessResponse(w, r, "updating tags") } diff --git a/logic/tags.go b/logic/tags.go index 10841e7fc..3710816f7 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -121,6 +121,18 @@ func UpdateTag(req models.UpdateTagReq) { delete(deletedTaggedHost.Tags, req.ID) UpsertHost(&deletedTaggedHost) } + go func(req models.UpdateTagReq) { + if req.NewID != "" { + tagHostsMap = GetHostsWithTag(req.ID) + for _, hostI := range tagHostsMap { + hostI := hostI + delete(hostI.Tags, req.ID) + hostI.Tags[req.NewID] = struct{}{} + UpsertHost(&hostI) + } + } + }(req) + } // SortTagEntrys - Sorts slice of Tag entries by their id diff --git a/models/tags.go b/models/tags.go index 84352f7f0..fc7d0acc6 100644 --- a/models/tags.go +++ b/models/tags.go @@ -27,5 +27,6 @@ type TagListResp struct { type UpdateTagReq struct { Tag + NewID TagID `json:"new_id"` TaggedHosts []string `json:"tagged_hosts"` } From c64dc852aea86d25d66f44f433245596ea46e993 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 22 Sep 2024 12:22:24 +0400 Subject: [PATCH 021/169] associate tags to network level --- controllers/tags.go | 44 +++++++++++++++++++++++++++++--------------- logic/tags.go | 6 +++--- models/tags.go | 18 ++++++++++++++---- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index a2682ac81..f3cc4f031 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -3,6 +3,7 @@ package controller import ( "encoding/json" "errors" + "fmt" "net/http" "net/url" "strings" @@ -63,6 +64,25 @@ func createTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + // check if tag network exists + _, err = logic.GetNetwork(req.Network.String()) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to get network details for "+req.Network.String()), "badrequest")) + return + } + // check if tag exists + tag := models.Tag{ + ID: models.TagID(fmt.Sprintf("%s.%s", req.Network, req.TagName)), + TagName: req.TagName, + Network: req.Network, + CreatedBy: user.UserName, + CreatedAt: time.Now(), + } + err = logic.InsertTag(tag) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } go func() { for _, hostID := range req.TaggedHosts { h, err := logic.GetHost(hostID) @@ -72,21 +92,11 @@ func createTag(w http.ResponseWriter, r *http.Request) { if h.Tags == nil { h.Tags = make(map[models.TagID]struct{}) } - h.Tags[req.ID] = struct{}{} + h.Tags[tag.ID] = struct{}{} logic.UpsertHost(h) } }() - tag := models.Tag{ - ID: req.ID, - CreatedBy: user.UserName, - CreatedAt: time.Now(), - } - err = logic.InsertTag(tag) - if err != nil { - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) - return - } logic.ReturnSuccessResponseWithJson(w, r, req, "created tag successfully") } @@ -105,21 +115,25 @@ func updateTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + tag, err := logic.GetTag(updateTag.ID) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - updateTag.NewID = models.TagID(strings.TrimSpace(updateTag.NewID.String())) - if updateTag.NewID.String() != "" { - tag.ID = updateTag.NewID + updateTag.NewName = strings.TrimSpace(updateTag.NewName) + var newID models.TagID + if updateTag.NewName != "" { + newID = models.TagID(fmt.Sprintf("%s.%s", tag.Network, updateTag.NewName)) + tag.ID = newID + tag.TagName = updateTag.NewName err = logic.InsertTag(tag) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } } - go logic.UpdateTag(updateTag) + go logic.UpdateTag(updateTag, newID) logic.ReturnSuccessResponse(w, r, "updating tags") } diff --git a/logic/tags.go b/logic/tags.go index 3710816f7..637375c62 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -97,7 +97,7 @@ func ListTags() ([]models.Tag, error) { } // UpdateTag - updates and syncs hosts with tag update -func UpdateTag(req models.UpdateTagReq) { +func UpdateTag(req models.UpdateTagReq, newID models.TagID) { tagMutex.Lock() defer tagMutex.Unlock() tagHostsMap := GetHostsWithTag(req.ID) @@ -122,12 +122,12 @@ func UpdateTag(req models.UpdateTagReq) { UpsertHost(&deletedTaggedHost) } go func(req models.UpdateTagReq) { - if req.NewID != "" { + if newID != "" { tagHostsMap = GetHostsWithTag(req.ID) for _, hostI := range tagHostsMap { hostI := hostI delete(hostI.Tags, req.ID) - hostI.Tags[req.NewID] = struct{}{} + hostI.Tags[newID] = struct{}{} UpsertHost(&hostI) } } diff --git a/models/tags.go b/models/tags.go index fc7d0acc6..6af9687e7 100644 --- a/models/tags.go +++ b/models/tags.go @@ -1,6 +1,9 @@ package models -import "time" +import ( + "fmt" + "time" +) type TagID string @@ -8,15 +11,22 @@ func (id TagID) String() string { return string(id) } +func (t Tag) GetIDFromName() string { + return fmt.Sprintf("%s.%s", t.Network, t.TagName) +} + type Tag struct { ID TagID `json:"id"` + TagName string `json:"tag_name"` + Network NetworkID `json:"network"` CreatedBy string `json:"created_by"` CreatedAt time.Time `json:"created_at"` } type CreateTagReq struct { - ID TagID `json:"id"` - TaggedHosts []string `json:"tagged_hosts"` + TagName string `json:"tag_name"` + Network NetworkID `json:"network"` + TaggedHosts []string `json:"tagged_hosts"` } type TagListResp struct { @@ -27,6 +37,6 @@ type TagListResp struct { type UpdateTagReq struct { Tag - NewID TagID `json:"new_id"` + NewName string `json:"new_name"` TaggedHosts []string `json:"tagged_hosts"` } From 04b8737a021f1318321050dec3863a408a346484 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 22 Sep 2024 13:37:58 +0400 Subject: [PATCH 022/169] move tags to node model --- controllers/tags.go | 35 ++++++++++++------- logic/hosts.go | 32 ----------------- logic/nodes.go | 37 ++++++++++++++++++++ logic/tags.go | 85 +++++++++++++++++++++++++++++---------------- models/api_host.go | 49 ++++++++++++-------------- models/api_node.go | 3 ++ models/host.go | 63 +++++++++++++++++---------------- models/node.go | 1 + models/tags.go | 12 +++++-- 9 files changed, 183 insertions(+), 134 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index f3cc4f031..ea52ff2b8 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -16,7 +16,7 @@ import ( ) func tagHandlers(r *mux.Router) { - r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(getAllTags))). + r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(getTags))). Methods(http.MethodGet) r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(createTag))). Methods(http.MethodPost) @@ -27,21 +27,32 @@ func tagHandlers(r *mux.Router) { } -// @Summary Get all Tag entries +// @Summary List Tags in a network // @Router /api/v1/tags [get] // @Tags TAG // @Accept json // @Success 200 {array} models.SuccessResponse // @Failure 500 {object} models.ErrorResponse -func getAllTags(w http.ResponseWriter, r *http.Request) { - tags, err := logic.ListTagsWithHosts() +func getTags(w http.ResponseWriter, r *http.Request) { + netID, _ := url.QueryUnescape(r.URL.Query().Get("network")) + if netID == "" { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network id param is missing"), "badrequest")) + return + } + // check if network exists + _, err := logic.GetNetwork(netID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + tags, err := logic.ListTagsWithNodes(models.NetworkID(netID)) if err != nil { - logger.Log(0, r.Header.Get("user"), "failed to get all DNS entries: ", err.Error()) + logger.Log(0, r.Header.Get("user"), "failed to get all network tag entries: ", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } logic.SortTagEntrys(tags[:]) - logic.ReturnSuccessResponseWithJson(w, r, tags, "fetched all tags") + logic.ReturnSuccessResponseWithJson(w, r, tags, "fetched all tags in the network "+netID) } // @Summary Create Tag @@ -84,16 +95,16 @@ func createTag(w http.ResponseWriter, r *http.Request) { return } go func() { - for _, hostID := range req.TaggedHosts { - h, err := logic.GetHost(hostID) + for _, nodeID := range req.TaggedNodes { + node, err := logic.GetNodeByID(nodeID) if err != nil { continue } - if h.Tags == nil { - h.Tags = make(map[models.TagID]struct{}) + if node.Tags == nil { + node.Tags = make(map[models.TagID]struct{}) } - h.Tags[tag.ID] = struct{}{} - logic.UpsertHost(h) + node.Tags[tag.ID] = struct{}{} + logic.UpsertNode(&node) } }() diff --git a/logic/hosts.go b/logic/hosts.go index b8a90e8c9..0fa8887e9 100644 --- a/logic/hosts.go +++ b/logic/hosts.go @@ -572,35 +572,3 @@ func SortApiHosts(unsortedHosts []models.ApiHost) { return unsortedHosts[i].ID < unsortedHosts[j].ID }) } - -func GetTagMapWithHosts() (tagHostMap map[models.TagID][]models.Host) { - tagHostMap = make(map[models.TagID][]models.Host) - hosts, _ := GetAllHosts() - for _, hostI := range hosts { - if hostI.Tags == nil { - continue - } - for hostTagID := range hostI.Tags { - if _, ok := tagHostMap[hostTagID]; ok { - tagHostMap[hostTagID] = append(tagHostMap[hostTagID], hostI) - } else { - tagHostMap[hostTagID] = []models.Host{hostI} - } - } - } - return -} - -func GetHostsWithTag(tagID models.TagID) map[string]models.Host { - hMap := make(map[string]models.Host) - hosts, _ := GetAllHosts() - for _, hostI := range hosts { - if hostI.Tags == nil { - continue - } - if _, ok := hostI.Tags[tagID]; ok { - hMap[hostI.ID.String()] = hostI - } - } - return hMap -} diff --git a/logic/nodes.go b/logic/nodes.go index e241c6ccc..8cb451feb 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -698,3 +698,40 @@ func GetAllFailOvers() ([]models.Node, error) { } return igs, nil } + +func GetTagMapWithNodes(netID models.NetworkID) (tagNodesMap map[models.TagID][]models.Node) { + tagNodesMap = make(map[models.TagID][]models.Node) + nodes, _ := GetNetworkNodes(netID.String()) + for _, nodeI := range nodes { + if nodeI.Tags == nil { + continue + } + for nodeTagID := range nodeI.Tags { + if _, ok := tagNodesMap[nodeTagID]; ok { + tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) + } else { + tagNodesMap[nodeTagID] = []models.Node{nodeI} + } + } + } + return +} + +func GetNodesWithTag(tagID models.TagID) map[string]models.Node { + + nMap := make(map[string]models.Node) + tag, err := GetTag(tagID) + if err != nil { + return nMap + } + nodes, _ := GetNetworkNodes(tag.Network.String()) + for _, nodeI := range nodes { + if nodeI.Tags == nil { + continue + } + if _, ok := nodeI.Tags[tagID]; ok { + nMap[nodeI.ID.String()] = nodeI + } + } + return nMap +} diff --git a/logic/tags.go b/logic/tags.go index 637375c62..0f6ea2780 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -42,35 +42,39 @@ func InsertTag(tag models.Tag) error { // DeleteTag - delete tag, will also untag hosts func DeleteTag(tagID models.TagID) error { // cleanUp tags on hosts - hosts, err := GetAllHosts() + tag, err := GetTag(tagID) if err != nil { return err } - for _, hostI := range hosts { - hostI := hostI - if _, ok := hostI.Tags[tagID]; ok { - delete(hostI.Tags, tagID) - UpsertHost(&hostI) + nodes, err := GetNetworkNodes(tag.Network.String()) + if err != nil { + return err + } + for _, nodeI := range nodes { + nodeI := nodeI + if _, ok := nodeI.Tags[tagID]; ok { + delete(nodeI.Tags, tagID) + UpsertNode(&nodeI) } } return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String()) } // ListTagsWithHosts - lists all tags with tagged hosts -func ListTagsWithHosts() ([]models.TagListResp, error) { +func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) { tagMutex.RLock() defer tagMutex.RUnlock() - tags, err := ListTags() + tags, err := ListNetworkTags(netID) if err != nil { return []models.TagListResp{}, err } - tagsHostMap := GetTagMapWithHosts() + tagsNodeMap := GetTagMapWithNodes(netID) resp := []models.TagListResp{} for _, tagI := range tags { tagRespI := models.TagListResp{ Tag: tagI, - UsedByCnt: len(tagsHostMap[tagI.ID]), - TaggedHosts: tagsHostMap[tagI.ID], + UsedByCnt: len(tagsNodeMap[tagI.ID]), + TaggedNodes: tagsNodeMap[tagI.ID], } resp = append(resp, tagRespI) } @@ -96,39 +100,62 @@ func ListTags() ([]models.Tag, error) { return tags, nil } +// ListTags - lists all tags from DB +func ListNetworkTags(netID models.NetworkID) ([]models.Tag, error) { + + data, err := database.FetchRecords(database.TAG_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Tag{}, err + } + tags := []models.Tag{} + for _, dataI := range data { + tag := models.Tag{} + err := json.Unmarshal([]byte(dataI), &tag) + if err != nil { + continue + } + if tag.Network == netID { + tags = append(tags, tag) + } + + } + return tags, nil +} + // UpdateTag - updates and syncs hosts with tag update func UpdateTag(req models.UpdateTagReq, newID models.TagID) { tagMutex.Lock() defer tagMutex.Unlock() - tagHostsMap := GetHostsWithTag(req.ID) - for _, hostID := range req.TaggedHosts { - hostI, err := GetHost(hostID) + tagNodesMap := GetNodesWithTag(req.ID) + for _, nodeID := range req.TaggedNodes { + node, err := GetNodeByID(nodeID) if err != nil { continue } - if _, ok := tagHostsMap[hostI.ID.String()]; !ok { - if hostI.Tags == nil { - hostI.Tags = make(map[models.TagID]struct{}) + + if _, ok := tagNodesMap[node.ID.String()]; !ok { + if node.Tags == nil { + node.Tags = make(map[models.TagID]struct{}) } - hostI.Tags[req.ID] = struct{}{} - UpsertHost(hostI) + node.Tags[req.ID] = struct{}{} + UpsertNode(&node) } else { - delete(tagHostsMap, hostI.ID.String()) + delete(tagNodesMap, node.ID.String()) } } - for _, deletedTaggedHost := range tagHostsMap { - deletedTaggedHost := deletedTaggedHost + for _, deletedTaggedNode := range tagNodesMap { + deletedTaggedHost := deletedTaggedNode delete(deletedTaggedHost.Tags, req.ID) - UpsertHost(&deletedTaggedHost) + UpsertNode(&deletedTaggedHost) } go func(req models.UpdateTagReq) { if newID != "" { - tagHostsMap = GetHostsWithTag(req.ID) - for _, hostI := range tagHostsMap { - hostI := hostI - delete(hostI.Tags, req.ID) - hostI.Tags[newID] = struct{}{} - UpsertHost(&hostI) + tagNodesMap = GetNodesWithTag(req.ID) + for _, nodeI := range tagNodesMap { + nodeI := nodeI + delete(nodeI.Tags, req.ID) + nodeI.Tags[newID] = struct{}{} + UpsertNode(&nodeI) } } }(req) diff --git a/models/api_host.go b/models/api_host.go index c84317105..324bf9f8c 100644 --- a/models/api_host.go +++ b/models/api_host.go @@ -8,30 +8,29 @@ import ( // ApiHost - the host struct for API usage type ApiHost struct { - ID string `json:"id"` - Verbosity int `json:"verbosity"` - FirewallInUse string `json:"firewallinuse"` - Version string `json:"version"` - Name string `json:"name"` - OS string `json:"os"` - Debug bool `json:"debug"` - IsStaticPort bool `json:"isstaticport"` - IsStatic bool `json:"isstatic"` - ListenPort int `json:"listenport"` - WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` - MTU int `json:"mtu" yaml:"mtu"` - Interfaces []ApiIface `json:"interfaces" yaml:"interfaces"` - DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"` - EndpointIP string `json:"endpointip" yaml:"endpointip"` - EndpointIPv6 string `json:"endpointipv6" yaml:"endpointipv6"` - PublicKey string `json:"publickey"` - MacAddress string `json:"macaddress"` - Nodes []string `json:"nodes"` - IsDefault bool `json:"isdefault" yaml:"isdefault"` - NatType string `json:"nat_type" yaml:"nat_type"` - PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"` - AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` - Tags map[TagID]struct{} `json:"tags"` + ID string `json:"id"` + Verbosity int `json:"verbosity"` + FirewallInUse string `json:"firewallinuse"` + Version string `json:"version"` + Name string `json:"name"` + OS string `json:"os"` + Debug bool `json:"debug"` + IsStaticPort bool `json:"isstaticport"` + IsStatic bool `json:"isstatic"` + ListenPort int `json:"listenport"` + WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` + MTU int `json:"mtu" yaml:"mtu"` + Interfaces []ApiIface `json:"interfaces" yaml:"interfaces"` + DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"` + EndpointIP string `json:"endpointip" yaml:"endpointip"` + EndpointIPv6 string `json:"endpointipv6" yaml:"endpointipv6"` + PublicKey string `json:"publickey"` + MacAddress string `json:"macaddress"` + Nodes []string `json:"nodes"` + IsDefault bool `json:"isdefault" yaml:"isdefault"` + NatType string `json:"nat_type" yaml:"nat_type"` + PersistentKeepalive int `json:"persistentkeepalive" yaml:"persistentkeepalive"` + AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` } // ApiIface - the interface struct for API usage @@ -79,7 +78,6 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost { a.NatType = h.NatType a.PersistentKeepalive = int(h.PersistentKeepalive.Seconds()) a.AutoUpdate = h.AutoUpdate - a.Tags = h.Tags return &a } @@ -125,6 +123,5 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host { h.TurnEndpoint = currentHost.TurnEndpoint h.PersistentKeepalive = time.Duration(a.PersistentKeepalive) * time.Second h.AutoUpdate = a.AutoUpdate - h.Tags = a.Tags return &h } diff --git a/models/api_node.go b/models/api_node.go index 0c91bbeca..1f8a45b95 100644 --- a/models/api_node.go +++ b/models/api_node.go @@ -48,6 +48,7 @@ type ApiNode struct { InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"` InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"` AdditionalRagIps []string `json:"additional_rag_ips" yaml:"additional_rag_ips"` + Tags map[TagID]struct{} `json:"tags" yaml:"tags"` } // ApiNode.ConvertToServerNode - converts an api node to a server node @@ -123,6 +124,7 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node { } convertedNode.AdditionalRagIps = append(convertedNode.AdditionalRagIps, ragIp) } + convertedNode.Tags = a.Tags return &convertedNode } @@ -180,6 +182,7 @@ func (nm *Node) ConvertToAPINode() *ApiNode { apiNode.FailedOverBy = nm.FailedOverBy apiNode.Metadata = nm.Metadata apiNode.AdditionalRagIps = []string{} + apiNode.Tags = nm.Tags for _, ip := range nm.AdditionalRagIps { apiNode.AdditionalRagIps = append(apiNode.AdditionalRagIps, ip.String()) } diff --git a/models/host.go b/models/host.go index 8b336dfad..2781dee0e 100644 --- a/models/host.go +++ b/models/host.go @@ -41,38 +41,37 @@ const ( // Host - represents a host on the network type Host struct { - ID uuid.UUID `json:"id" yaml:"id"` - Verbosity int `json:"verbosity" yaml:"verbosity"` - FirewallInUse string `json:"firewallinuse" yaml:"firewallinuse"` - Version string `json:"version" yaml:"version"` - IPForwarding bool `json:"ipforwarding" yaml:"ipforwarding"` - DaemonInstalled bool `json:"daemoninstalled" yaml:"daemoninstalled"` - AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` - HostPass string `json:"hostpass" yaml:"hostpass"` - Name string `json:"name" yaml:"name"` - OS string `json:"os" yaml:"os"` - Interface string `json:"interface" yaml:"interface"` - Debug bool `json:"debug" yaml:"debug"` - ListenPort int `json:"listenport" yaml:"listenport"` - WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` - MTU int `json:"mtu" yaml:"mtu"` - PublicKey wgtypes.Key `json:"publickey" yaml:"publickey"` - MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"` - TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"` - Nodes []string `json:"nodes" yaml:"nodes"` - Interfaces []Iface `json:"interfaces" yaml:"interfaces"` - DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"` - EndpointIP net.IP `json:"endpointip" yaml:"endpointip"` - EndpointIPv6 net.IP `json:"endpointipv6" yaml:"endpointipv6"` - IsDocker bool `json:"isdocker" yaml:"isdocker"` - IsK8S bool `json:"isk8s" yaml:"isk8s"` - IsStaticPort bool `json:"isstaticport" yaml:"isstaticport"` - IsStatic bool `json:"isstatic" yaml:"isstatic"` - IsDefault bool `json:"isdefault" yaml:"isdefault"` - NatType string `json:"nat_type,omitempty" yaml:"nat_type,omitempty"` - TurnEndpoint *netip.AddrPort `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"` - PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"` - Tags map[TagID]struct{} `json:"tags" yaml:"tags"` + ID uuid.UUID `json:"id" yaml:"id"` + Verbosity int `json:"verbosity" yaml:"verbosity"` + FirewallInUse string `json:"firewallinuse" yaml:"firewallinuse"` + Version string `json:"version" yaml:"version"` + IPForwarding bool `json:"ipforwarding" yaml:"ipforwarding"` + DaemonInstalled bool `json:"daemoninstalled" yaml:"daemoninstalled"` + AutoUpdate bool `json:"autoupdate" yaml:"autoupdate"` + HostPass string `json:"hostpass" yaml:"hostpass"` + Name string `json:"name" yaml:"name"` + OS string `json:"os" yaml:"os"` + Interface string `json:"interface" yaml:"interface"` + Debug bool `json:"debug" yaml:"debug"` + ListenPort int `json:"listenport" yaml:"listenport"` + WgPublicListenPort int `json:"wg_public_listen_port" yaml:"wg_public_listen_port"` + MTU int `json:"mtu" yaml:"mtu"` + PublicKey wgtypes.Key `json:"publickey" yaml:"publickey"` + MacAddress net.HardwareAddr `json:"macaddress" yaml:"macaddress"` + TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"` + Nodes []string `json:"nodes" yaml:"nodes"` + Interfaces []Iface `json:"interfaces" yaml:"interfaces"` + DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"` + EndpointIP net.IP `json:"endpointip" yaml:"endpointip"` + EndpointIPv6 net.IP `json:"endpointipv6" yaml:"endpointipv6"` + IsDocker bool `json:"isdocker" yaml:"isdocker"` + IsK8S bool `json:"isk8s" yaml:"isk8s"` + IsStaticPort bool `json:"isstaticport" yaml:"isstaticport"` + IsStatic bool `json:"isstatic" yaml:"isstatic"` + IsDefault bool `json:"isdefault" yaml:"isdefault"` + NatType string `json:"nat_type,omitempty" yaml:"nat_type,omitempty"` + TurnEndpoint *netip.AddrPort `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"` + PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"` } // FormatBool converts a boolean to a [yes|no] string diff --git a/models/node.go b/models/node.go index e5ea2cfc4..1eb78ab61 100644 --- a/models/node.go +++ b/models/node.go @@ -99,6 +99,7 @@ type Node struct { InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"` InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"` AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips" swaggertype:"array,number"` + Tags map[TagID]struct{} `json:"tags" yaml:"tags"` } // LegacyNode - legacy struct for node model diff --git a/models/tags.go b/models/tags.go index 6af9687e7..7589d451d 100644 --- a/models/tags.go +++ b/models/tags.go @@ -26,17 +26,23 @@ type Tag struct { type CreateTagReq struct { TagName string `json:"tag_name"` Network NetworkID `json:"network"` - TaggedHosts []string `json:"tagged_hosts"` + TaggedNodes []string `json:"tagged_nodes"` } type TagListResp struct { Tag UsedByCnt int `json:"used_by_count"` - TaggedHosts []Host `json:"tagged_hosts"` + TaggedNodes []Node `json:"tagged_nodes"` +} + +type TagListRespNodes struct { + Tag + UsedByCnt int `json:"used_by_count"` + TaggedNodes []Node `json:"tagged_nodes"` } type UpdateTagReq struct { Tag NewName string `json:"new_name"` - TaggedHosts []string `json:"tagged_hosts"` + TaggedNodes []string `json:"tagged_nodes"` } From 7dffa98884162b4d1ce8fd45ce9abaa5693274f6 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 22 Sep 2024 14:06:17 +0400 Subject: [PATCH 023/169] associate enrollment key tags to node --- auth/host_session.go | 12 ++++++++++-- controllers/enrollmentkeys.go | 11 ++--------- logic/nodes.go | 3 +++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/auth/host_session.go b/auth/host_session.go index 62e9d4387..7a3929240 100644 --- a/auth/host_session.go +++ b/auth/host_session.go @@ -222,7 +222,7 @@ func SessionHandler(conn *websocket.Conn) { if err = conn.WriteMessage(messageType, reponseData); err != nil { logger.Log(0, "error during message writing:", err.Error()) } - go CheckNetRegAndHostUpdate(netsToAdd[:], &result.Host, uuid.Nil) + go CheckNetRegAndHostUpdate(netsToAdd[:], &result.Host, uuid.Nil, []models.TagID{}) case <-timeout: // the read from req.answerCh has timed out logger.Log(0, "timeout signal recv,exiting oauth socket conn") break @@ -236,7 +236,7 @@ func SessionHandler(conn *websocket.Conn) { } // CheckNetRegAndHostUpdate - run through networks and send a host update -func CheckNetRegAndHostUpdate(networks []string, h *models.Host, relayNodeId uuid.UUID) { +func CheckNetRegAndHostUpdate(networks []string, h *models.Host, relayNodeId uuid.UUID, tags []models.TagID) { // publish host update through MQ for i := range networks { network := networks[i] @@ -246,6 +246,14 @@ func CheckNetRegAndHostUpdate(networks []string, h *models.Host, relayNodeId uui logger.Log(0, "failed to add host to network:", h.ID.String(), h.Name, network, err.Error()) continue } + if len(tags) > 0 { + newNode.Tags = make(map[models.TagID]struct{}) + for _, tagI := range tags { + newNode.Tags[tagI] = struct{}{} + } + logic.UpsertNode(newNode) + } + if relayNodeId != uuid.Nil && !newNode.IsRelayed { // check if relay node exists and acting as relay relaynode, err := logic.GetNodeByID(relayNodeId.String()) diff --git a/controllers/enrollmentkeys.go b/controllers/enrollmentkeys.go index 4ae31e687..9d7fbe432 100644 --- a/controllers/enrollmentkeys.go +++ b/controllers/enrollmentkeys.go @@ -308,10 +308,7 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) { return } } - newHost.Tags = make(map[models.TagID]struct{}) - for _, tagI := range enrollmentKey.Groups { - newHost.Tags[tagI] = struct{}{} - } + if err = logic.CreateHost(&newHost); err != nil { logger.Log( 0, @@ -342,10 +339,6 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) { return } logic.UpdateHostFromClient(&newHost, currHost) - currHost.Tags = make(map[models.TagID]struct{}) - for _, tagI := range enrollmentKey.Groups { - currHost.Tags[tagI] = struct{}{} - } err = logic.UpsertHost(currHost) if err != nil { slog.Error("failed to update host", "id", currHost.ID, "error", err) @@ -364,5 +357,5 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(&response) // notify host of changes, peer and node updates - go auth.CheckNetRegAndHostUpdate(enrollmentKey.Networks, &newHost, enrollmentKey.Relay) + go auth.CheckNetRegAndHostUpdate(enrollmentKey.Networks, &newHost, enrollmentKey.Relay, enrollmentKey.Groups) } diff --git a/logic/nodes.go b/logic/nodes.go index 8cb451feb..af59f6e95 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -420,6 +420,9 @@ func SetNodeDefaults(node *models.Node, resetConnected bool) { node.SetDefaultConnected() } node.SetExpirationDateTime() + if node.Tags == nil { + node.Tags = make(map[models.TagID]struct{}) + } } // GetRecordKey - get record key From ad4c6636125fdf5ab5cca5701358eddedc740118 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 22 Sep 2024 15:22:36 +0400 Subject: [PATCH 024/169] fix tag udpate with new ID --- controllers/tags.go | 2 ++ logic/tags.go | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index ea52ff2b8..238611c85 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -143,6 +143,8 @@ func updateTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + // delete old Tag entry + logic.DeleteTag(updateTag.ID) } go logic.UpdateTag(updateTag, newID) logic.ReturnSuccessResponse(w, r, "updating tags") diff --git a/logic/tags.go b/logic/tags.go index 0f6ea2780..7436aa266 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -15,7 +15,7 @@ var tagMutex = &sync.RWMutex{} // GetTag - fetches tag info func GetTag(tagID models.TagID) (models.Tag, error) { data, err := database.FetchRecord(database.TAG_TABLE_NAME, tagID.String()) - if err != nil && !database.IsEmptyRecord(err) { + if err != nil { return models.Tag{}, err } tag := models.Tag{} @@ -137,11 +137,21 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) { if node.Tags == nil { node.Tags = make(map[models.TagID]struct{}) } - node.Tags[req.ID] = struct{}{} + if newID != "" { + node.Tags[newID] = struct{}{} + } else { + node.Tags[req.ID] = struct{}{} + } UpsertNode(&node) } else { + if newID != "" { + delete(node.Tags, req.ID) + node.Tags[newID] = struct{}{} + UpsertNode(&node) + } delete(tagNodesMap, node.ID.String()) } + } for _, deletedTaggedNode := range tagNodesMap { deletedTaggedHost := deletedTaggedNode From 6c107246221d2ae9320989bd815fad3e93113849 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 22 Sep 2024 18:24:48 +0400 Subject: [PATCH 025/169] add mutex to tag operations --- logic/tags.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/logic/tags.go b/logic/tags.go index 7436aa266..769d0c036 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -28,6 +28,8 @@ func GetTag(tagID models.TagID) (models.Tag, error) { // InsertTag - creates new tag func InsertTag(tag models.Tag) error { + tagMutex.Lock() + defer tagMutex.Unlock() _, err := database.FetchRecord(database.TAG_TABLE_NAME, tag.ID.String()) if err == nil { return fmt.Errorf("tag `%s` exists already", tag.ID) @@ -41,6 +43,8 @@ func InsertTag(tag models.Tag) error { // DeleteTag - delete tag, will also untag hosts func DeleteTag(tagID models.TagID) error { + tagMutex.Lock() + defer tagMutex.Unlock() // cleanUp tags on hosts tag, err := GetTag(tagID) if err != nil { @@ -62,8 +66,6 @@ func DeleteTag(tagID models.TagID) error { // ListTagsWithHosts - lists all tags with tagged hosts func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) { - tagMutex.RLock() - defer tagMutex.RUnlock() tags, err := ListNetworkTags(netID) if err != nil { return []models.TagListResp{}, err @@ -83,7 +85,8 @@ func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) { // ListTags - lists all tags from DB func ListTags() ([]models.Tag, error) { - + tagMutex.RLock() + defer tagMutex.RUnlock() data, err := database.FetchRecords(database.TAG_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Tag{}, err @@ -102,7 +105,8 @@ func ListTags() ([]models.Tag, error) { // ListTags - lists all tags from DB func ListNetworkTags(netID models.NetworkID) ([]models.Tag, error) { - + tagMutex.RLock() + defer tagMutex.RUnlock() data, err := database.FetchRecords(database.TAG_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Tag{}, err From 873d3ea8d8c2c35685126e225546e32dd9776e4a Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 23 Sep 2024 16:09:59 +0400 Subject: [PATCH 026/169] define acl model --- models/acl.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 models/acl.go diff --git a/models/acl.go b/models/acl.go new file mode 100644 index 000000000..54fe4057e --- /dev/null +++ b/models/acl.go @@ -0,0 +1,27 @@ +package models + +type SrcType string +type DstType string + +// AllowedTrafficDirection - allowed direction of traffic +type AllowedTrafficDirection int + +const ( + // TrafficDirectionUni implies traffic is only allowed in one direction (src --> dst) + TrafficDirectionUni AllowedTrafficDirection = iota + // TrafficDirectionBi implies traffic is allowed both direction (src <--> dst ) + TrafficDirectionBi +) + +const ( + SrcUser SrcType = "user" + SrcHost SrcType = "host" + + DstHost DstType = "host" +) + +type Acl struct { + Src SrcType `json:"src_type"` + Dst DstType `json:"dst_type"` + AllowedDirection AllowedTrafficDirection `json:"allowed_traffic_direction"` +} From e258f12ecbe8d2453388db636c367c691b6550a5 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 24 Sep 2024 19:09:15 +0400 Subject: [PATCH 027/169] set Acl DB crud --- database/database.go | 2 ++ logic/acls.go | 40 ++++++++++++++++++++++++++++++++++++++++ models/acl.go | 22 ++++++++++++++-------- 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 logic/acls.go diff --git a/database/database.go b/database/database.go index 2a950b6c3..5bd684998 100644 --- a/database/database.go +++ b/database/database.go @@ -47,6 +47,8 @@ const ( GENERATED_TABLE_NAME = "generated" // NODE_ACLS_TABLE_NAME - stores the node ACL rules NODE_ACLS_TABLE_NAME = "nodeacls" + // ACLS_TABLE_NAME - table for acls v2 + ACLS_TABLE_NAME = "acls" // SSO_STATE_CACHE - holds sso session information for OAuth2 sign-ins SSO_STATE_CACHE = "ssostatecache" // METRICS_TABLE_NAME - stores network metrics diff --git a/logic/acls.go b/logic/acls.go new file mode 100644 index 000000000..fc5f4d3a4 --- /dev/null +++ b/logic/acls.go @@ -0,0 +1,40 @@ +package logic + +import ( + "encoding/json" + + "github.com/gravitl/netmaker/database" + "github.com/gravitl/netmaker/models" +) + +// Create - creates acl policy +func Create(a models.Acl) error { + d, err := json.Marshal(a) + if err != nil { + return err + } + return database.Insert(a.ID.String(), string(d), database.ACLS_TABLE_NAME) +} + +// Delete - deletes acl policy +func Delete(a models.Acl) error { + return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) +} + +// List - lists all acl policies +func List(a models.Acl) ([]models.Acl, error) { + data, err := database.FetchRecords(database.TAG_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Acl{}, err + } + acls := []models.Acl{} + for _, dataI := range data { + acl := models.Acl{} + err := json.Unmarshal([]byte(dataI), &acl) + if err != nil { + continue + } + acls = append(acls, acl) + } + return acls, nil +} diff --git a/models/acl.go b/models/acl.go index 54fe4057e..094ecfea0 100644 --- a/models/acl.go +++ b/models/acl.go @@ -1,7 +1,8 @@ package models -type SrcType string -type DstType string +import ( + "github.com/google/uuid" +) // AllowedTrafficDirection - allowed direction of traffic type AllowedTrafficDirection int @@ -13,15 +14,20 @@ const ( TrafficDirectionBi ) -const ( - SrcUser SrcType = "user" - SrcHost SrcType = "host" +type AclPolicyType string - DstHost DstType = "host" +const ( + UserPolicy AclPolicyType = "user-policy" + DevicePolicy AclPolicyType = "device-policy" ) type Acl struct { - Src SrcType `json:"src_type"` - Dst DstType `json:"dst_type"` + ID uuid.UUID `json:"id"` + Name string `json:"name"` + NetworkID NetworkID `json:"network_id"` + RuleType AclPolicyType `json:"policy_type"` + Src []string `json:"src_type"` + Dst []string `json:"dst_type"` AllowedDirection AllowedTrafficDirection `json:"allowed_traffic_direction"` + Enabled bool `json:"enabled"` } From 6bc59adb2c6e2e7971497175f1df014d37b5a8d0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 24 Sep 2024 19:45:45 +0400 Subject: [PATCH 028/169] add acls api handlers --- controllers/acls.go | 150 ++++++++++++++++++++++++++++++++++++++ controllers/controller.go | 1 + logic/acls.go | 53 ++++++++++++-- models/acl.go | 4 + 4 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 controllers/acls.go diff --git a/controllers/acls.go b/controllers/acls.go new file mode 100644 index 000000000..90044e0f6 --- /dev/null +++ b/controllers/acls.go @@ -0,0 +1,150 @@ +package controller + +import ( + "encoding/json" + "errors" + "net/http" + "net/url" + "time" + + "github.com/google/uuid" + "github.com/gorilla/mux" + "github.com/gravitl/netmaker/logger" + "github.com/gravitl/netmaker/logic" + "github.com/gravitl/netmaker/models" +) + +func aclHandlers(r *mux.Router) { + r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(getAcls))). + Methods(http.MethodGet) + r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(createAcl))). + Methods(http.MethodPost) + r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(updateAcl))). + Methods(http.MethodPut) + r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(deleteAcl))). + Methods(http.MethodDelete) + +} + +// @Summary List Acls in a network +// @Router /api/v1/acls [get] +// @Tags ACL +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func getAcls(w http.ResponseWriter, r *http.Request) { + netID, _ := url.QueryUnescape(r.URL.Query().Get("network")) + if netID == "" { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network id param is missing"), "badrequest")) + return + } + // check if network exists + _, err := logic.GetNetwork(netID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + acls, err := logic.ListAcls(models.NetworkID(netID)) + if err != nil { + logger.Log(0, r.Header.Get("user"), "failed to get all network acl entries: ", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + logic.SortAclEntrys(acls[:]) + logic.ReturnSuccessResponseWithJson(w, r, acls, "fetched all acls in the network "+netID) +} + +// @Summary Create Acl +// @Router /api/v1/acls [post] +// @Tags ACL +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func createAcl(w http.ResponseWriter, r *http.Request) { + var req models.Acl + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + logger.Log(0, "error decoding request body: ", + err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + user, err := logic.GetUser(r.Header.Get("user")) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + // check if acl network exists + _, err = logic.GetNetwork(req.NetworkID.String()) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to get network details for "+req.NetworkID.String()), "badrequest")) + return + } + // check if acl exists + acl := req + acl.ID = uuid.New() + acl.CreatedBy = user.UserName + acl.CreatedAt = time.Now().UTC() + + err = logic.InsertAcl(acl) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + + logic.ReturnSuccessResponseWithJson(w, r, req, "created acl successfully") +} + +// @Summary Update Acl +// @Router /api/v1/acls [put] +// @Tags ACL +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func updateAcl(w http.ResponseWriter, r *http.Request) { + var updateAcl models.Acl + err := json.NewDecoder(r.Body).Decode(&updateAcl) + if err != nil { + logger.Log(0, "error decoding request body: ", + err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + + acl, err := logic.GetAcl(updateAcl.ID.String()) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + err = logic.UpdateAcl(updateAcl, acl) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + logic.ReturnSuccessResponse(w, r, "updated acl "+updateAcl.Name) +} + +// @Summary Delete Acl +// @Router /api/v1/acls [delete] +// @Tags ACL +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func deleteAcl(w http.ResponseWriter, r *http.Request) { + aclID, _ := url.QueryUnescape(r.URL.Query().Get("acl_id")) + if aclID == "" { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("acl id is required"), "badrequest")) + return + } + acl, err := logic.GetAcl(aclID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + err = logic.DeleteAcl(acl) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + logic.ReturnSuccessResponse(w, r, "deleted acl "+acl.Name) +} diff --git a/controllers/controller.go b/controllers/controller.go index 5a1396d3d..317536dd8 100644 --- a/controllers/controller.go +++ b/controllers/controller.go @@ -35,6 +35,7 @@ var HttpHandlers = []interface{}{ hostHandlers, enrollmentKeyHandlers, tagHandlers, + aclHandlers, legacyHandlers, } diff --git a/logic/acls.go b/logic/acls.go index fc5f4d3a4..d8c11642b 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -2,13 +2,14 @@ package logic import ( "encoding/json" + "sort" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" ) -// Create - creates acl policy -func Create(a models.Acl) error { +// InsertAcl - creates acl policy +func InsertAcl(a models.Acl) error { d, err := json.Marshal(a) if err != nil { return err @@ -16,13 +17,42 @@ func Create(a models.Acl) error { return database.Insert(a.ID.String(), string(d), database.ACLS_TABLE_NAME) } -// Delete - deletes acl policy -func Delete(a models.Acl) error { +func GetAcl(aID string) (models.Acl, error) { + a := models.Acl{} + d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID) + if err != nil { + return a, err + } + err = json.Unmarshal([]byte(d), &a) + if err != nil { + return a, err + } + return a, nil +} + +// UpdateAcl - updates allowed fields on acls and commits to DB +func UpdateAcl(newAcl, acl models.Acl) error { + if newAcl.Name != "" { + acl.Name = newAcl.Name + } + acl.Src = newAcl.Src + acl.Dst = newAcl.Dst + acl.AllowedDirection = newAcl.AllowedDirection + acl.Enabled = newAcl.Enabled + d, err := json.Marshal(acl) + if err != nil { + return err + } + return database.Insert(acl.ID.String(), string(d), database.ACLS_TABLE_NAME) +} + +// DeleteAcl - deletes acl policy +func DeleteAcl(a models.Acl) error { return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) } -// List - lists all acl policies -func List(a models.Acl) ([]models.Acl, error) { +// ListAcls - lists all acl policies +func ListAcls(netID models.NetworkID) ([]models.Acl, error) { data, err := database.FetchRecords(database.TAG_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{}, err @@ -34,7 +64,16 @@ func List(a models.Acl) ([]models.Acl, error) { if err != nil { continue } - acls = append(acls, acl) + if acl.NetworkID == netID { + acls = append(acls, acl) + } } return acls, nil } + +// SortTagEntrys - Sorts slice of Tag entries by their id +func SortAclEntrys(acls []models.Acl) { + sort.Slice(acls, func(i, j int) bool { + return acls[i].Name < acls[j].Name + }) +} diff --git a/models/acl.go b/models/acl.go index 094ecfea0..2d041ac62 100644 --- a/models/acl.go +++ b/models/acl.go @@ -1,6 +1,8 @@ package models import ( + "time" + "github.com/google/uuid" ) @@ -30,4 +32,6 @@ type Acl struct { Dst []string `json:"dst_type"` AllowedDirection AllowedTrafficDirection `json:"allowed_traffic_direction"` Enabled bool `json:"enabled"` + CreatedBy string `json:"created_by"` + CreatedAt time.Time `json:"created_at"` } From 630928b4f7b2c8d70db4bb9b7e3c3b28a81c50bd Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 25 Sep 2024 10:37:44 +0400 Subject: [PATCH 029/169] add acl policy checker --- controllers/acls.go | 10 ++++++++- logic/acls.go | 54 +++++++++++++++++++++++++++++++++++++++++++++ models/acl.go | 11 +++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/controllers/acls.go b/controllers/acls.go index 90044e0f6..e5c8e796b 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -85,7 +85,11 @@ func createAcl(w http.ResponseWriter, r *http.Request) { acl.ID = uuid.New() acl.CreatedBy = user.UserName acl.CreatedAt = time.Now().UTC() - + // validate create acl policy + if !logic.IsAclPolicyValid(acl) { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) + return + } err = logic.InsertAcl(acl) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) @@ -116,6 +120,10 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + if !logic.IsAclPolicyValid(updateAcl) { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) + return + } err = logic.UpdateAcl(updateAcl, acl) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) diff --git a/logic/acls.go b/logic/acls.go index d8c11642b..01163952b 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -3,6 +3,7 @@ package logic import ( "encoding/json" "sort" + "strings" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" @@ -30,6 +31,59 @@ func GetAcl(aID string) (models.Acl, error) { return a, nil } +func IsAclPolicyValid(acl models.Acl) bool { + //check if src and dst are valid + isValid := false + switch acl.RuleType { + case models.UserPolicy: + // src list should only contain users + for _, srcI := range acl.Src { + userTagLi := strings.Split(srcI, ":") + if len(userTagLi) < 2 { + break + } + if userTagLi[0] != models.UserAcl.String() && + userTagLi[0] != models.UserGroupAcl.String() { + break + } + } + for _, dstI := range acl.Dst { + dstILi := strings.Split(dstI, ":") + if len(dstILi) < 2 { + break + } + if dstILi[0] == models.UserAcl.String() || + dstILi[0] == models.UserGroupAcl.String() { + break + } + } + isValid = true + case models.DevicePolicy: + for _, srcI := range acl.Src { + userTagLi := strings.Split(srcI, ":") + if len(userTagLi) < 2 { + break + } + if userTagLi[0] == models.UserAcl.String() || + userTagLi[0] == models.UserGroupAcl.String() { + break + } + } + for _, dstI := range acl.Dst { + dstILi := strings.Split(dstI, ":") + if len(dstILi) < 2 { + break + } + if dstILi[0] == models.UserAcl.String() || + dstILi[0] == models.UserGroupAcl.String() { + break + } + } + isValid = true + } + return isValid +} + // UpdateAcl - updates allowed fields on acls and commits to DB func UpdateAcl(newAcl, acl models.Acl) error { if newAcl.Name != "" { diff --git a/models/acl.go b/models/acl.go index 2d041ac62..761d641e7 100644 --- a/models/acl.go +++ b/models/acl.go @@ -23,6 +23,17 @@ const ( DevicePolicy AclPolicyType = "device-policy" ) +type AclGroupType string + +const ( + UserAcl AclGroupType = "user" + UserGroupAcl AclGroupType = "user-group" +) + +func (g AclGroupType) String() string { + return string(g) +} + type Acl struct { ID uuid.UUID `json:"id"` Name string `json:"name"` From 00b082d11cb2b9379e77aca20c5702af5f486a49 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 25 Sep 2024 13:01:40 +0400 Subject: [PATCH 030/169] add validation check for tags --- logic/acls.go | 43 ++++++++++++++++++++++++++++++------------ logic/user_mgmt.go | 3 +++ models/acl.go | 7 +++++-- pro/initialize.go | 1 + pro/logic/user_mgmt.go | 10 ++++++++++ 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 01163952b..2ca682172 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -42,40 +42,59 @@ func IsAclPolicyValid(acl models.Acl) bool { if len(userTagLi) < 2 { break } - if userTagLi[0] != models.UserAcl.String() && - userTagLi[0] != models.UserGroupAcl.String() { + if userTagLi[0] != models.UserAclID.String() && + userTagLi[0] != models.UserGroupAclID.String() { break } + // check if user group is valid + if userTagLi[0] == models.UserAclID.String() { + _, err := GetUser(userTagLi[1]) + if err != nil { + break + } + } else if userTagLi[0] == models.UserGroupAclID.String() { + err := IsGroupValid(models.UserGroupID(userTagLi[1])) + if err != nil { + break + } + } + } for _, dstI := range acl.Dst { dstILi := strings.Split(dstI, ":") if len(dstILi) < 2 { break } - if dstILi[0] == models.UserAcl.String() || - dstILi[0] == models.UserGroupAcl.String() { + if dstILi[0] == models.UserAclID.String() || + dstILi[0] == models.UserGroupAclID.String() { + break + } + if dstILi[0] != models.DeviceAclID.String() { + break + } + // check if tag is valid + _, err := GetTag(models.TagID(dstILi[1])) + if err != nil { break } } isValid = true case models.DevicePolicy: for _, srcI := range acl.Src { - userTagLi := strings.Split(srcI, ":") - if len(userTagLi) < 2 { + deviceTagLi := strings.Split(srcI, ":") + if len(deviceTagLi) < 2 { break } - if userTagLi[0] == models.UserAcl.String() || - userTagLi[0] == models.UserGroupAcl.String() { + if deviceTagLi[0] != models.DeviceAclID.String() { break } } for _, dstI := range acl.Dst { - dstILi := strings.Split(dstI, ":") - if len(dstILi) < 2 { + deviceTagLi := strings.Split(dstI, ":") + if len(deviceTagLi) < 2 { break } - if dstILi[0] == models.UserAcl.String() || - dstILi[0] == models.UserGroupAcl.String() { + if deviceTagLi[0] != models.DeviceAclID.String() { break } } diff --git a/logic/user_mgmt.go b/logic/user_mgmt.go index 8727cb57a..31cba66cd 100644 --- a/logic/user_mgmt.go +++ b/logic/user_mgmt.go @@ -39,6 +39,9 @@ var FilterNetworksByRole = func(allnetworks []models.Network, user models.User) var IsGroupsValid = func(groups map[models.UserGroupID]struct{}) error { return nil } +var IsGroupValid = func(groupID models.UserGroupID) error { + return nil +} var IsNetworkRolesValid = func(networkRoles map[models.NetworkID]map[models.UserRoleID]struct{}) error { return nil } diff --git a/models/acl.go b/models/acl.go index 761d641e7..504681170 100644 --- a/models/acl.go +++ b/models/acl.go @@ -26,8 +26,11 @@ const ( type AclGroupType string const ( - UserAcl AclGroupType = "user" - UserGroupAcl AclGroupType = "user-group" + UserAclID AclGroupType = "user" + UserGroupAclID AclGroupType = "user-group" + DeviceAclID AclGroupType = "tag" + NetmakerIPAclID AclGroupType = "ip" + NetmakerSubNetRangeAClID AclGroupType = "ipset" ) func (g AclGroupType) String() string { diff --git a/pro/initialize.go b/pro/initialize.go index 1c6ba8a1c..3dfae5807 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -130,6 +130,7 @@ func InitPro() { logic.CreateDefaultNetworkRolesAndGroups = proLogic.CreateDefaultNetworkRolesAndGroups logic.FilterNetworksByRole = proLogic.FilterNetworksByRole logic.IsGroupsValid = proLogic.IsGroupsValid + logic.IsGroupValid = proLogic.IsGroupValid logic.IsNetworkRolesValid = proLogic.IsNetworkRolesValid logic.InitialiseRoles = proLogic.UserRolesInit logic.UpdateUserGwAccess = proLogic.UpdateUserGwAccess diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 84c5987bb..af4d4c79b 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -789,6 +789,16 @@ func IsGroupsValid(groups map[models.UserGroupID]struct{}) error { return nil } +func IsGroupValid(groupID models.UserGroupID) error { + + _, err := GetUserGroup(groupID) + if err != nil { + return fmt.Errorf("user group `%s` not found", groupID) + } + + return nil +} + func IsNetworkRolesValid(networkRoles map[models.NetworkID]map[models.UserRoleID]struct{}) error { for netID, netRoles := range networkRoles { From fcd3325173da87f0909616baf40b1e4932af2f2e Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 25 Sep 2024 16:06:08 +0400 Subject: [PATCH 031/169] enforce new acl policy access check --- logic/acls.go | 122 ++++++++++++++++++++++++++++++++++++++++--------- logic/peers.go | 1 + models/acl.go | 10 +++- 3 files changed, 110 insertions(+), 23 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 2ca682172..06c78abe4 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -2,8 +2,8 @@ package logic import ( "encoding/json" + "errors" "sort" - "strings" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" @@ -38,22 +38,22 @@ func IsAclPolicyValid(acl models.Acl) bool { case models.UserPolicy: // src list should only contain users for _, srcI := range acl.Src { - userTagLi := strings.Split(srcI, ":") - if len(userTagLi) < 2 { + + if srcI.ID == "" || srcI.Value == "" { break } - if userTagLi[0] != models.UserAclID.String() && - userTagLi[0] != models.UserGroupAclID.String() { + if srcI.ID != models.UserAclID && + srcI.ID != models.UserGroupAclID { break } // check if user group is valid - if userTagLi[0] == models.UserAclID.String() { - _, err := GetUser(userTagLi[1]) + if srcI.ID == models.UserAclID { + _, err := GetUser(srcI.Value) if err != nil { break } - } else if userTagLi[0] == models.UserGroupAclID.String() { - err := IsGroupValid(models.UserGroupID(userTagLi[1])) + } else if srcI.ID == models.UserGroupAclID { + err := IsGroupValid(models.UserGroupID(srcI.Value)) if err != nil { break } @@ -61,19 +61,19 @@ func IsAclPolicyValid(acl models.Acl) bool { } for _, dstI := range acl.Dst { - dstILi := strings.Split(dstI, ":") - if len(dstILi) < 2 { + + if dstI.ID == "" || dstI.Value == "" { break } - if dstILi[0] == models.UserAclID.String() || - dstILi[0] == models.UserGroupAclID.String() { + if dstI.ID == models.UserAclID || + dstI.ID == models.UserGroupAclID { break } - if dstILi[0] != models.DeviceAclID.String() { + if dstI.ID != models.DeviceAclID { break } // check if tag is valid - _, err := GetTag(models.TagID(dstILi[1])) + _, err := GetTag(models.TagID(dstI.Value)) if err != nil { break } @@ -81,20 +81,29 @@ func IsAclPolicyValid(acl models.Acl) bool { isValid = true case models.DevicePolicy: for _, srcI := range acl.Src { - deviceTagLi := strings.Split(srcI, ":") - if len(deviceTagLi) < 2 { + if srcI.ID == "" || srcI.Value == "" { + break + } + if srcI.ID != models.DeviceAclID { break } - if deviceTagLi[0] != models.DeviceAclID.String() { + // check if tag is valid + _, err := GetTag(models.TagID(srcI.Value)) + if err != nil { break } } for _, dstI := range acl.Dst { - deviceTagLi := strings.Split(dstI, ":") - if len(deviceTagLi) < 2 { + + if dstI.ID == "" || dstI.Value == "" { + break + } + if dstI.ID != models.DeviceAclID { break } - if deviceTagLi[0] != models.DeviceAclID.String() { + // check if tag is valid + _, err := GetTag(models.TagID(dstI.Value)) + if err != nil { break } } @@ -124,6 +133,36 @@ func DeleteAcl(a models.Acl) error { return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) } +func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) { + acls, _ := ListAcls(netID) + for _, acl := range acls { + if acl.Default && acl.RuleType == ruleType { + return acl, nil + } + } + return models.Acl{}, errors.New("default rule not found") +} + +// listDevicePolicies - lists all device policies in a network +func listDevicePolicies(netID models.NetworkID) []models.Acl { + data, err := database.FetchRecords(database.TAG_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Acl{} + } + acls := []models.Acl{} + for _, dataI := range data { + acl := models.Acl{} + err := json.Unmarshal([]byte(dataI), &acl) + if err != nil { + continue + } + if acl.NetworkID == netID && acl.RuleType == models.DevicePolicy { + acls = append(acls, acl) + } + } + return acls +} + // ListAcls - lists all acl policies func ListAcls(netID models.NetworkID) ([]models.Acl, error) { data, err := database.FetchRecords(database.TAG_TABLE_NAME) @@ -144,6 +183,47 @@ func ListAcls(netID models.NetworkID) ([]models.Acl, error) { return acls, nil } +func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { + aclValueMap := make(map[string]struct{}) + for _, aclTagI := range acltags { + aclValueMap[aclTagI.ID.String()] = struct{}{} + } + return aclValueMap +} + +func IsNodeAllowedToCommunicate(node, peer models.Node) bool { + // check default policy if all allowed return true + defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) + if err == nil { + if defaultPolicy.Enabled { + return true + } + } + // list device policies + policies := listDevicePolicies(models.NetworkID(peer.Network)) + for _, policy := range policies { + srcMap := convAclTagToValueMap(policy.Src) + dstMap := convAclTagToValueMap(policy.Dst) + for tagID := range peer.Tags { + if _, ok := dstMap[tagID.String()]; ok { + for tagID := range node.Tags { + if _, ok := srcMap[tagID.String()]; ok { + return true + } + } + } + if _, ok := srcMap[tagID.String()]; ok { + for tagID := range node.Tags { + if _, ok := dstMap[tagID.String()]; ok { + return true + } + } + } + } + } + return false +} + // SortTagEntrys - Sorts slice of Tag entries by their id func SortAclEntrys(acls []models.Acl) { sort.Slice(acls, func(i, j int) bool { diff --git a/logic/peers.go b/logic/peers.go index 77e76a2a9..ead2bc3b8 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -241,6 +241,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N !peer.PendingDelete && peer.Connected && nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) && + IsNodeAllowedToCommunicate(node, peer) && (deletedNode == nil || (deletedNode != nil && peer.ID.String() != deletedNode.ID.String())) { peerConfig.AllowedIPs = allowedips // only append allowed IPs if valid connection } diff --git a/models/acl.go b/models/acl.go index 504681170..17386149e 100644 --- a/models/acl.go +++ b/models/acl.go @@ -23,6 +23,11 @@ const ( DevicePolicy AclPolicyType = "device-policy" ) +type AclPolicyTag struct { + ID AclGroupType `json:"id"` + Value string `json:"value"` +} + type AclGroupType string const ( @@ -39,11 +44,12 @@ func (g AclGroupType) String() string { type Acl struct { ID uuid.UUID `json:"id"` + Default bool `json:"default"` Name string `json:"name"` NetworkID NetworkID `json:"network_id"` RuleType AclPolicyType `json:"policy_type"` - Src []string `json:"src_type"` - Dst []string `json:"dst_type"` + Src []AclPolicyTag `json:"src_type"` + Dst []AclPolicyTag `json:"dst_type"` AllowedDirection AllowedTrafficDirection `json:"allowed_traffic_direction"` Enabled bool `json:"enabled"` CreatedBy string `json:"created_by"` From 3d327bb89e1a569800d4d7122c90f682e9b080a0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 25 Sep 2024 18:18:23 +0400 Subject: [PATCH 032/169] fetch user gw via access policy --- logic/acls.go | 51 ++++++++++++++++++++++++++++++++++++++++ logic/nodes.go | 22 ++++++++++++----- logic/tags.go | 2 +- pro/controllers/users.go | 2 +- pro/logic/user_mgmt.go | 17 ++++++++++++++ 5 files changed, 86 insertions(+), 8 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 06c78abe4..16cea43f7 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -143,6 +143,57 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo return models.Acl{}, errors.New("default rule not found") } +func ListUserPolicies(u models.User) []models.Acl { + data, err := database.FetchRecords(database.TAG_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Acl{} + } + acls := []models.Acl{} + for _, dataI := range data { + acl := models.Acl{} + err := json.Unmarshal([]byte(dataI), &acl) + if err != nil { + continue + } + + if acl.RuleType == models.UserPolicy { + srcMap := convAclTagToValueMap(acl.Src) + if _, ok := srcMap[u.UserName]; ok { + acls = append(acls, acl) + } else { + // check for user groups + for gID := range u.UserGroups { + if _, ok := srcMap[gID.String()]; ok { + acls = append(acls, acl) + break + } + } + } + + } + } + return acls +} + +func ListUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { + data, err := database.FetchRecords(database.TAG_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Acl{} + } + acls := []models.Acl{} + for _, dataI := range data { + acl := models.Acl{} + err := json.Unmarshal([]byte(dataI), &acl) + if err != nil { + continue + } + if acl.NetworkID == netID && acl.RuleType == models.UserPolicy { + acls = append(acls, acl) + } + } + return acls +} + // listDevicePolicies - lists all device policies in a network func listDevicePolicies(netID models.NetworkID) []models.Acl { data, err := database.FetchRecords(database.TAG_TABLE_NAME) diff --git a/logic/nodes.go b/logic/nodes.go index af59f6e95..5c0b2f8e9 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -702,7 +702,21 @@ func GetAllFailOvers() ([]models.Node, error) { return igs, nil } -func GetTagMapWithNodes(netID models.NetworkID) (tagNodesMap map[models.TagID][]models.Node) { +func GetTagMapWithNodes() (tagNodesMap map[models.TagID][]models.Node) { + tagNodesMap = make(map[models.TagID][]models.Node) + nodes, _ := GetAllNodes() + for _, nodeI := range nodes { + if nodeI.Tags == nil { + continue + } + for nodeTagID := range nodeI.Tags { + tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) + } + } + return +} + +func GetTagMapWithNodesByNetwork(netID models.NetworkID) (tagNodesMap map[models.TagID][]models.Node) { tagNodesMap = make(map[models.TagID][]models.Node) nodes, _ := GetNetworkNodes(netID.String()) for _, nodeI := range nodes { @@ -710,11 +724,7 @@ func GetTagMapWithNodes(netID models.NetworkID) (tagNodesMap map[models.TagID][] continue } for nodeTagID := range nodeI.Tags { - if _, ok := tagNodesMap[nodeTagID]; ok { - tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) - } else { - tagNodesMap[nodeTagID] = []models.Node{nodeI} - } + tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) } } return diff --git a/logic/tags.go b/logic/tags.go index 769d0c036..5b89bc89d 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -70,7 +70,7 @@ func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) { if err != nil { return []models.TagListResp{}, err } - tagsNodeMap := GetTagMapWithNodes(netID) + tagsNodeMap := GetTagMapWithNodesByNetwork(netID) resp := []models.TagListResp{} for _, tagI := range tags { tagRespI := models.TagListResp{ diff --git a/pro/controllers/users.go b/pro/controllers/users.go index fbd6db9df..18978e9c1 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -861,7 +861,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) for _, extClient := range allextClients { node, ok := userGwNodes[extClient.IngressGatewayID] if !ok { diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index af4d4c79b..0c52bc082 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -508,6 +508,23 @@ func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, n _, ok = rsrcScope[rsrcID] return ok } + +func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { + gws = make(map[string]models.Node) + + tagNodesMap := logic.GetTagMapWithNodes() + accessPolices := logic.ListUserPolicies(user) + for _, policyI := range accessPolices { + for _, dstI := range policyI.Dst { + if nodes, ok := tagNodesMap[models.TagID(dstI.Value)]; ok { + for _, node := range nodes { + gws[node.ID.String()] = node + } + } + } + } + return +} func GetUserRAGNodes(user models.User) (gws map[string]models.Node) { gws = make(map[string]models.Node) userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user) From dfed77906aed6d129dd722193d218a90e688cea8 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 25 Sep 2024 20:24:04 +0400 Subject: [PATCH 033/169] create default acl policies on network creation --- controllers/network.go | 3 +- logic/acls.go | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/controllers/network.go b/controllers/network.go index acb479ec9..f340e836c 100644 --- a/controllers/network.go +++ b/controllers/network.go @@ -412,6 +412,7 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) { return } go logic.DeleteNetworkRoles(network) + go logic.DeleteDefaultNetworkPolicies(models.NetworkID(network)) //delete network from allocated ip map go logic.RemoveNetworkFromAllocatedIpMap(network) @@ -487,7 +488,7 @@ func createNetwork(w http.ResponseWriter, r *http.Request) { return } logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(network.NetID)) - + logic.CreateDefaultAclNetworkPolicies(models.NetworkID(network.NetID)) //add new network to allocated ip map go logic.AddNetworkToAllocatedIpMap(network.NetID) diff --git a/logic/acls.go b/logic/acls.go index 16cea43f7..382bd43f3 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -4,11 +4,75 @@ import ( "encoding/json" "errors" "sort" + "time" + "github.com/google/uuid" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" ) +// CreateDefaultAclNetworkPolicies - create default acl network policies +func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { + defaultDeviceAcl := models.Acl{ + ID: uuid.New(), + Default: true, + Name: "all-nodes", + NetworkID: netID, + RuleType: models.DevicePolicy, + Src: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionBi, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + InsertAcl(defaultDeviceAcl) + defaultUserAcl := models.Acl{ + ID: uuid.New(), + Default: true, + Name: "all-users", + NetworkID: netID, + RuleType: models.UserPolicy, + Src: []models.AclPolicyTag{ + { + ID: models.UserAclID, + Value: "*", + }, + { + ID: models.UserGroupAclID, + Value: "*", + }, + }, + Dst: []models.AclPolicyTag{{ + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + InsertAcl(defaultUserAcl) +} + +// DeleteDefaultNetworkPolicies - deletes all default network acl policies +func DeleteDefaultNetworkPolicies(netId models.NetworkID) { + acls, _ := ListAcls(netId) + for _, acl := range acls { + if acl.NetworkID == netId && acl.Default { + DeleteAcl(acl) + } + } +} + // InsertAcl - creates acl policy func InsertAcl(a models.Acl) error { d, err := json.Marshal(a) @@ -18,6 +82,7 @@ func InsertAcl(a models.Acl) error { return database.Insert(a.ID.String(), string(d), database.ACLS_TABLE_NAME) } +// GetAcl - gets acl info by id func GetAcl(aID string) (models.Acl, error) { a := models.Acl{} d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID) @@ -31,6 +96,7 @@ func GetAcl(aID string) (models.Acl, error) { return a, nil } +// IsAclPolicyValid - validates if acl policy is valid func IsAclPolicyValid(acl models.Acl) bool { //check if src and dst are valid isValid := false @@ -133,6 +199,7 @@ func DeleteAcl(a models.Acl) error { return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) } +// GetDefaultPolicy - fetches default policy in the network by ruleType func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) { acls, _ := ListAcls(netID) for _, acl := range acls { @@ -143,6 +210,7 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo return models.Acl{}, errors.New("default rule not found") } +// ListUserPolicies - lists all acl policies enforced on an user func ListUserPolicies(u models.User) []models.Acl { data, err := database.FetchRecords(database.TAG_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { @@ -175,6 +243,7 @@ func ListUserPolicies(u models.User) []models.Acl { return acls } +// ListUserPoliciesByNetwork - lists all acl user policies in a network func ListUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { data, err := database.FetchRecords(database.TAG_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { @@ -242,6 +311,7 @@ func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { return aclValueMap } +// IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // check default policy if all allowed return true defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) From 4e825f7b9e7604d689263d6a4efa63aa416bb6cc Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 25 Sep 2024 20:25:23 +0400 Subject: [PATCH 034/169] force set default acl field to false --- controllers/acls.go | 1 + 1 file changed, 1 insertion(+) diff --git a/controllers/acls.go b/controllers/acls.go index e5c8e796b..1321a4630 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -85,6 +85,7 @@ func createAcl(w http.ResponseWriter, r *http.Request) { acl.ID = uuid.New() acl.CreatedBy = user.UserName acl.CreatedAt = time.Now().UTC() + acl.Default = false // validate create acl policy if !logic.IsAclPolicyValid(acl) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) From d58439ac9dd07ac1b4e2948b2a656f369a4bef68 Mon Sep 17 00:00:00 2001 From: Abhishek K Date: Thu, 26 Sep 2024 11:52:21 +0400 Subject: [PATCH 035/169] api for network with stats (#3111) --- controllers/network.go | 44 ++++++++++++++++++++++++++++++++++++++++++ models/network.go | 5 +++++ 2 files changed, 49 insertions(+) diff --git a/controllers/network.go b/controllers/network.go index acb479ec9..03f40cb9e 100644 --- a/controllers/network.go +++ b/controllers/network.go @@ -24,6 +24,8 @@ import ( func networkHandlers(r *mux.Router) { r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))). Methods(http.MethodGet) + r.HandleFunc("/api/v1/networks/stats", logic.SecurityCheck(true, http.HandlerFunc(getNetworksStats))). + Methods(http.MethodGet) r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))). Methods(http.MethodPost) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(getNetwork))). @@ -74,6 +76,48 @@ func getNetworks(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(allnetworks) } +// @Summary Lists all networks with stats +// @Router /api/v1/networks/stats [get] +// @Tags Networks +// @Security oauth +// @Produce json +// @Success 200 {object} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func getNetworksStats(w http.ResponseWriter, r *http.Request) { + + var err error + allnetworks, err := logic.GetNetworks() + if err != nil && !database.IsEmptyRecord(err) { + slog.Error("failed to fetch networks", "error", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + if r.Header.Get("ismaster") != "yes" { + username := r.Header.Get("user") + user, err := logic.GetUser(username) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + allnetworks = logic.FilterNetworksByRole(allnetworks, *user) + } + allNodes, err := logic.GetAllNodes() + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + netstats := []models.NetworkStatResp{} + logic.SortNetworks(allnetworks[:]) + for _, network := range allnetworks { + netstats = append(netstats, models.NetworkStatResp{ + Network: network, + Hosts: len(logic.GetNetworkNodesMemory(allNodes, network.NetID)), + }) + } + logger.Log(2, r.Header.Get("user"), "fetched networks.") + logic.ReturnSuccessResponseWithJson(w, r, netstats, "fetched networks with stats") +} + // @Summary Get a network // @Router /api/networks/{networkname} [get] // @Tags Networks diff --git a/models/network.go b/models/network.go index c29b45d74..32d95f865 100644 --- a/models/network.go +++ b/models/network.go @@ -97,3 +97,8 @@ func (network *Network) GetNetworkNetworkCIDR6() *net.IPNet { _, netCidr, _ := net.ParseCIDR(network.AddressRange6) return netCidr } + +type NetworkStatResp struct { + Network + Hosts int `json:"hosts"` +} From 940ed8b2f04f5371312ceb2a984eacd56811830e Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 26 Sep 2024 18:45:54 +0400 Subject: [PATCH 036/169] remove uuid on id type --- controllers/acls.go | 36 +++++++++++++++++++++++++----------- logic/acls.go | 42 +++++++++++++++++++++++++++++------------- migrate/migrate.go | 1 + models/acl.go | 24 +++++++++++++++++++++--- 4 files changed, 76 insertions(+), 27 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 1321a4630..3bdfa6cf9 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -7,7 +7,6 @@ import ( "net/url" "time" - "github.com/google/uuid" "github.com/gorilla/mux" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" @@ -74,15 +73,14 @@ func createAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - // check if acl network exists - _, err = logic.GetNetwork(req.NetworkID.String()) + err = logic.ValidateCreateAclReq(req) if err != nil { - logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to get network details for "+req.NetworkID.String()), "badrequest")) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } // check if acl exists acl := req - acl.ID = uuid.New() + acl.GetID(req.NetworkID, req.Name) acl.CreatedBy = user.UserName acl.CreatedAt = time.Now().UTC() acl.Default = false @@ -107,7 +105,7 @@ func createAcl(w http.ResponseWriter, r *http.Request) { // @Success 200 {array} models.SuccessResponse // @Failure 500 {object} models.ErrorResponse func updateAcl(w http.ResponseWriter, r *http.Request) { - var updateAcl models.Acl + var updateAcl models.UpdateAclRequest err := json.NewDecoder(r.Body).Decode(&updateAcl) if err != nil { logger.Log(0, "error decoding request body: ", @@ -116,21 +114,37 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { return } - acl, err := logic.GetAcl(updateAcl.ID.String()) + acl, err := logic.GetAcl(updateAcl.Acl.ID) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - if !logic.IsAclPolicyValid(updateAcl) { + if !logic.IsAclPolicyValid(updateAcl.Acl) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) return } - err = logic.UpdateAcl(updateAcl, acl) + if updateAcl.Acl.NetworkID != acl.NetworkID { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy, network id mismatch"), "badrequest")) + return + } + if updateAcl.NewName != "" { + //check if policy exists with same name + id := models.FormatAclID(updateAcl.Acl.NetworkID, updateAcl.NewName) + _, err := logic.GetAcl(id) + if err != nil { + logic.ReturnErrorResponse(w, r, + logic.FormatError(errors.New("policy already exists with name "+updateAcl.NewName), "badrequest")) + return + } + updateAcl.Acl.ID = id + updateAcl.Acl.Name = updateAcl.NewName + } + err = logic.UpdateAcl(updateAcl.Acl, acl) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - logic.ReturnSuccessResponse(w, r, "updated acl "+updateAcl.Name) + logic.ReturnSuccessResponse(w, r, "updated acl "+acl.Name) } // @Summary Delete Acl @@ -145,7 +159,7 @@ func deleteAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("acl id is required"), "badrequest")) return } - acl, err := logic.GetAcl(aclID) + acl, err := logic.GetAcl(models.AclID(aclID)) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return diff --git a/logic/acls.go b/logic/acls.go index 382bd43f3..54ca4daea 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -3,10 +3,10 @@ package logic import ( "encoding/json" "errors" + "fmt" "sort" "time" - "github.com/google/uuid" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" ) @@ -14,9 +14,9 @@ import ( // CreateDefaultAclNetworkPolicies - create default acl network policies func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { defaultDeviceAcl := models.Acl{ - ID: uuid.New(), - Default: true, + ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes")), Name: "all-nodes", + Default: true, NetworkID: netID, RuleType: models.DevicePolicy, Src: []models.AclPolicyTag{ @@ -36,7 +36,7 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { } InsertAcl(defaultDeviceAcl) defaultUserAcl := models.Acl{ - ID: uuid.New(), + ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-users")), Default: true, Name: "all-users", NetworkID: netID, @@ -73,6 +73,19 @@ func DeleteDefaultNetworkPolicies(netId models.NetworkID) { } } +// ValidateCreateAclReq - validates create req for acl +func ValidateCreateAclReq(req models.Acl) error { + // check if acl network exists + _, err := GetNetwork(req.NetworkID.String()) + if err != nil { + return errors.New("failed to get network details for " + req.NetworkID.String()) + } + if req.Name == "" { + return errors.New("name is required") + } + return nil +} + // InsertAcl - creates acl policy func InsertAcl(a models.Acl) error { d, err := json.Marshal(a) @@ -83,9 +96,9 @@ func InsertAcl(a models.Acl) error { } // GetAcl - gets acl info by id -func GetAcl(aID string) (models.Acl, error) { +func GetAcl(aID models.AclID) (models.Acl, error) { a := models.Acl{} - d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID) + d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID.String()) if err != nil { return a, err } @@ -180,13 +193,16 @@ func IsAclPolicyValid(acl models.Acl) bool { // UpdateAcl - updates allowed fields on acls and commits to DB func UpdateAcl(newAcl, acl models.Acl) error { - if newAcl.Name != "" { - acl.Name = newAcl.Name - } + + acl.Name = newAcl.Name acl.Src = newAcl.Src acl.Dst = newAcl.Dst acl.AllowedDirection = newAcl.AllowedDirection acl.Enabled = newAcl.Enabled + if acl.ID != newAcl.ID { + database.DeleteRecord(acl.ID.String(), database.ACLS_TABLE_NAME) + acl.ID = newAcl.ID + } d, err := json.Marshal(acl) if err != nil { return err @@ -212,7 +228,7 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo // ListUserPolicies - lists all acl policies enforced on an user func ListUserPolicies(u models.User) []models.Acl { - data, err := database.FetchRecords(database.TAG_TABLE_NAME) + data, err := database.FetchRecords(database.ACLS_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{} } @@ -245,7 +261,7 @@ func ListUserPolicies(u models.User) []models.Acl { // ListUserPoliciesByNetwork - lists all acl user policies in a network func ListUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { - data, err := database.FetchRecords(database.TAG_TABLE_NAME) + data, err := database.FetchRecords(database.ACLS_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{} } @@ -265,7 +281,7 @@ func ListUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { // listDevicePolicies - lists all device policies in a network func listDevicePolicies(netID models.NetworkID) []models.Acl { - data, err := database.FetchRecords(database.TAG_TABLE_NAME) + data, err := database.FetchRecords(database.ACLS_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{} } @@ -285,7 +301,7 @@ func listDevicePolicies(netID models.NetworkID) []models.Acl { // ListAcls - lists all acl policies func ListAcls(netID models.NetworkID) ([]models.Acl, error) { - data, err := database.FetchRecords(database.TAG_TABLE_NAME) + data, err := database.FetchRecords(database.ACLS_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{}, err } diff --git a/migrate/migrate.go b/migrate/migrate.go index a2d9b65d4..850e438b8 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -320,6 +320,7 @@ func syncUsers() { if err == nil { for _, netI := range networks { logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(netI.NetID)) + logic.CreateDefaultAclNetworkPolicies(models.NetworkID(netI.NetID)) networkNodes := logic.GetNetworkNodesMemory(nodes, netI.NetID) for _, networkNodeI := range networkNodes { if networkNodeI.IsIngressGateway { diff --git a/models/acl.go b/models/acl.go index 17386149e..acd1decb6 100644 --- a/models/acl.go +++ b/models/acl.go @@ -1,11 +1,24 @@ package models import ( + "fmt" "time" - - "github.com/google/uuid" ) +type AclID string + +func (aID AclID) String() string { + return string(aID) +} + +func (a *Acl) GetID(netID NetworkID, name string) { + a.ID = AclID(fmt.Sprintf("%s.%s", netID.String(), name)) +} + +func FormatAclID(netID NetworkID, name string) AclID { + return AclID(fmt.Sprintf("%s.%s", netID.String(), name)) +} + // AllowedTrafficDirection - allowed direction of traffic type AllowedTrafficDirection int @@ -42,8 +55,13 @@ func (g AclGroupType) String() string { return string(g) } +type UpdateAclRequest struct { + Acl Acl + NewName string `json:"new_name"` +} + type Acl struct { - ID uuid.UUID `json:"id"` + ID AclID `json:"id"` Default bool `json:"default"` Name string `json:"name"` NetworkID NetworkID `json:"network_id"` From 5b49872d5d97ed78f5afefddc5639a5367a3d9c2 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 26 Sep 2024 21:00:04 +0400 Subject: [PATCH 037/169] fix update acl policy --- controllers/acls.go | 48 +++++++++++++++++++++++++++++++++++--------- database/database.go | 1 + logic/acls.go | 9 ++++++--- models/acl.go | 7 ++++++- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 3bdfa6cf9..18ad9d19e 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -16,6 +16,8 @@ import ( func aclHandlers(r *mux.Router) { r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(getAcls))). Methods(http.MethodGet) + r.HandleFunc("/api/v1/acls/policy_types", logic.SecurityCheck(true, http.HandlerFunc(getAclPolicyTypes))). + Methods(http.MethodGet) r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(createAcl))). Methods(http.MethodPost) r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(updateAcl))). @@ -25,6 +27,16 @@ func aclHandlers(r *mux.Router) { } +// @Summary List Acl Policy types +// @Router /api/v1/acls/policy_types [get] +// @Tags ACL +// @Accept json +// @Success 200 {array} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func getAclPolicyTypes(w http.ResponseWriter, r *http.Request) { + logic.ReturnSuccessResponseWithJson(w, r, nil, "fetched all acls in the network ") +} + // @Summary List Acls in a network // @Router /api/v1/acls [get] // @Tags ACL @@ -78,12 +90,17 @@ func createAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - // check if acl exists + acl := req acl.GetID(req.NetworkID, req.Name) acl.CreatedBy = user.UserName acl.CreatedAt = time.Now().UTC() acl.Default = false + if acl.RuleType == models.DevicePolicy { + acl.AllowedDirection = models.TrafficDirectionBi + } else { + acl.AllowedDirection = models.TrafficDirectionUni + } // validate create acl policy if !logic.IsAclPolicyValid(acl) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) @@ -91,11 +108,15 @@ func createAcl(w http.ResponseWriter, r *http.Request) { } err = logic.InsertAcl(acl) if err != nil { - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - - logic.ReturnSuccessResponseWithJson(w, r, req, "created acl successfully") + acl, err = logic.GetAcl(acl.ID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + logic.ReturnSuccessResponseWithJson(w, r, acl, "created acl successfully") } // @Summary Update Acl @@ -114,11 +135,15 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { return } - acl, err := logic.GetAcl(updateAcl.Acl.ID) + acl, err := logic.GetAcl(updateAcl.ID) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + if acl.Default { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update default policy"), "badrequest")) + return + } if !logic.IsAclPolicyValid(updateAcl.Acl) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) return @@ -129,14 +154,14 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { } if updateAcl.NewName != "" { //check if policy exists with same name - id := models.FormatAclID(updateAcl.Acl.NetworkID, updateAcl.NewName) + id := models.FormatAclID(updateAcl.NetworkID, updateAcl.NewName) _, err := logic.GetAcl(id) - if err != nil { + if err == nil { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("policy already exists with name "+updateAcl.NewName), "badrequest")) return } - updateAcl.Acl.ID = id + updateAcl.ID = id updateAcl.Acl.Name = updateAcl.NewName } err = logic.UpdateAcl(updateAcl.Acl, acl) @@ -164,9 +189,14 @@ func deleteAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + if acl.Default { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } err = logic.DeleteAcl(acl) if err != nil { - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + logic.ReturnErrorResponse(w, r, + logic.FormatError(errors.New("cannot delete default policy"), "internal")) return } logic.ReturnSuccessResponse(w, r, "deleted acl "+acl.Name) diff --git a/database/database.go b/database/database.go index 5bd684998..6590e0063 100644 --- a/database/database.go +++ b/database/database.go @@ -157,6 +157,7 @@ func createTables() { CreateTable(USER_PERMISSIONS_TABLE_NAME) CreateTable(USER_INVITES_TABLE_NAME) CreateTable(TAG_TABLE_NAME) + CreateTable(ACLS_TABLE_NAME) } func CreateTable(tableName string) error { diff --git a/logic/acls.go b/logic/acls.go index 54ca4daea..2ad042c0c 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -83,6 +83,11 @@ func ValidateCreateAclReq(req models.Acl) error { if req.Name == "" { return errors.New("name is required") } + req.GetID(req.NetworkID, req.Name) + _, err = GetAcl(req.ID) + if err == nil { + return errors.New("acl exists already with name " + req.Name) + } return nil } @@ -193,14 +198,12 @@ func IsAclPolicyValid(acl models.Acl) bool { // UpdateAcl - updates allowed fields on acls and commits to DB func UpdateAcl(newAcl, acl models.Acl) error { - acl.Name = newAcl.Name acl.Src = newAcl.Src acl.Dst = newAcl.Dst - acl.AllowedDirection = newAcl.AllowedDirection acl.Enabled = newAcl.Enabled if acl.ID != newAcl.ID { - database.DeleteRecord(acl.ID.String(), database.ACLS_TABLE_NAME) + database.DeleteRecord(database.ACLS_TABLE_NAME, acl.ID.String()) acl.ID = newAcl.ID } d, err := json.Marshal(acl) diff --git a/models/acl.go b/models/acl.go index acd1decb6..a8f8c0a92 100644 --- a/models/acl.go +++ b/models/acl.go @@ -56,10 +56,15 @@ func (g AclGroupType) String() string { } type UpdateAclRequest struct { - Acl Acl + Acl NewName string `json:"new_name"` } +type AclPolicy struct { + TypeID AclPolicyType + PrefixTagUser AclGroupType +} + type Acl struct { ID AclID `json:"id"` Default bool `json:"default"` From 2c3f4581e84e803ba007afa3ed75baecf1f2bfdb Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 27 Sep 2024 11:40:04 +0400 Subject: [PATCH 038/169] publish peer upate on acl changes --- controllers/acls.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/controllers/acls.go b/controllers/acls.go index 18ad9d19e..ae657ca8c 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -11,6 +11,7 @@ import ( "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/mq" ) func aclHandlers(r *mux.Router) { @@ -116,6 +117,7 @@ func createAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + go mq.PublishPeerUpdate(false) logic.ReturnSuccessResponseWithJson(w, r, acl, "created acl successfully") } @@ -169,6 +171,7 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + go mq.PublishPeerUpdate(false) logic.ReturnSuccessResponse(w, r, "updated acl "+acl.Name) } @@ -199,5 +202,6 @@ func deleteAcl(w http.ResponseWriter, r *http.Request) { logic.FormatError(errors.New("cannot delete default policy"), "internal")) return } + go mq.PublishPeerUpdate(false) logic.ReturnSuccessResponse(w, r, "deleted acl "+acl.Name) } From 9deac0ad2dff4be04e6a2d164d42dbe86788abc1 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 28 Sep 2024 17:19:01 +0400 Subject: [PATCH 039/169] sync tag updates with acl policies --- controllers/acls.go | 21 ++++++++++---- controllers/tags.go | 21 ++++++++++++-- logic/acls.go | 71 ++++++++++++++++++++++++++++++++++++++++++--- logic/tags.go | 2 ++ 4 files changed, 102 insertions(+), 13 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index ae657ca8c..5574968a5 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -35,7 +35,20 @@ func aclHandlers(r *mux.Router) { // @Success 200 {array} models.SuccessResponse // @Failure 500 {object} models.ErrorResponse func getAclPolicyTypes(w http.ResponseWriter, r *http.Request) { - logic.ReturnSuccessResponseWithJson(w, r, nil, "fetched all acls in the network ") + nodeID, _ := url.QueryUnescape(r.URL.Query().Get("node")) + peerID, _ := url.QueryUnescape(r.URL.Query().Get("peer")) + node, err := logic.GetNodeByID(nodeID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + peer, err := logic.GetNodeByID(peerID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + allowed := logic.IsNodeAllowedToCommunicate(node, peer) + logic.ReturnSuccessResponseWithJson(w, r, allowed, "fetched all acls in the network ") } // @Summary List Acls in a network @@ -142,10 +155,6 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - if acl.Default { - logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update default policy"), "badrequest")) - return - } if !logic.IsAclPolicyValid(updateAcl.Acl) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy"), "badrequest")) return @@ -154,7 +163,7 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("invalid policy, network id mismatch"), "badrequest")) return } - if updateAcl.NewName != "" { + if !acl.Default && updateAcl.NewName != "" { //check if policy exists with same name id := models.FormatAclID(updateAcl.NetworkID, updateAcl.NewName) _, err := logic.GetAcl(id) diff --git a/controllers/tags.go b/controllers/tags.go index 238611c85..837cc603d 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -13,6 +13,7 @@ import ( "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/mq" ) func tagHandlers(r *mux.Router) { @@ -107,7 +108,7 @@ func createTag(w http.ResponseWriter, r *http.Request) { logic.UpsertNode(&node) } }() - + go mq.PublishPeerUpdate(false) logic.ReturnSuccessResponseWithJson(w, r, req, "created tag successfully") } @@ -146,7 +147,11 @@ func updateTag(w http.ResponseWriter, r *http.Request) { // delete old Tag entry logic.DeleteTag(updateTag.ID) } - go logic.UpdateTag(updateTag, newID) + go func() { + logic.UpdateTag(updateTag, newID) + logic.UpdateDeviceTag(updateTag.ID, newID, tag.Network) + mq.PublishPeerUpdate(false) + }() logic.ReturnSuccessResponse(w, r, "updating tags") } @@ -162,10 +167,20 @@ func deleteTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest")) return } - err := logic.DeleteTag(models.TagID(tagID)) + tag, err := logic.GetTag(models.TagID(tagID)) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + err = logic.DeleteTag(models.TagID(tagID)) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + + go func() { + logic.RemoveDeviceTagFromAclPolicies(tag.ID, tag.Network) + mq.PublishPeerUpdate(false) + }() logic.ReturnSuccessResponse(w, r, "deleted tag "+tagID) } diff --git a/logic/acls.go b/logic/acls.go index 2ad042c0c..3372453d9 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -198,9 +198,11 @@ func IsAclPolicyValid(acl models.Acl) bool { // UpdateAcl - updates allowed fields on acls and commits to DB func UpdateAcl(newAcl, acl models.Acl) error { - acl.Name = newAcl.Name - acl.Src = newAcl.Src - acl.Dst = newAcl.Dst + if !acl.Default { + acl.Name = newAcl.Name + acl.Src = newAcl.Src + acl.Dst = newAcl.Dst + } acl.Enabled = newAcl.Enabled if acl.ID != newAcl.ID { database.DeleteRecord(database.ACLS_TABLE_NAME, acl.ID.String()) @@ -213,6 +215,15 @@ func UpdateAcl(newAcl, acl models.Acl) error { return database.Insert(acl.ID.String(), string(d), database.ACLS_TABLE_NAME) } +// UpsertAcl - upserts acl +func UpsertAcl(acl models.Acl) error { + d, err := json.Marshal(acl) + if err != nil { + return err + } + return database.Insert(acl.ID.String(), string(d), database.ACLS_TABLE_NAME) +} + // DeleteAcl - deletes acl policy func DeleteAcl(a models.Acl) error { return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) @@ -325,7 +336,7 @@ func ListAcls(netID models.NetworkID) ([]models.Acl, error) { func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { aclValueMap := make(map[string]struct{}) for _, aclTagI := range acltags { - aclValueMap[aclTagI.ID.String()] = struct{}{} + aclValueMap[aclTagI.Value] = struct{}{} } return aclValueMap } @@ -344,6 +355,10 @@ func IsNodeAllowedToCommunicate(node, peer models.Node) bool { for _, policy := range policies { srcMap := convAclTagToValueMap(policy.Src) dstMap := convAclTagToValueMap(policy.Dst) + fmt.Printf("\n======> SRCMAP: %+v\n", srcMap) + fmt.Printf("\n======> DSTMAP: %+v\n", dstMap) + fmt.Printf("\n======> node Tags: %+v\n", node.Tags) + fmt.Printf("\n======> peer Tags: %+v\n", peer.Tags) for tagID := range peer.Tags { if _, ok := dstMap[tagID.String()]; ok { for tagID := range node.Tags { @@ -370,3 +385,51 @@ func SortAclEntrys(acls []models.Acl) { return acls[i].Name < acls[j].Name }) } + +// UpdateDeviceTag - updates device tag on acl policies +func UpdateDeviceTag(OldID, newID models.TagID, netID models.NetworkID) { + acls := listDevicePolicies(netID) + update := false + for _, acl := range acls { + for i, srcTagI := range acl.Src { + if srcTagI.ID == models.DeviceAclID { + if OldID.String() == srcTagI.Value { + acl.Src[i].Value = newID.String() + update = true + } + } + } + for i, dstTagI := range acl.Dst { + if dstTagI.ID == models.DeviceAclID { + if OldID.String() == dstTagI.Value { + acl.Dst[i].Value = newID.String() + update = true + } + } + } + if update { + UpsertAcl(acl) + } + } +} + +func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) error { + acls := listDevicePolicies(netID) + for _, acl := range acls { + for i, srcTagI := range acl.Src { + if srcTagI.ID == models.DeviceAclID { + if tagID.String() == srcTagI.Value { + acl.Src = append(acl.Src[:i], acl.Src[i+1:]...) + } + } + } + for i, dstTagI := range acl.Dst { + if dstTagI.ID == models.DeviceAclID { + if tagID.String() == dstTagI.Value { + acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...) + } + } + } + } + return nil +} diff --git a/logic/tags.go b/logic/tags.go index 5b89bc89d..c5ef61df8 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -61,6 +61,8 @@ func DeleteTag(tagID models.TagID) error { UpsertNode(&nodeI) } } + // remove tag used on acl policy + go RemoveDeviceTagFromAclPolicies(tagID, tag.Network) return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String()) } From 5a7e1f3aff8a707069f66adcddd59761996264bf Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 28 Sep 2024 17:20:17 +0400 Subject: [PATCH 040/169] upsert acl on tag deletion --- logic/acls.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/logic/acls.go b/logic/acls.go index 3372453d9..0571adab7 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -415,11 +415,13 @@ func UpdateDeviceTag(OldID, newID models.TagID, netID models.NetworkID) { func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) error { acls := listDevicePolicies(netID) + update := false for _, acl := range acls { for i, srcTagI := range acl.Src { if srcTagI.ID == models.DeviceAclID { if tagID.String() == srcTagI.Value { acl.Src = append(acl.Src[:i], acl.Src[i+1:]...) + update = true } } } @@ -427,9 +429,13 @@ func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) if dstTagI.ID == models.DeviceAclID { if tagID.String() == dstTagI.Value { acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...) + update = true } } } + if update { + UpsertAcl(acl) + } } return nil } From 6f12dde94ba2711dfa126abca3442e20920c312b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 28 Sep 2024 18:02:28 +0400 Subject: [PATCH 041/169] check id syntax --- controllers/tags.go | 4 +++- logic/acls.go | 23 +++++++++++++++++++++-- logic/util.go | 11 +++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index 837cc603d..cd5bf65f3 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -149,7 +149,9 @@ func updateTag(w http.ResponseWriter, r *http.Request) { } go func() { logic.UpdateTag(updateTag, newID) - logic.UpdateDeviceTag(updateTag.ID, newID, tag.Network) + if updateTag.NewName != "" { + logic.UpdateDeviceTag(updateTag.ID, newID, tag.Network) + } mq.PublishPeerUpdate(false) }() logic.ReturnSuccessResponse(w, r, "updating tags") diff --git a/logic/acls.go b/logic/acls.go index 0571adab7..83e35f04a 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "sort" + "strings" "time" "github.com/gravitl/netmaker/database" @@ -73,6 +74,22 @@ func DeleteDefaultNetworkPolicies(netId models.NetworkID) { } } +func checkIDSyntax(id string) error { + if id == "" { + return errors.New("name is required") + } + if len(id) < 3 { + return errors.New("name should have min 3 characters") + } + if HasSymbol(id) { + return errors.New("symbols are not allowed") + } + if strings.Contains(id, ".") { + return errors.New("dot not allowed") + } + return nil +} + // ValidateCreateAclReq - validates create req for acl func ValidateCreateAclReq(req models.Acl) error { // check if acl network exists @@ -80,8 +97,9 @@ func ValidateCreateAclReq(req models.Acl) error { if err != nil { return errors.New("failed to get network details for " + req.NetworkID.String()) } - if req.Name == "" { - return errors.New("name is required") + err = checkIDSyntax(req.Name) + if err != nil { + return err } req.GetID(req.NetworkID, req.Name) _, err = GetAcl(req.ID) @@ -413,6 +431,7 @@ func UpdateDeviceTag(OldID, newID models.TagID, netID models.NetworkID) { } } +// RemoveDeviceTagFromAclPolicies - remove device tag from acl policies func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) error { acls := listDevicePolicies(netID) update := false diff --git a/logic/util.go b/logic/util.go index 3b410c586..cd98f358e 100644 --- a/logic/util.go +++ b/logic/util.go @@ -10,6 +10,7 @@ import ( "os" "strings" "time" + "unicode" "github.com/c-robinson/iplib" "github.com/gravitl/netmaker/database" @@ -148,4 +149,14 @@ func IsSlicesEqual(a, b []string) bool { return true } +// HasSymbol - checks if string has symbols +func HasSymbol(str string) bool { + for _, letter := range str { + if unicode.IsSymbol(letter) { + return true + } + } + return false +} + // == private == From e521393d3ec10b5fc026dd8944603d72fb9631f4 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 28 Sep 2024 18:08:45 +0400 Subject: [PATCH 042/169] add validation checks on tag name --- controllers/tags.go | 17 +++++++++++++++++ logic/tags.go | 18 ++++++++++++++++++ logic/util.go | 10 ++++++++++ 3 files changed, 45 insertions(+) diff --git a/controllers/tags.go b/controllers/tags.go index 238611c85..89f33b970 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -89,6 +89,17 @@ func createTag(w http.ResponseWriter, r *http.Request) { CreatedBy: user.UserName, CreatedAt: time.Now(), } + _, err = logic.GetTag(tag.ID) + if err == nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("tag with id %s exists already", tag.TagName), "badrequest")) + return + } + // validate name + err = logic.CheckIDSyntax(tag.TagName) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } err = logic.InsertTag(tag) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) @@ -135,6 +146,12 @@ func updateTag(w http.ResponseWriter, r *http.Request) { updateTag.NewName = strings.TrimSpace(updateTag.NewName) var newID models.TagID if updateTag.NewName != "" { + // validate name + err = logic.CheckIDSyntax(updateTag.NewName) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } newID = models.TagID(fmt.Sprintf("%s.%s", tag.Network, updateTag.NewName)) tag.ID = newID tag.TagName = updateTag.NewName diff --git a/logic/tags.go b/logic/tags.go index 7436aa266..d55b8c8c2 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -2,8 +2,10 @@ package logic import ( "encoding/json" + "errors" "fmt" "sort" + "strings" "sync" "github.com/gravitl/netmaker/database" @@ -178,3 +180,19 @@ func SortTagEntrys(tags []models.TagListResp) { return tags[i].ID < tags[j].ID }) } + +func CheckIDSyntax(id string) error { + if id == "" { + return errors.New("name is required") + } + if len(id) < 3 { + return errors.New("name should have min 3 characters") + } + if HasSymbol(id) { + return errors.New("symbols are not allowed") + } + if strings.Contains(id, ".") { + return errors.New("dots not allowed") + } + return nil +} diff --git a/logic/util.go b/logic/util.go index 3b410c586..455ec02d1 100644 --- a/logic/util.go +++ b/logic/util.go @@ -10,6 +10,7 @@ import ( "os" "strings" "time" + "unicode" "github.com/c-robinson/iplib" "github.com/gravitl/netmaker/database" @@ -148,4 +149,13 @@ func IsSlicesEqual(a, b []string) bool { return true } +func HasSymbol(str string) bool { + for _, letter := range str { + if unicode.IsSymbol(letter) { + return true + } + } + return false +} + // == private == From 025167f115b7b4785d4c7ad3642fa1f25d8a0478 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 28 Sep 2024 18:38:49 +0400 Subject: [PATCH 043/169] add regex check for tag name --- logic/tags.go | 11 ++++++----- logic/util.go | 10 ---------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/logic/tags.go b/logic/tags.go index 097ce2024..413f9a3d5 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" "fmt" + "regexp" "sort" - "strings" "sync" "github.com/gravitl/netmaker/database" @@ -192,11 +192,12 @@ func CheckIDSyntax(id string) error { if len(id) < 3 { return errors.New("name should have min 3 characters") } - if HasSymbol(id) { - return errors.New("symbols are not allowed") + reg, err := regexp.Compile("^[a-zA-Z-]+$") + if err != nil { + return err } - if strings.Contains(id, ".") { - return errors.New("dots not allowed") + if !reg.MatchString(id) { + return errors.New("invalid name. allowed characters are [a-zA-Z-]") } return nil } diff --git a/logic/util.go b/logic/util.go index 455ec02d1..3b410c586 100644 --- a/logic/util.go +++ b/logic/util.go @@ -10,7 +10,6 @@ import ( "os" "strings" "time" - "unicode" "github.com/c-robinson/iplib" "github.com/gravitl/netmaker/database" @@ -149,13 +148,4 @@ func IsSlicesEqual(a, b []string) bool { return true } -func HasSymbol(str string) bool { - for _, letter := range str { - if unicode.IsSymbol(letter) { - return true - } - } - return false -} - // == private == From f3b0bb60f02d8eabc317fc8886f72518a24124a0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 28 Sep 2024 19:40:26 +0400 Subject: [PATCH 044/169] fix acl update --- controllers/tags.go | 4 +- logic/acls.go | 148 +++++++++++++++++++++++++------------------- logic/tags.go | 8 ++- 3 files changed, 93 insertions(+), 67 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index f3305f934..5e271ba7f 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -162,7 +162,7 @@ func updateTag(w http.ResponseWriter, r *http.Request) { return } // delete old Tag entry - logic.DeleteTag(updateTag.ID) + logic.DeleteTag(updateTag.ID, false) } go func() { logic.UpdateTag(updateTag, newID) @@ -191,7 +191,7 @@ func deleteTag(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - err = logic.DeleteTag(models.TagID(tagID)) + err = logic.DeleteTag(models.TagID(tagID), true) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return diff --git a/logic/acls.go b/logic/acls.go index aa63f64f3..91a1d0863 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -13,54 +13,62 @@ import ( // CreateDefaultAclNetworkPolicies - create default acl network policies func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { - defaultDeviceAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes")), - Name: "all-nodes", - Default: true, - NetworkID: netID, - RuleType: models.DevicePolicy, - Src: []models.AclPolicyTag{ - { - ID: models.DeviceAclID, - Value: "*", - }}, - Dst: []models.AclPolicyTag{ - { - ID: models.DeviceAclID, - Value: "*", - }}, - AllowedDirection: models.TrafficDirectionBi, - Enabled: true, - CreatedBy: "auto", - CreatedAt: time.Now().UTC(), + if netID.String() == "" { + return } - InsertAcl(defaultDeviceAcl) - defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-users")), - Default: true, - Name: "all-users", - NetworkID: netID, - RuleType: models.UserPolicy, - Src: []models.AclPolicyTag{ - { - ID: models.UserAclID, - Value: "*", + if !IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes"))) { + defaultDeviceAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes")), + Name: "all-nodes", + Default: true, + NetworkID: netID, + RuleType: models.DevicePolicy, + Src: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionBi, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + InsertAcl(defaultDeviceAcl) + } + if !IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, "all-users"))) { + defaultUserAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-users")), + Default: true, + Name: "all-users", + NetworkID: netID, + RuleType: models.UserPolicy, + Src: []models.AclPolicyTag{ + { + ID: models.UserAclID, + Value: "*", + }, + { + ID: models.UserGroupAclID, + Value: "*", + }, }, - { - ID: models.UserGroupAclID, + Dst: []models.AclPolicyTag{{ + ID: models.DeviceAclID, Value: "*", - }, - }, - Dst: []models.AclPolicyTag{{ - ID: models.DeviceAclID, - Value: "*", - }}, - AllowedDirection: models.TrafficDirectionUni, - Enabled: true, - CreatedBy: "auto", - CreatedAt: time.Now().UTC(), + }}, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + InsertAcl(defaultUserAcl) } - InsertAcl(defaultUserAcl) + } // DeleteDefaultNetworkPolicies - deletes all default network acl policies @@ -115,32 +123,41 @@ func GetAcl(aID models.AclID) (models.Acl, error) { return a, nil } +// IsAclExists - checks if acl exists +func IsAclExists(aclID models.AclID) bool { + _, err := GetAcl(aclID) + return err == nil +} + // IsAclPolicyValid - validates if acl policy is valid func IsAclPolicyValid(acl models.Acl) bool { //check if src and dst are valid - isValid := false + switch acl.RuleType { case models.UserPolicy: // src list should only contain users for _, srcI := range acl.Src { if srcI.ID == "" || srcI.Value == "" { - break + return false } if srcI.ID != models.UserAclID && srcI.ID != models.UserGroupAclID { - break + return false } // check if user group is valid if srcI.ID == models.UserAclID { _, err := GetUser(srcI.Value) if err != nil { - break + return false } } else if srcI.ID == models.UserGroupAclID { + if srcI.Value == "*" { + continue + } err := IsGroupValid(models.UserGroupID(srcI.Value)) if err != nil { - break + return false } } @@ -148,53 +165,60 @@ func IsAclPolicyValid(acl models.Acl) bool { for _, dstI := range acl.Dst { if dstI.ID == "" || dstI.Value == "" { - break + return false } if dstI.ID == models.UserAclID || dstI.ID == models.UserGroupAclID { - break + return false } if dstI.ID != models.DeviceAclID { - break + return false + } + if dstI.Value == "*" { + continue } // check if tag is valid _, err := GetTag(models.TagID(dstI.Value)) if err != nil { - break + return false } } - isValid = true case models.DevicePolicy: for _, srcI := range acl.Src { if srcI.ID == "" || srcI.Value == "" { - break + return false } if srcI.ID != models.DeviceAclID { - break + return false + } + if srcI.Value == "*" { + continue } // check if tag is valid _, err := GetTag(models.TagID(srcI.Value)) if err != nil { - break + return false } } for _, dstI := range acl.Dst { if dstI.ID == "" || dstI.Value == "" { - break + return false } if dstI.ID != models.DeviceAclID { - break + return false + } + if dstI.Value == "*" { + continue } // check if tag is valid _, err := GetTag(models.TagID(dstI.Value)) if err != nil { - break + return false } } - isValid = true } - return isValid + return true } // UpdateAcl - updates allowed fields on acls and commits to DB diff --git a/logic/tags.go b/logic/tags.go index d66212c4d..3f52f7791 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -44,7 +44,7 @@ func InsertTag(tag models.Tag) error { } // DeleteTag - delete tag, will also untag hosts -func DeleteTag(tagID models.TagID) error { +func DeleteTag(tagID models.TagID, removeFromPolicy bool) error { tagMutex.Lock() defer tagMutex.Unlock() // cleanUp tags on hosts @@ -63,8 +63,10 @@ func DeleteTag(tagID models.TagID) error { UpsertNode(&nodeI) } } - // remove tag used on acl policy - go RemoveDeviceTagFromAclPolicies(tagID, tag.Network) + if removeFromPolicy { + // remove tag used on acl policy + go RemoveDeviceTagFromAclPolicies(tagID, tag.Network) + } return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String()) } From a9697f9d7bcb11de4c60d23aa75d07425dd849d5 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 30 Sep 2024 12:42:26 +0400 Subject: [PATCH 045/169] add acl types api --- controllers/acls.go | 26 ++++++++++++++++++++++++-- models/acl.go | 6 ++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 5574968a5..20084dd4b 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -17,7 +17,7 @@ import ( func aclHandlers(r *mux.Router) { r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(getAcls))). Methods(http.MethodGet) - r.HandleFunc("/api/v1/acls/policy_types", logic.SecurityCheck(true, http.HandlerFunc(getAclPolicyTypes))). + r.HandleFunc("/api/v1/acls/policy_types", logic.SecurityCheck(true, http.HandlerFunc(aclPolicyTypes))). Methods(http.MethodGet) r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(createAcl))). Methods(http.MethodPost) @@ -25,6 +25,8 @@ func aclHandlers(r *mux.Router) { Methods(http.MethodPut) r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(deleteAcl))). Methods(http.MethodDelete) + r.HandleFunc("/api/v1/acls/debug", logic.SecurityCheck(true, http.HandlerFunc(aclDebug))). + Methods(http.MethodGet) } @@ -34,7 +36,27 @@ func aclHandlers(r *mux.Router) { // @Accept json // @Success 200 {array} models.SuccessResponse // @Failure 500 {object} models.ErrorResponse -func getAclPolicyTypes(w http.ResponseWriter, r *http.Request) { +func aclPolicyTypes(w http.ResponseWriter, r *http.Request) { + resp := models.AclPolicyTypes{ + RuleTypes: []models.AclPolicyType{ + models.DevicePolicy, + models.UserPolicy, + }, + SrcGroupTypes: []models.AclGroupType{ + models.UserAclID, + models.UserGroupAclID, + models.DeviceAclID, + }, + DstGroupTypes: []models.AclGroupType{ + models.DeviceAclID, + // models.NetmakerIPAclID, + // models.NetmakerSubNetRangeAClID, + }, + } + logic.ReturnSuccessResponseWithJson(w, r, resp, "fetched acls types") +} + +func aclDebug(w http.ResponseWriter, r *http.Request) { nodeID, _ := url.QueryUnescape(r.URL.Query().Get("node")) peerID, _ := url.QueryUnescape(r.URL.Query().Get("peer")) node, err := logic.GetNodeByID(nodeID) diff --git a/models/acl.go b/models/acl.go index a8f8c0a92..f0bc2a6cf 100644 --- a/models/acl.go +++ b/models/acl.go @@ -78,3 +78,9 @@ type Acl struct { CreatedBy string `json:"created_by"` CreatedAt time.Time `json:"created_at"` } + +type AclPolicyTypes struct { + RuleTypes []AclPolicyType `json:"policy_types"` + SrcGroupTypes []AclGroupType `json:"src_grp_types"` + DstGroupTypes []AclGroupType `json:"dst_grp_types"` +} From 10f56800495abf381fc2c7145c443f1f3f976f21 Mon Sep 17 00:00:00 2001 From: Max Ma Date: Mon, 30 Sep 2024 16:50:26 +0200 Subject: [PATCH 046/169] downgrade paho.mqtt to v1.4.3 (#3143) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 30bd1a001..e2b53e6bc 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/gravitl/netmaker go 1.23 require ( - github.com/eclipse/paho.mqtt.golang v1.5.0 + github.com/eclipse/paho.mqtt.golang v1.4.3 github.com/go-playground/validator/v10 v10.22.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index 6ee07bf27..9f0434ce8 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= -github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= +github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= +github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= From 1f9808ff597850c830795027e552e8a9576a4ac1 Mon Sep 17 00:00:00 2001 From: Abhishek K Date: Tue, 1 Oct 2024 17:48:36 +0400 Subject: [PATCH 047/169] NET-1604: New Simplified RAC Apis (#3147) * ipv6 fix for mobile apps * simplified RAC APIs * add response to invite api * fix get config api * fix middleware for auth * add separate controller for rac apis * Revert "ipv6 fix for mobile apps" This reverts commit dc84d90be260d0a000fd4575e65e93c98b9279be. --- controllers/middleware.go | 4 + models/structs.go | 10 ++ pro/controllers/rac.go | 14 +++ pro/controllers/users.go | 214 +++++++++++++++++++++++++++++++++++++- pro/initialize.go | 1 + pro/logic/security.go | 3 + pro/logic/user_mgmt.go | 25 +++++ 7 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 pro/controllers/rac.go diff --git a/controllers/middleware.go b/controllers/middleware.go index fb2bef683..8c014fca8 100644 --- a/controllers/middleware.go +++ b/controllers/middleware.go @@ -27,6 +27,7 @@ func userMiddleWare(handler http.Handler) http.Handler { r.Header.Set("TARGET_RSRC", "") r.Header.Set("RSRC_TYPE", "") r.Header.Set("TARGET_RSRC_ID", "") + r.Header.Set("RAC", "") r.Header.Set("NET_ID", params["network"]) if strings.Contains(route, "hosts") || strings.Contains(route, "nodes") { r.Header.Set("TARGET_RSRC", models.HostRsrc.String()) @@ -34,6 +35,9 @@ func userMiddleWare(handler http.Handler) http.Handler { if strings.Contains(route, "dns") { r.Header.Set("TARGET_RSRC", models.DnsRsrc.String()) } + if strings.Contains(route, "rac") { + r.Header.Set("RAC", "true") + } if strings.Contains(route, "users") { r.Header.Set("TARGET_RSRC", models.UserRsrc.String()) } diff --git a/models/structs.go b/models/structs.go index f8dd753f4..3cc20ca47 100644 --- a/models/structs.go +++ b/models/structs.go @@ -45,6 +45,16 @@ type UserRemoteGws struct { NetworkAddresses []string `json:"network_addresses"` } +// UserRAGs - struct for user access gws +type UserRAGs struct { + GwID string `json:"remote_access_gw_id"` + GWName string `json:"gw_name"` + Network string `json:"network"` + Connected bool `json:"connected"` + IsInternetGateway bool `json:"is_internet_gateway"` + Metadata string `json:"metadata"` +} + // UserRemoteGwsReq - struct to hold user remote acccess gws req type UserRemoteGwsReq struct { RemoteAccessClientID string `json:"remote_access_clientid"` diff --git a/pro/controllers/rac.go b/pro/controllers/rac.go new file mode 100644 index 000000000..0d1b127fd --- /dev/null +++ b/pro/controllers/rac.go @@ -0,0 +1,14 @@ +package controllers + +import ( + "net/http" + + "github.com/gorilla/mux" + "github.com/gravitl/netmaker/logic" +) + +func RacHandlers(r *mux.Router) { + r.HandleFunc("/api/v1/rac/networks", logic.SecurityCheck(false, http.HandlerFunc(getUserRemoteAccessNetworks))).Methods(http.MethodGet) + r.HandleFunc("/api/v1/rac/network/{network}/access_points", logic.SecurityCheck(false, http.HandlerFunc(getUserRemoteAccessNetworkGateways))).Methods(http.MethodGet) + r.HandleFunc("/api/v1/rac/access_point/{access_point_id}/config", logic.SecurityCheck(false, http.HandlerFunc(getRemoteAccessGatewayConf))).Methods(http.MethodGet) +} diff --git a/pro/controllers/users.go b/pro/controllers/users.go index c8119b79e..d5ea4ddb0 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -263,7 +263,6 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) { }(invite) } logic.ReturnSuccessResponse(w, r, "triggered user invites") - } // swagger:route GET /api/v1/users/invites user listUserInvites @@ -816,6 +815,218 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(logic.ToReturnUser(*user)) } +// @Summary Get Users Remote Access Gw Networks. +// @Router /api/users/{username}/remote_access_gw [get] +// @Tags Users +// @Param username path string true "Username to fetch all the gateways with access" +// @Success 200 {object} map[string][]models.UserRemoteGws +// @Failure 500 {object} models.ErrorResponse +func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) { + // set header. + w.Header().Set("Content-Type", "application/json") + username := r.Header.Get("user") + user, err := logic.GetUser(username) + if err != nil { + logger.Log(0, username, "failed to fetch user: ", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) + return + } + userGws := make(map[string][]models.UserRemoteGws) + networks := []models.Network{} + networkMap := make(map[string]struct{}) + userGwNodes := proLogic.GetUserRAGNodes(*user) + for _, node := range userGwNodes { + network, err := logic.GetNetwork(node.Network) + if err != nil { + slog.Error("failed to get node network", "error", err) + continue + } + if _, ok := networkMap[network.NetID]; ok { + continue + } + networkMap[network.NetID] = struct{}{} + networks = append(networks, network) + } + + slog.Debug("returned user gws", "user", username, "gws", userGws) + logic.ReturnSuccessResponseWithJson(w, r, networks, "fetched user accessible networks") +} + +// @Summary Get Users Remote Access Gw Networks. +// @Router /api/users/{username}/remote_access_gw [get] +// @Tags Users +// @Param username path string true "Username to fetch all the gateways with access" +// @Success 200 {object} map[string][]models.UserRemoteGws +// @Failure 500 {object} models.ErrorResponse +func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request) { + // set header. + w.Header().Set("Content-Type", "application/json") + var params = mux.Vars(r) + username := r.Header.Get("user") + user, err := logic.GetUser(username) + if err != nil { + logger.Log(0, username, "failed to fetch user: ", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) + return + } + network := params["network"] + if network == "" { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params network"), "badrequest")) + return + } + userGws := []models.UserRAGs{} + + userGwNodes := proLogic.GetUserRAGNodes(*user) + for _, node := range userGwNodes { + if node.Network != network { + continue + } + + host, err := logic.GetHost(node.HostID.String()) + if err != nil { + continue + } + + userGws = append(userGws, models.UserRAGs{ + GwID: node.ID.String(), + GWName: host.Name, + Network: node.Network, + IsInternetGateway: node.IsInternetGateway, + Metadata: node.Metadata, + }) + + } + + slog.Debug("returned user gws", "user", username, "gws", userGws) + logic.ReturnSuccessResponseWithJson(w, r, userGws, "fetched user accessible gateways in network "+network) +} + +// @Summary Get Users Remote Access Gw Networks. +// @Router /api/users/{username}/remote_access_gw [get] +// @Tags Users +// @Param username path string true "Username to fetch all the gateways with access" +// @Success 200 {object} map[string][]models.UserRemoteGws +// @Failure 500 {object} models.ErrorResponse +func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) { + // set header. + w.Header().Set("Content-Type", "application/json") + var params = mux.Vars(r) + username := r.Header.Get("user") + user, err := logic.GetUser(username) + if err != nil { + logger.Log(0, username, "failed to fetch user: ", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest")) + return + } + remoteGwID := params["access_point_id"] + if remoteGwID == "" { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("required params access_point_id"), "badrequest")) + return + } + var req models.UserRemoteGwsReq + err = json.NewDecoder(r.Body).Decode(&req) + if err != nil { + slog.Error("error decoding request body: ", "error", err) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + + userGwNodes := proLogic.GetUserRAGNodes(*user) + if _, ok := userGwNodes[remoteGwID]; !ok { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden")) + return + } + node, err := logic.GetNodeByID(remoteGwID) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch gw node %s, error: %v", remoteGwID, err), "badrequest")) + return + } + host, err := logic.GetHost(node.HostID.String()) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch gw host %s, error: %v", remoteGwID, err), "badrequest")) + return + } + network, err := logic.GetNetwork(node.Network) + if err != nil { + slog.Error("failed to get node network", "error", err) + } + var userConf models.ExtClient + allextClients, err := logic.GetAllExtClients() + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + for _, extClient := range allextClients { + if extClient.Network != network.NetID || extClient.IngressGatewayID != node.ID.String() { + continue + } + if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username { + userConf = extClient + userConf.AllowedIPs = logic.GetExtclientAllowedIPs(extClient) + } + } + if userConf.ClientID == "" { + // create a new conf + userConf.OwnerID = user.UserName + userConf.RemoteAccessClientID = req.RemoteAccessClientID + userConf.IngressGatewayID = node.ID.String() + + // set extclient dns to ingressdns if extclient dns is not explicitly set + if (userConf.DNS == "") && (node.IngressDNS != "") { + userConf.DNS = node.IngressDNS + } + + userConf.Network = node.Network + host, err := logic.GetHost(node.HostID.String()) + if err != nil { + logger.Log(0, r.Header.Get("user"), + fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", node.ID, err)) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + listenPort := logic.GetPeerListenPort(host) + if host.EndpointIP.To4() == nil { + userConf.IngressGatewayEndpoint = fmt.Sprintf("[%s]:%d", host.EndpointIPv6.String(), listenPort) + } else { + userConf.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort) + } + userConf.Enabled = true + parentNetwork, err := logic.GetNetwork(node.Network) + if err == nil { // check if parent network default ACL is enabled (yes) or not (no) + userConf.Enabled = parentNetwork.DefaultACL == "yes" + } + if err = logic.CreateExtClient(&userConf); err != nil { + slog.Error( + "failed to create extclient", + "user", + r.Header.Get("user"), + "network", + node.Network, + "error", + err, + ) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + } + userGw := models.UserRemoteGws{ + GwID: node.ID.String(), + GWName: host.Name, + Network: node.Network, + GwClient: userConf, + Connected: true, + IsInternetGateway: node.IsInternetGateway, + GwPeerPublicKey: host.PublicKey.String(), + GwListenPort: logic.GetPeerListenPort(host), + Metadata: node.Metadata, + AllowedEndpoints: getAllowedRagEndpoints(&node, host), + NetworkAddresses: []string{network.AddressRange, network.AddressRange6}, + } + + slog.Debug("returned user gw config", "user", user.UserName, "gws", userGw) + logic.ReturnSuccessResponseWithJson(w, r, userGw, "fetched user config to gw "+remoteGwID) +} + // @Summary Get Users Remote Access Gw. // @Router /api/users/{username}/remote_access_gw [get] // @Tags Users @@ -876,6 +1087,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) { network, err := logic.GetNetwork(node.Network) if err != nil { slog.Error("failed to get node network", "error", err) + continue } gws := userGws[node.Network] diff --git a/pro/initialize.go b/pro/initialize.go index 1c6ba8a1c..3a41b1e38 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -33,6 +33,7 @@ func InitPro() { proControllers.UserHandlers, proControllers.FailOverHandlers, proControllers.InetHandlers, + proControllers.RacHandlers, ) controller.ListRoles = proControllers.ListRoles logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() { diff --git a/pro/logic/security.go b/pro/logic/security.go index fcc6d73cd..0bda7e026 100644 --- a/pro/logic/security.go +++ b/pro/logic/security.go @@ -50,6 +50,9 @@ func NetworkPermissionsCheck(username string, r *http.Request) error { if targetRsrc == "" { return errors.New("target rsrc is missing") } + if r.Header.Get("RAC") == "true" && r.Method == http.MethodGet { + return nil + } if netID == "" { return errors.New("network id is missing") } diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 1d336cc17..0f3db1055 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -511,6 +511,31 @@ func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, n _, ok = rsrcScope[rsrcID] return ok } + +func DoesUserHaveAccessToRAGNode(user models.User, node models.Node) bool { + userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user) + logger.Log(3, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope)) + _, allNetAccess := userGwAccessScope["*"] + if node.IsIngressGateway && !node.PendingDelete { + if allNetAccess { + return true + } else { + gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)] + scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID] + if !ok { + if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok { + return false + } + } + if scope.VPNaccess { + return true + } + + } + } + return false +} + func GetUserRAGNodes(user models.User) (gws map[string]models.Node) { gws = make(map[string]models.Node) userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user) From 287bcd8abc1f48845124b7544565621077207452 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 2 Oct 2024 15:43:01 +0400 Subject: [PATCH 048/169] static node init --- logic/extpeers.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/logic/extpeers.go b/logic/extpeers.go index c619dde94..e9afa96cb 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -528,3 +528,16 @@ func GetExtclientAllowedIPs(client models.ExtClient) (allowedIPs []string) { } return } + +func GetStaticNodesByGw(gwNode models.Node) (staticNode []models.Node) { + extClients, err := GetAllExtClients() + if err != nil { + return + } + for _, extI := range extClients { + if extI.IngressGatewayID == gwNode.ID.String() { + staticNode = append(staticNode, models.Node{}) + } + } + return +} From 24cee9b6deefe9a1760fafbdb691858a5e2af239 Mon Sep 17 00:00:00 2001 From: Max Ma Date: Thu, 10 Oct 2024 00:15:58 -0900 Subject: [PATCH 049/169] NET-1608:reset failover if endpoint changed (#3149) * reset failover if endpoint changed * add peerUpdate in pull when resetfailover * remove go routine for peerUpdate in pull * update peerUpdate in pull --- controllers/hosts.go | 10 +++++++++- logic/hosts.go | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/controllers/hosts.go b/controllers/hosts.go index 349894331..dbfbc6d51 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -167,6 +167,8 @@ func pull(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + + sendPeerUpdate := false for _, nodeID := range host.Nodes { node, err := logic.GetNodeByID(nodeID) if err != nil { @@ -174,7 +176,13 @@ func pull(w http.ResponseWriter, r *http.Request) { continue } if node.FailedOverBy != uuid.Nil { - go logic.ResetFailedOverPeer(&node) + logic.ResetFailedOverPeer(&node) + sendPeerUpdate = true + } + } + if sendPeerUpdate { + if err := mq.PublishPeerUpdate(true); err != nil { + logger.Log(0, "fail to publish peer update: ", err.Error()) } } allNodes, err := logic.GetAllNodes() diff --git a/logic/hosts.go b/logic/hosts.go index 0fa8887e9..48482e045 100644 --- a/logic/hosts.go +++ b/logic/hosts.go @@ -10,6 +10,7 @@ import ( "github.com/google/uuid" "golang.org/x/crypto/bcrypt" + "golang.org/x/exp/slog" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" @@ -254,14 +255,31 @@ func UpdateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) currHost.WgPublicListenPort = newHost.WgPublicListenPort sendPeerUpdate = true } + isEndpointChanged := false if currHost.EndpointIP.String() != newHost.EndpointIP.String() { currHost.EndpointIP = newHost.EndpointIP sendPeerUpdate = true + isEndpointChanged = true } if currHost.EndpointIPv6.String() != newHost.EndpointIPv6.String() { currHost.EndpointIPv6 = newHost.EndpointIPv6 sendPeerUpdate = true + isEndpointChanged = true } + + if isEndpointChanged { + for _, nodeID := range currHost.Nodes { + node, err := GetNodeByID(nodeID) + if err != nil { + slog.Error("failed to get node:", "id", node.ID, "error", err) + continue + } + if node.FailedOverBy != uuid.Nil { + ResetFailedOverPeer(&node) + } + } + } + currHost.DaemonInstalled = newHost.DaemonInstalled currHost.Debug = newHost.Debug currHost.Verbosity = newHost.Verbosity From b41353b415ef5435ff846e0250251c6293973724 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 14 Oct 2024 16:36:25 +0400 Subject: [PATCH 050/169] add static nodes to api resp --- controllers/node.go | 2 ++ logic/extpeers.go | 26 +++++++++++++++++++++++++- logic/nodes.go | 14 ++++++++++++++ models/node.go | 5 ++++- pro/logic/user_mgmt.go | 4 +++- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/controllers/node.go b/controllers/node.go index fd6f5d902..15c1f2fb3 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -362,6 +362,8 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) { } if !userPlatformRole.FullAccess { nodes = logic.GetFilteredNodesByUserAccess(*user, nodes) + } else { + nodes = logic.AddStaticNodestoList(nodes) } } // return all the nodes in JSON/API format diff --git a/logic/extpeers.go b/logic/extpeers.go index e9afa96cb..24ee787fe 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -529,6 +529,25 @@ func GetExtclientAllowedIPs(client models.ExtClient) (allowedIPs []string) { return } +func GetStaticNodesByNetwork(network models.NetworkID) (staticNode []models.Node) { + extClients, err := GetAllExtClients() + if err != nil { + return + } + for _, extI := range extClients { + if extI.Network == network.String() { + n := models.Node{ + IsStatic: true, + StaticNode: extI, + IsUserNode: extI.RemoteAccessClientID != "", + } + staticNode = append(staticNode, n) + } + } + + return +} + func GetStaticNodesByGw(gwNode models.Node) (staticNode []models.Node) { extClients, err := GetAllExtClients() if err != nil { @@ -536,7 +555,12 @@ func GetStaticNodesByGw(gwNode models.Node) (staticNode []models.Node) { } for _, extI := range extClients { if extI.IngressGatewayID == gwNode.ID.String() { - staticNode = append(staticNode, models.Node{}) + n := models.Node{ + IsStatic: true, + StaticNode: extI, + IsUserNode: extI.RemoteAccessClientID != "", + } + staticNode = append(staticNode, n) } } return diff --git a/logic/nodes.go b/logic/nodes.go index e241c6ccc..b5ad8ee8d 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -378,6 +378,20 @@ func GetAllNodes() ([]models.Node, error) { return nodes, nil } +func AddStaticNodestoList(nodes []models.Node) []models.Node { + netMap := make(map[string]struct{}) + for _, node := range nodes { + if _, ok := netMap[node.Network]; ok { + continue + } + if node.IsIngressGateway { + nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network))...) + netMap[node.Network] = struct{}{} + } + } + return nodes +} + // GetNetworkByNode - gets the network model from a node func GetNetworkByNode(node *models.Node) (models.Network, error) { diff --git a/models/node.go b/models/node.go index e5ea2cfc4..d5534744e 100644 --- a/models/node.go +++ b/models/node.go @@ -98,7 +98,10 @@ type Node struct { IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"` InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"` InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"` - AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips" swaggertype:"array,number"` + AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips" swaggertype:"array,number"` + IsStatic bool `json:"is_static"` + IsUserNode bool `json:"is_user_node"` + StaticNode ExtClient `json:"static_node"` } // LegacyNode - legacy struct for node model diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 0f3db1055..89799d4a9 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -687,7 +687,9 @@ func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filter nodesMap := make(map[string]struct{}) allNetworkRoles := make(map[models.UserRoleID]struct{}) - + defer func() { + logic.AddStaticNodestoList(nodes) + }() if len(user.NetworkRoles) > 0 { for _, netRoles := range user.NetworkRoles { for netRoleI := range netRoles { From 6ccafe82ede77d35846f0781bf5bb725d7430b2b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 15 Oct 2024 19:36:46 +0400 Subject: [PATCH 051/169] set static nodes to list --- controllers/node.go | 5 +++-- models/api_node.go | 6 ++++++ pro/logic/user_mgmt.go | 8 +++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/controllers/node.go b/controllers/node.go index 15c1f2fb3..ab28ba96d 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -326,6 +326,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) { if len(filteredNodes) > 0 { nodes = filteredNodes } + nodes = logic.AddStaticNodestoList(nodes) // returns all the nodes in JSON/API format apiNodes := logic.GetAllNodesAPI(nodes[:]) @@ -362,10 +363,10 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) { } if !userPlatformRole.FullAccess { nodes = logic.GetFilteredNodesByUserAccess(*user, nodes) - } else { - nodes = logic.AddStaticNodestoList(nodes) } + } + nodes = logic.AddStaticNodestoList(nodes) // return all the nodes in JSON/API format apiNodes := logic.GetAllNodesAPI(nodes[:]) logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to") diff --git a/models/api_node.go b/models/api_node.go index 0c91bbeca..14d2d1640 100644 --- a/models/api_node.go +++ b/models/api_node.go @@ -48,6 +48,9 @@ type ApiNode struct { InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"` InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"` AdditionalRagIps []string `json:"additional_rag_ips" yaml:"additional_rag_ips"` + IsStatic bool `json:"is_static"` + IsUserNode bool `json:"is_user_node"` + StaticNode ExtClient `json:"static_node"` } // ApiNode.ConvertToServerNode - converts an api node to a server node @@ -183,6 +186,9 @@ func (nm *Node) ConvertToAPINode() *ApiNode { for _, ip := range nm.AdditionalRagIps { apiNode.AdditionalRagIps = append(apiNode.AdditionalRagIps, ip.String()) } + apiNode.IsStatic = nm.IsStatic + apiNode.IsUserNode = nm.IsUserNode + apiNode.StaticNode = nm.StaticNode return &apiNode } diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 89799d4a9..cb9da06bf 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -688,7 +688,7 @@ func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filter nodesMap := make(map[string]struct{}) allNetworkRoles := make(map[models.UserRoleID]struct{}) defer func() { - logic.AddStaticNodestoList(nodes) + filteredNodes = logic.AddStaticNodestoList(filteredNodes) }() if len(user.NetworkRoles) > 0 { for _, netRoles := range user.NetworkRoles { @@ -698,7 +698,8 @@ func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filter } } if _, ok := user.NetworkRoles[models.AllNetworks]; ok { - return nodes + filteredNodes = nodes + return } if len(user.UserGroups) > 0 { for userGID := range user.UserGroups { @@ -706,7 +707,8 @@ func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filter if err == nil { if len(userG.NetworkRoles) > 0 { if _, ok := userG.NetworkRoles[models.AllNetworks]; ok { - return nodes + filteredNodes = nodes + return } for _, netRoles := range userG.NetworkRoles { for netRoleI := range netRoles { From 43d948948272792b05b7a099e25d6825cb832271 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 16 Oct 2024 18:46:26 +0400 Subject: [PATCH 052/169] fix static check --- logic/nodes.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/logic/nodes.go b/logic/nodes.go index af59f6e95..b0f132363 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -710,11 +710,7 @@ func GetTagMapWithNodes(netID models.NetworkID) (tagNodesMap map[models.TagID][] continue } for nodeTagID := range nodeI.Tags { - if _, ok := tagNodesMap[nodeTagID]; ok { - tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) - } else { - tagNodesMap[nodeTagID] = []models.Node{nodeI} - } + tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) } } return From 272dfda088c0ef007fb0488bb89e775f15ad070d Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 10:41:33 +0400 Subject: [PATCH 053/169] create default tags on network --- controllers/network.go | 3 ++- logic/tags.go | 22 ++++++++++++++++++++++ migrate/migrate.go | 11 +++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/controllers/network.go b/controllers/network.go index 03f40cb9e..d6ad45e6e 100644 --- a/controllers/network.go +++ b/controllers/network.go @@ -530,8 +530,9 @@ func createNetwork(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(network.NetID)) + logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(network.NetID)) + logic.CreateDefaultTags(models.NetworkID(network.NetID)) //add new network to allocated ip map go logic.AddNetworkToAllocatedIpMap(network.NetID) diff --git a/logic/tags.go b/logic/tags.go index 413f9a3d5..1bca39682 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -7,9 +7,11 @@ import ( "regexp" "sort" "sync" + "time" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" + "golang.org/x/exp/slog" ) var tagMutex = &sync.RWMutex{} @@ -201,3 +203,23 @@ func CheckIDSyntax(id string) error { } return nil } + +func CreateDefaultTags(netID models.NetworkID) { + // create tag for remote access gws in the network + tag := models.Tag{ + ID: models.TagID(fmt.Sprintf("%s.%s", netID.String(), "remote-access-gws")), + TagName: "remote-access-gws", + Network: netID, + CreatedBy: "auto", + CreatedAt: time.Now(), + } + _, err := GetTag(tag.ID) + if err == nil { + return + } + err = InsertTag(tag) + if err != nil { + slog.Error("failed to create remote access gw tag", "error", err.Error()) + return + } +} diff --git a/migrate/migrate.go b/migrate/migrate.go index 6612d4ddc..3f42a0a9e 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -26,6 +26,7 @@ func Run() { updateHosts() updateNodes() updateAcls() + createDefaultTags() } func assignSuperAdmin() { @@ -432,3 +433,13 @@ func syncUsers() { } } } + +func createDefaultTags() { + networks, err := logic.GetNetworks() + if err != nil { + return + } + for _, network := range networks { + logic.CreateDefaultTags(models.NetworkID(network.NetID)) + } +} From 7d80274ff808c326de027c2fd7ff4e943a2aec4f Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 11:04:43 +0400 Subject: [PATCH 054/169] create default acl for remote access gw --- logic/acls.go | 27 +++++++++++++++++++++++++++ migrate/migrate.go | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/logic/acls.go b/logic/acls.go index 91a1d0863..ddb5ecfd7 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -69,6 +69,33 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { InsertAcl(defaultUserAcl) } + if !IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, "all-remote-access-gws"))) { + defaultUserAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-remote-access-gws")), + Default: true, + Name: "all-remote-access-gws", + NetworkID: netID, + RuleType: models.DevicePolicy, + Src: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + }, + }, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }, + }, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + InsertAcl(defaultUserAcl) + } + } // DeleteDefaultNetworkPolicies - deletes all default network acl policies diff --git a/migrate/migrate.go b/migrate/migrate.go index ba935789b..862f1dd2b 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -335,7 +335,6 @@ func syncUsers() { if err == nil { for _, netI := range networks { logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(netI.NetID)) - logic.CreateDefaultAclNetworkPolicies(models.NetworkID(netI.NetID)) networkNodes := logic.GetNetworkNodesMemory(nodes, netI.NetID) for _, networkNodeI := range networkNodes { if networkNodeI.IsIngressGateway { @@ -442,5 +441,6 @@ func createDefaultTags() { } for _, network := range networks { logic.CreateDefaultTags(models.NetworkID(network.NetID)) + logic.CreateDefaultAclNetworkPolicies(models.NetworkID(network.NetID)) } } From d407c6b6c4353723c0f0d91b799792daa364eac7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 11:24:37 +0400 Subject: [PATCH 055/169] add node to remote access gw tag --- logic/gateway.go | 3 +++ logic/tags.go | 4 ++-- models/tags.go | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/logic/gateway.go b/logic/gateway.go index b25d3e1d0..ba7521976 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -2,6 +2,7 @@ package logic import ( "errors" + "fmt" "time" "github.com/gravitl/netmaker/database" @@ -182,6 +183,7 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq if node.Metadata == "" { node.Metadata = "This host can be used for remote access" } + node.Tags[models.TagID(fmt.Sprintf("%s.%s", netid, models.RemoteAccessTagName))] = struct{}{} err = UpsertNode(&node) if err != nil { return models.Node{}, err @@ -257,6 +259,7 @@ func DeleteIngressGateway(nodeid string) (models.Node, []models.ExtClient, error if !servercfg.IsPro { node.IsInternetGateway = false } + delete(node.Tags, models.TagID(fmt.Sprintf("%s.%s", node.Network, models.RemoteAccessTagName))) node.IngressGatewayRange = "" node.Metadata = "" err = UpsertNode(&node) diff --git a/logic/tags.go b/logic/tags.go index 1bca39682..f3c45caed 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -207,8 +207,8 @@ func CheckIDSyntax(id string) error { func CreateDefaultTags(netID models.NetworkID) { // create tag for remote access gws in the network tag := models.Tag{ - ID: models.TagID(fmt.Sprintf("%s.%s", netID.String(), "remote-access-gws")), - TagName: "remote-access-gws", + ID: models.TagID(fmt.Sprintf("%s.%s", netID.String(), models.RemoteAccessTagName)), + TagName: models.RemoteAccessTagName, Network: netID, CreatedBy: "auto", CreatedAt: time.Now(), diff --git a/models/tags.go b/models/tags.go index 7589d451d..c611ade7b 100644 --- a/models/tags.go +++ b/models/tags.go @@ -7,6 +7,10 @@ import ( type TagID string +const ( + RemoteAccessTagName = "remote-access-gws" +) + func (id TagID) String() string { return string(id) } From 14152a9484792119e53d25a0961b76c4c8e2c57e Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 11:30:28 +0400 Subject: [PATCH 056/169] add remote access tags in migration --- migrate/migrate.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/migrate/migrate.go b/migrate/migrate.go index 3f42a0a9e..d7841e0f7 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -21,12 +21,12 @@ import ( func Run() { updateEnrollmentKeys() assignSuperAdmin() + createDefaultTags() removeOldUserGrps() syncUsers() updateHosts() updateNodes() updateAcls() - createDefaultTags() } func assignSuperAdmin() { @@ -167,6 +167,16 @@ func updateNodes() { return } for _, node := range nodes { + node := node + if node.IsIngressGateway { + tagID := models.TagID(fmt.Sprintf("%s.%s", node.Network, + models.RemoteAccessTagName)) + if _, ok := node.Tags[tagID]; !ok { + node.Tags[tagID] = struct{}{} + logic.UpsertNode(&node) + } + + } if node.IsEgressGateway { egressRanges, update := removeInterGw(node.EgressGatewayRanges) if update { From be086ee87213f4fb25ad6941b34f99c8923bdc8b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 11:37:32 +0400 Subject: [PATCH 057/169] update traffic direction of default remote access acl to Bi --- logic/acls.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/acls.go b/logic/acls.go index ddb5ecfd7..5a28152b4 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -88,7 +88,7 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { Value: "*", }, }, - AllowedDirection: models.TrafficDirectionUni, + AllowedDirection: models.TrafficDirectionBi, Enabled: true, CreatedBy: "auto", CreatedAt: time.Now().UTC(), From 4e4ffac787e3bc9e9d2da2651bdce4ef2783c1b3 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 13:07:46 +0400 Subject: [PATCH 058/169] fix acls peer update logic --- controllers/acls.go | 2 +- logic/acls.go | 48 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 20084dd4b..b588aeed1 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -224,7 +224,7 @@ func deleteAcl(w http.ResponseWriter, r *http.Request) { return } if acl.Default { - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot delete default policy"), "badrequest")) return } err = logic.DeleteAcl(acl) diff --git a/logic/acls.go b/logic/acls.go index 5a28152b4..c6b7cd86a 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -281,15 +281,13 @@ func DeleteAcl(a models.Acl) error { return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) } -// GetDefaultPolicy - fetches default policy in the network by ruleType -func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) { - acls, _ := ListAcls(netID) - for _, acl := range acls { - if acl.Default && acl.RuleType == ruleType { - return acl, nil - } +// GetDefaultNodesPolicy - fetches default policy in the network by ruleType +func GetDefaultNodesPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) { + acl, err := GetAcl(models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes"))) + if err != nil { + return models.Acl{}, errors.New("default rule not found") } - return models.Acl{}, errors.New("default rule not found") + return acl, nil } // ListUserPolicies - lists all acl policies enforced on an user @@ -396,7 +394,7 @@ func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // check default policy if all allowed return true - defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) + defaultPolicy, err := GetDefaultNodesPolicy(models.NetworkID(node.Network), models.DevicePolicy) if err == nil { if defaultPolicy.Enabled { return true @@ -405,21 +403,53 @@ func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // list device policies policies := listDevicePolicies(models.NetworkID(peer.Network)) for _, policy := range policies { + if !policy.Enabled { + continue + } srcMap := convAclTagToValueMap(policy.Src) dstMap := convAclTagToValueMap(policy.Dst) fmt.Printf("\n======> SRCMAP: %+v\n", srcMap) fmt.Printf("\n======> DSTMAP: %+v\n", dstMap) fmt.Printf("\n======> node Tags: %+v\n", node.Tags) fmt.Printf("\n======> peer Tags: %+v\n", peer.Tags) + for tagID := range node.Tags { + if _, ok := dstMap[tagID.String()]; ok { + if _, ok := srcMap["*"]; ok { + return true + } + for tagID := range peer.Tags { + if _, ok := srcMap[tagID.String()]; ok { + return true + } + } + } + if _, ok := srcMap[tagID.String()]; ok { + if _, ok := dstMap["*"]; ok { + return true + } + for tagID := range peer.Tags { + if _, ok := dstMap[tagID.String()]; ok { + return true + } + } + } + } for tagID := range peer.Tags { if _, ok := dstMap[tagID.String()]; ok { + if _, ok := srcMap["*"]; ok { + return true + } for tagID := range node.Tags { + if _, ok := srcMap[tagID.String()]; ok { return true } } } if _, ok := srcMap[tagID.String()]; ok { + if _, ok := dstMap["*"]; ok { + return true + } for tagID := range node.Tags { if _, ok := dstMap[tagID.String()]; ok { return true From 1596060d4ba548ab38bf90822dcf936b924dfbf7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 14:13:33 +0400 Subject: [PATCH 059/169] add tags to extclient --- models/extclient.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/extclient.go b/models/extclient.go index 9d67207d3..d76ef2970 100644 --- a/models/extclient.go +++ b/models/extclient.go @@ -19,6 +19,7 @@ type ExtClient struct { DeniedACLs map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"` RemoteAccessClientID string `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine PostUp string `json:"postup" bson:"postup"` + Tags map[TagID]struct{} `json:"tags"` PostDown string `json:"postdown" bson:"postdown"` } From e2ac963d0a549c52eaed3b86077a7fba837d4a1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:31:34 +0400 Subject: [PATCH 060/169] Bump github.com/go-playground/validator/v10 from 10.22.0 to 10.22.1 (#3128) Bumps [github.com/go-playground/validator/v10](https://github.com/go-playground/validator) from 10.22.0 to 10.22.1. - [Release notes](https://github.com/go-playground/validator/releases) - [Commits](https://github.com/go-playground/validator/compare/v10.22.0...v10.22.1) --- updated-dependencies: - dependency-name: github.com/go-playground/validator/v10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e2b53e6bc..8594c3e7c 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.23 require ( github.com/eclipse/paho.mqtt.golang v1.4.3 - github.com/go-playground/validator/v10 v10.22.0 + github.com/go-playground/validator/v10 v10.22.1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/uuid v1.6.0 github.com/gorilla/handlers v1.5.2 diff --git a/go.sum b/go.sum index 9f0434ce8..0c85fa97b 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= -github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= From d17bc56acd053b635f6b6e381c43dca56f2aa9e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:31:48 +0400 Subject: [PATCH 061/169] Bump github.com/posthog/posthog-go from 1.2.21 to 1.2.24 (#3129) Bumps [github.com/posthog/posthog-go](https://github.com/posthog/posthog-go) from 1.2.21 to 1.2.24. - [Release notes](https://github.com/posthog/posthog-go/releases) - [Changelog](https://github.com/PostHog/posthog-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/posthog/posthog-go/compare/v1.2.21...v1.2.24) --- updated-dependencies: - dependency-name: github.com/posthog/posthog-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8594c3e7c..2c92eaf5b 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 github.com/c-robinson/iplib v1.0.8 - github.com/posthog/posthog-go v1.2.21 + github.com/posthog/posthog-go v1.2.24 ) require ( diff --git a/go.sum b/go.sum index 0c85fa97b..29a2bea9b 100644 --- a/go.sum +++ b/go.sum @@ -60,8 +60,8 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posthog/posthog-go v1.2.21 h1:p2ea0l+Qwtk+VC2LCAI87Dz36vwj9i+QHw5s6CpRikA= -github.com/posthog/posthog-go v1.2.21/go.mod h1:uYC2l1Yktc8E+9FAHJ9QZG4vQf/NHJPD800Hsm7DzoM= +github.com/posthog/posthog-go v1.2.24 h1:A+iG4saBJemo++VDlcWovbYf8KFFNUfrCoJtsc40RPA= +github.com/posthog/posthog-go v1.2.24/go.mod h1:uYC2l1Yktc8E+9FAHJ9QZG4vQf/NHJPD800Hsm7DzoM= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= From ab67ed41e49e1c42062c1dbec481ea8ad6311079 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:32:15 +0400 Subject: [PATCH 062/169] Bump github.com/mattn/go-sqlite3 from 1.14.22 to 1.14.24 (#3153) Bumps [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) from 1.14.22 to 1.14.24. - [Release notes](https://github.com/mattn/go-sqlite3/releases) - [Commits](https://github.com/mattn/go-sqlite3/compare/v1.14.22...v1.14.24) --- updated-dependencies: - dependency-name: github.com/mattn/go-sqlite3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2c92eaf5b..22254fdb1 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gorilla/handlers v1.5.2 github.com/gorilla/mux v1.8.1 github.com/lib/pq v1.10.9 - github.com/mattn/go-sqlite3 v1.14.22 + github.com/mattn/go-sqlite3 v1.14.24 github.com/rqlite/gorqlite v0.0.0-20240122221808-a8a425b1a6aa github.com/seancfoley/ipaddress-go v1.7.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e diff --git a/go.sum b/go.sum index 29a2bea9b..f5d8f5acd 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= From e6609e495694042a9454139e221228600aacb59c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:33:04 +0400 Subject: [PATCH 063/169] Bump golang.org/x/crypto from 0.27.0 to 0.28.0 (#3157) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.27.0 to 0.28.0. - [Commits](https://github.com/golang/crypto/compare/v0.27.0...v0.28.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 22254fdb1..c57a22e8a 100644 --- a/go.mod +++ b/go.mod @@ -16,11 +16,11 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.9.0 github.com/txn2/txeh v1.5.5 - golang.org/x/crypto v0.27.0 + golang.org/x/crypto v0.28.0 golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.23.0 - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20221104135756-97bc4ad4a1cb gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index f5d8f5acd..6b400acaa 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -116,8 +116,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -129,8 +129,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From f0601849a538fdb2b28cd922dbfefac3014bce37 Mon Sep 17 00:00:00 2001 From: Aceix Date: Thu, 17 Oct 2024 10:35:36 +0000 Subject: [PATCH 064/169] fix: update documentation links to new docs (#3156) --- cli/cmd/user/groups.go | 2 +- cli/cmd/user/roles.go | 2 +- docs/Authentication.md | 2 +- pro/auth/error.go | 4 ++-- pro/auth/templates.go | 2 +- swagger.yaml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/cmd/user/groups.go b/cli/cmd/user/groups.go index 0406083e1..0cb8db0a2 100644 --- a/cli/cmd/user/groups.go +++ b/cli/cmd/user/groups.go @@ -56,7 +56,7 @@ var userGroupCreateCmd = &cobra.Command{ Short: "create user group", Long: `create user group`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("CLI doesn't support creation of groups currently. Visit the dashboard to create one or refer to our api documentation https://docs.v2.netmaker.io/reference") + fmt.Println("CLI doesn't support creation of groups currently. Visit the dashboard to create one or refer to our api documentation https://docs.netmaker.io/api") }, } diff --git a/cli/cmd/user/roles.go b/cli/cmd/user/roles.go index 2bb880ef5..fbb8a5920 100644 --- a/cli/cmd/user/roles.go +++ b/cli/cmd/user/roles.go @@ -58,7 +58,7 @@ var userRoleCreateCmd = &cobra.Command{ Short: "create user role", Long: `create user role`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("CLI doesn't support creation of roles currently. Visit the dashboard to create one or refer to our api documentation https://docs.v2.netmaker.io/reference") + fmt.Println("CLI doesn't support creation of roles currently. Visit the dashboard to create one or refer to our api documentation https://docs.netmaker.io/api") }, } diff --git a/docs/Authentication.md b/docs/Authentication.md index b1a7a4445..bd084a97c 100644 --- a/docs/Authentication.md +++ b/docs/Authentication.md @@ -7,4 +7,4 @@ Call the api/users/adm/authenticate endpoint (see documentation below for detail Note: While a MasterKey exists (configurable via env var or config file), it should be considered a backup option, used only when server access is lost. By default, this key is "secret key," but it's crucial to change this and keep it secure in your instance. -For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.org/index.html). +For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.io/). diff --git a/pro/auth/error.go b/pro/auth/error.go index eb49b8769..9fb532d95 100644 --- a/pro/auth/error.go +++ b/pro/auth/error.go @@ -93,12 +93,12 @@ var htmlBaseTemplate = ` ` var oauthNotConfigured = fmt.Sprintf(htmlBaseTemplate, `

Your Netmaker server does not have OAuth configured.

-

Please visit the docs here to learn how to.

`) +

Please visit the docs here to learn how to.

`) var oauthStateInvalid = fmt.Sprintf(htmlBaseTemplate, `

Invalid OAuth Session. Please re-try again.

`) var userNotAllowed = fmt.Sprintf(htmlBaseTemplate, `

Your account does not have access to the dashboard. Please contact your administrator for more information about your account.

-

Non-Admins can access the netmaker networks using RemoteAccessClient.

`) +

Non-Admins can access the netmaker networks using our Remote Access Client.

`) var userFirstTimeSignUp = fmt.Sprintf(htmlBaseTemplate, `

Thank you for signing up. Please contact your administrator for access.

`) diff --git a/pro/auth/templates.go b/pro/auth/templates.go index 52b9cd52e..10bee9ad8 100644 --- a/pro/auth/templates.go +++ b/pro/auth/templates.go @@ -118,7 +118,7 @@ var ssoErrCallbackTemplate = template.Must(

Error reason: {.Verb}

Your Netmaker server may not have SSO configured properly. - Please visit the docs for more information. + Please visit the docs for more information.

If you feel this is a mistake, please contact your network administrator. diff --git a/swagger.yaml b/swagger.yaml index e0b27e4b5..e3d8a276c 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -3098,7 +3098,7 @@ tags: Note: While a MasterKey exists (configurable via env var or config file), it should be considered a backup option, used only when server access is lost. By default, this key is "secret key," but it's crucial to change this and keep it secure in your instance. - For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.org/index.html). + For more information on configuration and security best practices, refer to the [Netmaker documentation](https://docs.netmaker.io/). name: Authentication - description: | Check out our [Pricing](https://www.netmaker.io/pricing). And Feel Free to [Contact Us](https://www.netmaker.io/contact) if you have any questions or need some clarifications. From d2918ccc2f7f3735499c1af9af1abaf87ea646b5 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 19:33:43 +0400 Subject: [PATCH 065/169] support tags system on ext clients --- controllers/tags.go | 15 ++++++++-- logic/nodes.go | 60 ++++++++++++++++++++++++++++++++++++++-- logic/tags.go | 67 +++++++++++++++++++++++++++++++++++++-------- models/tags.go | 14 +++++----- 4 files changed, 134 insertions(+), 22 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index 89f33b970..2def88f68 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -106,8 +106,19 @@ func createTag(w http.ResponseWriter, r *http.Request) { return } go func() { - for _, nodeID := range req.TaggedNodes { - node, err := logic.GetNodeByID(nodeID) + for _, node := range req.TaggedNodes { + if node.IsStatic { + extclient, err := logic.GetExtClient(node.StaticNode.ClientID, node.StaticNode.Network) + if err == nil && extclient.RemoteAccessClientID == "" { + if extclient.Tags == nil { + extclient.Tags = make(map[models.TagID]struct{}) + } + extclient.Tags[tag.ID] = struct{}{} + logic.SaveExtClient(&extclient) + } + continue + } + node, err := logic.GetNodeByID(node.ID) if err != nil { continue } diff --git a/logic/nodes.go b/logic/nodes.go index 2f8a4b6fd..85b857c87 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -727,11 +727,31 @@ func GetTagMapWithNodes(netID models.NetworkID) (tagNodesMap map[models.TagID][] tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) } } - return + return AddTagMapWithStaticNodes(netID, tagNodesMap) } -func GetNodesWithTag(tagID models.TagID) map[string]models.Node { +func AddTagMapWithStaticNodes(netID models.NetworkID, + tagNodesMap map[models.TagID][]models.Node) map[models.TagID][]models.Node { + extclients, err := GetNetworkExtClients(netID.String()) + if err != nil { + return tagNodesMap + } + for _, extclient := range extclients { + if extclient.Tags == nil || extclient.RemoteAccessClientID != "" { + continue + } + for tagID := range extclient.Tags { + tagNodesMap[tagID] = append(tagNodesMap[tagID], models.Node{ + IsStatic: true, + StaticNode: extclient, + }) + } + } + return tagNodesMap +} + +func GetNodesWithTag(tagID models.TagID) map[string]models.Node { nMap := make(map[string]models.Node) tag, err := GetTag(tagID) if err != nil { @@ -746,5 +766,41 @@ func GetNodesWithTag(tagID models.TagID) map[string]models.Node { nMap[nodeI.ID.String()] = nodeI } } + return AddStaticNodesWithTag(tag, nMap) +} + +func AddStaticNodesWithTag(tag models.Tag, nMap map[string]models.Node) map[string]models.Node { + extclients, err := GetNetworkExtClients(tag.Network.String()) + if err != nil { + return nMap + } + for _, extclient := range extclients { + if extclient.RemoteAccessClientID != "" { + continue + } + nMap[extclient.ClientID] = models.Node{ + IsStatic: true, + StaticNode: extclient, + } + } + return nMap +} + +func GetStaticNodeWithTag(tagID models.TagID) map[string]models.Node { + nMap := make(map[string]models.Node) + tag, err := GetTag(tagID) + if err != nil { + return nMap + } + extclients, err := GetNetworkExtClients(tag.Network.String()) + if err != nil { + return nMap + } + for _, extclient := range extclients { + nMap[extclient.ClientID] = models.Node{ + IsStatic: true, + StaticNode: extclient, + } + } return nMap } diff --git a/logic/tags.go b/logic/tags.go index f3c45caed..97d43b752 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -80,7 +80,7 @@ func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) { tagRespI := models.TagListResp{ Tag: tagI, UsedByCnt: len(tagsNodeMap[tagI.ID]), - TaggedNodes: tagsNodeMap[tagI.ID], + TaggedNodes: GetAllNodesAPI(tagsNodeMap[tagI.ID]), } resp = append(resp, tagRespI) } @@ -134,46 +134,91 @@ func ListNetworkTags(netID models.NetworkID) ([]models.Tag, error) { func UpdateTag(req models.UpdateTagReq, newID models.TagID) { tagMutex.Lock() defer tagMutex.Unlock() + var err error tagNodesMap := GetNodesWithTag(req.ID) - for _, nodeID := range req.TaggedNodes { - node, err := GetNodeByID(nodeID) - if err != nil { - continue + for _, apiNode := range req.TaggedNodes { + node := models.Node{} + if apiNode.IsStatic { + if apiNode.StaticNode.RemoteAccessClientID != "" { + continue + } + extclient, err := GetExtClient(apiNode.StaticNode.ClientID, apiNode.StaticNode.Network) + if err != nil { + continue + } + node.IsStatic = true + node.StaticNode = extclient + } else { + node, err = GetNodeByID(apiNode.ID) + if err != nil { + continue + } } if _, ok := tagNodesMap[node.ID.String()]; !ok { + if node.StaticNode.Tags == nil { + node.StaticNode.Tags = make(map[models.TagID]struct{}) + } if node.Tags == nil { node.Tags = make(map[models.TagID]struct{}) } if newID != "" { node.Tags[newID] = struct{}{} + node.StaticNode.Tags[newID] = struct{}{} } else { node.Tags[req.ID] = struct{}{} + node.StaticNode.Tags[req.ID] = struct{}{} + } + if node.IsStatic { + SaveExtClient(&node.StaticNode) + } else { + UpsertNode(&node) } - UpsertNode(&node) } else { if newID != "" { delete(node.Tags, req.ID) + delete(node.StaticNode.Tags, req.ID) + node.StaticNode.Tags[newID] = struct{}{} node.Tags[newID] = struct{}{} - UpsertNode(&node) + if node.IsStatic { + SaveExtClient(&node.StaticNode) + } else { + UpsertNode(&node) + } } delete(tagNodesMap, node.ID.String()) } } for _, deletedTaggedNode := range tagNodesMap { - deletedTaggedHost := deletedTaggedNode - delete(deletedTaggedHost.Tags, req.ID) - UpsertNode(&deletedTaggedHost) + delete(deletedTaggedNode.Tags, req.ID) + delete(deletedTaggedNode.StaticNode.Tags, req.ID) + if deletedTaggedNode.IsStatic { + SaveExtClient(&deletedTaggedNode.StaticNode) + } else { + UpsertNode(&deletedTaggedNode) + } } go func(req models.UpdateTagReq) { if newID != "" { tagNodesMap = GetNodesWithTag(req.ID) for _, nodeI := range tagNodesMap { nodeI := nodeI + if nodeI.StaticNode.Tags == nil { + nodeI.StaticNode.Tags = make(map[models.TagID]struct{}) + } + if nodeI.Tags == nil { + nodeI.Tags = make(map[models.TagID]struct{}) + } delete(nodeI.Tags, req.ID) + delete(nodeI.StaticNode.Tags, req.ID) nodeI.Tags[newID] = struct{}{} - UpsertNode(&nodeI) + nodeI.StaticNode.Tags[newID] = struct{}{} + if nodeI.IsStatic { + SaveExtClient(&nodeI.StaticNode) + } else { + UpsertNode(&nodeI) + } } } }(req) diff --git a/models/tags.go b/models/tags.go index c611ade7b..9fcb449da 100644 --- a/models/tags.go +++ b/models/tags.go @@ -30,23 +30,23 @@ type Tag struct { type CreateTagReq struct { TagName string `json:"tag_name"` Network NetworkID `json:"network"` - TaggedNodes []string `json:"tagged_nodes"` + TaggedNodes []ApiNode `json:"tagged_nodes"` } type TagListResp struct { Tag - UsedByCnt int `json:"used_by_count"` - TaggedNodes []Node `json:"tagged_nodes"` + UsedByCnt int `json:"used_by_count"` + TaggedNodes []ApiNode `json:"tagged_nodes"` } type TagListRespNodes struct { Tag - UsedByCnt int `json:"used_by_count"` - TaggedNodes []Node `json:"tagged_nodes"` + UsedByCnt int `json:"used_by_count"` + TaggedNodes []ApiNode `json:"tagged_nodes"` } type UpdateTagReq struct { Tag - NewName string `json:"new_name"` - TaggedNodes []string `json:"tagged_nodes"` + NewName string `json:"new_name"` + TaggedNodes []ApiNode `json:"tagged_nodes"` } From 618c11f89a0e3365762048f9fb46e05272174d92 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 19:53:57 +0400 Subject: [PATCH 066/169] remove tag from extclient on tag deletion --- logic/tags.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/logic/tags.go b/logic/tags.go index 97d43b752..9dd309eeb 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -65,6 +65,14 @@ func DeleteTag(tagID models.TagID) error { UpsertNode(&nodeI) } } + + extclients, _ := GetNetworkExtClients(tag.Network.String()) + for _, extclient := range extclients { + if _, ok := extclient.Tags[tagID]; ok { + delete(extclient.Tags, tagID) + SaveExtClient(&extclient) + } + } return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String()) } @@ -138,6 +146,7 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) { tagNodesMap := GetNodesWithTag(req.ID) for _, apiNode := range req.TaggedNodes { node := models.Node{} + var nodeID string if apiNode.IsStatic { if apiNode.StaticNode.RemoteAccessClientID != "" { continue @@ -147,15 +156,17 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) { continue } node.IsStatic = true + nodeID = extclient.ClientID node.StaticNode = extclient } else { node, err = GetNodeByID(apiNode.ID) if err != nil { continue } + nodeID = node.ID.String() } - if _, ok := tagNodesMap[node.ID.String()]; !ok { + if _, ok := tagNodesMap[nodeID]; !ok { if node.StaticNode.Tags == nil { node.StaticNode.Tags = make(map[models.TagID]struct{}) } @@ -186,7 +197,7 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) { UpsertNode(&node) } } - delete(tagNodesMap, node.ID.String()) + delete(tagNodesMap, nodeID) } } From de7cabacba9a95e1b58e65d4edc7962aea7e81be Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 19:55:58 +0400 Subject: [PATCH 067/169] update tags on extclient update call --- logic/extpeers.go | 1 + models/extclient.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 24ee787fe..542f98b56 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -329,6 +329,7 @@ func UpdateExtClient(old *models.ExtClient, update *models.CustomExtClient) mode // replace any \r\n with \n in postup and postdown from HTTP request new.PostUp = strings.Replace(update.PostUp, "\r\n", "\n", -1) new.PostDown = strings.Replace(update.PostDown, "\r\n", "\n", -1) + new.Tags = update.Tags return new } diff --git a/models/extclient.go b/models/extclient.go index d76ef2970..b84a7c8d9 100644 --- a/models/extclient.go +++ b/models/extclient.go @@ -19,8 +19,8 @@ type ExtClient struct { DeniedACLs map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"` RemoteAccessClientID string `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine PostUp string `json:"postup" bson:"postup"` - Tags map[TagID]struct{} `json:"tags"` PostDown string `json:"postdown" bson:"postdown"` + Tags map[TagID]struct{} `json:"tags"` } // CustomExtClient - struct for CustomExtClient params @@ -34,4 +34,5 @@ type CustomExtClient struct { RemoteAccessClientID string `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine PostUp string `json:"postup" bson:"postup" validate:"max=1024"` PostDown string `json:"postdown" bson:"postdown" validate:"max=1024"` + Tags map[TagID]struct{} `json:"tags"` } From 27f276a3fe903c5c4e5493ba22ce4a95d30a3866 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 17 Oct 2024 20:25:31 +0400 Subject: [PATCH 068/169] isolate tag updates for extclient and nodes --- logic/tags.go | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/logic/tags.go b/logic/tags.go index 9dd309eeb..cddcb7002 100644 --- a/logic/tags.go +++ b/logic/tags.go @@ -174,26 +174,32 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) { node.Tags = make(map[models.TagID]struct{}) } if newID != "" { - node.Tags[newID] = struct{}{} - node.StaticNode.Tags[newID] = struct{}{} - } else { - node.Tags[req.ID] = struct{}{} - node.StaticNode.Tags[req.ID] = struct{}{} - } - if node.IsStatic { - SaveExtClient(&node.StaticNode) + if node.IsStatic { + node.StaticNode.Tags[newID] = struct{}{} + SaveExtClient(&node.StaticNode) + } else { + node.Tags[newID] = struct{}{} + UpsertNode(&node) + } + } else { - UpsertNode(&node) + if node.IsStatic { + node.StaticNode.Tags[req.ID] = struct{}{} + SaveExtClient(&node.StaticNode) + } else { + node.Tags[req.ID] = struct{}{} + UpsertNode(&node) + } } } else { if newID != "" { delete(node.Tags, req.ID) delete(node.StaticNode.Tags, req.ID) - node.StaticNode.Tags[newID] = struct{}{} - node.Tags[newID] = struct{}{} if node.IsStatic { + node.StaticNode.Tags[newID] = struct{}{} SaveExtClient(&node.StaticNode) } else { + node.Tags[newID] = struct{}{} UpsertNode(&node) } } From aea26dfdf69abe17cd17814880f167199a394963 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 11:21:32 +0400 Subject: [PATCH 069/169] check acl policy on ext client --- logic/acls.go | 9 +++++++-- logic/extpeers.go | 10 ++++++++++ logic/peers.go | 1 + models/extclient.go | 11 +++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index c6b7cd86a..b300abbb6 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -323,8 +323,8 @@ func ListUserPolicies(u models.User) []models.Acl { return acls } -// ListUserPoliciesByNetwork - lists all acl user policies in a network -func ListUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { +// listUserPoliciesByNetwork - lists all acl user policies in a network +func listUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { data, err := database.FetchRecords(database.ACLS_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{} @@ -391,6 +391,11 @@ func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { return aclValueMap } +func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { + listUserPoliciesByNetwork(models.NetworkID(peer.Network)) + return true +} + // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // check default policy if all allowed return true diff --git a/logic/extpeers.go b/logic/extpeers.go index 542f98b56..e37b2be58 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -413,6 +413,16 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA if !IsClientNodeAllowed(&extPeer, peer.ID.String()) { continue } + if extPeer.RemoteAccessClientID == "" { + if !IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), *peer) { + continue + } + } else { + if !IsUserAllowedToCommunicate(extPeer.OwnerID, *peer) { + continue + } + } + pubkey, err := wgtypes.ParseKey(extPeer.PublicKey) if err != nil { logger.Log(1, "error parsing ext pub key:", err.Error()) diff --git a/logic/peers.go b/logic/peers.go index ead2bc3b8..b2456826d 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -426,6 +426,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error()) } for _, extPeer := range extPeers { + allowedips = append(allowedips, extPeer.AllowedIPs...) } } diff --git a/models/extclient.go b/models/extclient.go index b84a7c8d9..d967da278 100644 --- a/models/extclient.go +++ b/models/extclient.go @@ -36,3 +36,14 @@ type CustomExtClient struct { PostDown string `json:"postdown" bson:"postdown" validate:"max=1024"` Tags map[TagID]struct{} `json:"tags"` } + +func (ext *ExtClient) ConvertToStaticNode() Node { + + return Node{ + CommonNode: CommonNode{ + Network: ext.Network, + }, + IsStatic: true, + StaticNode: *ext, + } +} From 298749b76c6fa7d612d2d7fdf9fd5f836920ee1c Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 12:00:11 +0400 Subject: [PATCH 070/169] fix tag update on extclients --- logic/nodes.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/logic/nodes.go b/logic/nodes.go index 85b857c87..2560b1ea6 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -778,10 +778,13 @@ func AddStaticNodesWithTag(tag models.Tag, nMap map[string]models.Node) map[stri if extclient.RemoteAccessClientID != "" { continue } - nMap[extclient.ClientID] = models.Node{ - IsStatic: true, - StaticNode: extclient, + if _, ok := extclient.Tags[tag.ID]; ok { + nMap[extclient.ClientID] = models.Node{ + IsStatic: true, + StaticNode: extclient, + } } + } return nMap } From 292c0744d55eadc12269960b10891161b654739a Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 12:27:34 +0400 Subject: [PATCH 071/169] add tags to static node model --- models/extclient.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/extclient.go b/models/extclient.go index d967da278..a6214c34a 100644 --- a/models/extclient.go +++ b/models/extclient.go @@ -43,6 +43,7 @@ func (ext *ExtClient) ConvertToStaticNode() Node { CommonNode: CommonNode{ Network: ext.Network, }, + Tags: ext.Tags, IsStatic: true, StaticNode: *ext, } From f347ca11212a01d34c85709ff9bcf535dd625ea7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 14:16:05 +0400 Subject: [PATCH 072/169] user policy acl func --- logic/acls.go | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/logic/acls.go b/logic/acls.go index b300abbb6..8a6f655c4 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -323,6 +323,37 @@ func ListUserPolicies(u models.User) []models.Acl { return acls } +// listPoliciesOfUser - lists all user acl policies applied to user in an network +func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl { + data, err := database.FetchRecords(database.ACLS_TABLE_NAME) + if err != nil && !database.IsEmptyRecord(err) { + return []models.Acl{} + } + acls := []models.Acl{} + for _, dataI := range data { + acl := models.Acl{} + err := json.Unmarshal([]byte(dataI), &acl) + if err != nil { + continue + } + if acl.NetworkID == netID && acl.RuleType == models.UserPolicy { + srcMap := convAclTagToValueMap(acl.Src) + if _, ok := srcMap[user.UserName]; ok { + acls = append(acls, acl) + continue + } + for userG := range user.UserGroups { + if _, ok := srcMap[userG.String()]; ok { + acls = append(acls, acl) + continue + } + } + + } + } + return acls +} + // listUserPoliciesByNetwork - lists all acl user policies in a network func listUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { data, err := database.FetchRecords(database.ACLS_TABLE_NAME) @@ -391,8 +422,25 @@ func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { return aclValueMap } +// IsUserAllowedToCommunicate - check if user is allowed to communicate with peer func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { - listUserPoliciesByNetwork(models.NetworkID(peer.Network)) + user, err := GetUser(userName) + if err != nil { + return false + } + policies := listPoliciesOfUser(*user, models.NetworkID(peer.Network)) + for _, policy := range policies { + if !policy.Enabled { + continue + } + dstMap := convAclTagToValueMap(policy.Dst) + for tagID := range peer.Tags { + if _, ok := dstMap[tagID.String()]; ok { + return true + } + } + + } return true } From d8a0398b2a5ea270a3851ba66820b8be044789e7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 14:25:55 +0400 Subject: [PATCH 073/169] add remoteaccess tag to extclients --- migrate/migrate.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/migrate/migrate.go b/migrate/migrate.go index d7841e0f7..26bbf434d 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -171,6 +171,9 @@ func updateNodes() { if node.IsIngressGateway { tagID := models.TagID(fmt.Sprintf("%s.%s", node.Network, models.RemoteAccessTagName)) + if node.Tags == nil { + node.Tags = make(map[models.TagID]struct{}) + } if _, ok := node.Tags[tagID]; !ok { node.Tags[tagID] = struct{}{} logic.UpsertNode(&node) @@ -186,6 +189,18 @@ func updateNodes() { } } } + extclients, _ := logic.GetAllExtClients() + for _, extclient := range extclients { + tagID := models.TagID(fmt.Sprintf("%s.%s", extclient.Network, + models.RemoteAccessTagName)) + if extclient.Tags == nil { + extclient.Tags = make(map[models.TagID]struct{}) + } + if _, ok := extclient.Tags[tagID]; !ok { + extclient.Tags[tagID] = struct{}{} + logic.SaveExtClient(&extclient) + } + } } func removeInterGw(egressRanges []string) ([]string, bool) { From c37cf2b7e37d6d68463cfd9647ce61c2c055029e Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 16:53:39 +0400 Subject: [PATCH 074/169] create default user policies --- controllers/acls.go | 1 + logic/acls.go | 29 ++++++++-- logic/user_mgmt.go | 1 + migrate/migrate.go | 4 +- models/acl.go | 1 + pro/initialize.go | 1 + pro/logic/user_mgmt.go | 121 ++++++++++++++++++++++++++++++++++++++++- 7 files changed, 148 insertions(+), 10 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index b588aeed1..4fdd05175 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -44,6 +44,7 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) { }, SrcGroupTypes: []models.AclGroupType{ models.UserAclID, + models.UserRoleAclID, models.UserGroupAclID, models.DeviceAclID, }, diff --git a/logic/acls.go b/logic/acls.go index 8a6f655c4..380a618a0 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -56,6 +56,10 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { ID: models.UserGroupAclID, Value: "*", }, + { + ID: models.UserRoleAclID, + Value: "*", + }, }, Dst: []models.AclPolicyTag{{ ID: models.DeviceAclID, @@ -95,7 +99,7 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { } InsertAcl(defaultUserAcl) } - + CreateDefaultUserPolicies(netID) } // DeleteDefaultNetworkPolicies - deletes all default network acl policies @@ -169,7 +173,7 @@ func IsAclPolicyValid(acl models.Acl) bool { return false } if srcI.ID != models.UserAclID && - srcI.ID != models.UserGroupAclID { + srcI.ID != models.UserGroupAclID && srcI.ID != models.UserRoleAclID { return false } // check if user group is valid @@ -178,6 +182,15 @@ func IsAclPolicyValid(acl models.Acl) bool { if err != nil { return false } + } else if srcI.ID == models.UserRoleAclID { + if srcI.Value == "*" { + continue + } + _, err := GetRole(models.UserRoleID(srcI.Value)) + if err != nil { + return false + } + } else if srcI.ID == models.UserGroupAclID { if srcI.Value == "*" { continue @@ -281,9 +294,13 @@ func DeleteAcl(a models.Acl) error { return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) } -// GetDefaultNodesPolicy - fetches default policy in the network by ruleType -func GetDefaultNodesPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) { - acl, err := GetAcl(models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes"))) +// GetDefaultPolicy - fetches default policy in the network by ruleType +func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (models.Acl, error) { + aclID := "all-users" + if ruleType == models.DevicePolicy { + aclID = "all-nodes" + } + acl, err := GetAcl(models.AclID(fmt.Sprintf("%s.%s", netID, aclID))) if err != nil { return models.Acl{}, errors.New("default rule not found") } @@ -447,7 +464,7 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // check default policy if all allowed return true - defaultPolicy, err := GetDefaultNodesPolicy(models.NetworkID(node.Network), models.DevicePolicy) + defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) if err == nil { if defaultPolicy.Enabled { return true diff --git a/logic/user_mgmt.go b/logic/user_mgmt.go index 31cba66cd..62ba22bf7 100644 --- a/logic/user_mgmt.go +++ b/logic/user_mgmt.go @@ -53,6 +53,7 @@ var UpdateRole = func(r models.UserRolePermissionTemplate) error { return nil } var InitialiseRoles = userRolesInit var DeleteNetworkRoles = func(netID string) {} var CreateDefaultNetworkRolesAndGroups = func(netID models.NetworkID) {} +var CreateDefaultUserPolicies = func(netID models.NetworkID) {} // GetRole - fetches role template by id func GetRole(roleID models.UserRoleID) (models.UserRolePermissionTemplate, error) { diff --git a/migrate/migrate.go b/migrate/migrate.go index e940576f8..eda7a7d33 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -21,7 +21,7 @@ import ( func Run() { updateEnrollmentKeys() assignSuperAdmin() - createDefaultTags() + createDefaultTagsAndPolicies() removeOldUserGrps() syncUsers() updateHosts() @@ -459,7 +459,7 @@ func syncUsers() { } } -func createDefaultTags() { +func createDefaultTagsAndPolicies() { networks, err := logic.GetNetworks() if err != nil { return diff --git a/models/acl.go b/models/acl.go index f0bc2a6cf..1200536b1 100644 --- a/models/acl.go +++ b/models/acl.go @@ -46,6 +46,7 @@ type AclGroupType string const ( UserAclID AclGroupType = "user" UserGroupAclID AclGroupType = "user-group" + UserRoleAclID AclGroupType = "user-role" DeviceAclID AclGroupType = "tag" NetmakerIPAclID AclGroupType = "ip" NetmakerSubNetRangeAClID AclGroupType = "ipset" diff --git a/pro/initialize.go b/pro/initialize.go index 25ada539b..66a498235 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -135,6 +135,7 @@ func InitPro() { logic.IsNetworkRolesValid = proLogic.IsNetworkRolesValid logic.InitialiseRoles = proLogic.UserRolesInit logic.UpdateUserGwAccess = proLogic.UpdateUserGwAccess + logic.CreateDefaultUserPolicies = proLogic.CreateDefaultUserPolicies } func retrieveProLogo() string { diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 4bc609355..97ab8d61c 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "time" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" @@ -138,6 +139,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) d, _ = json.Marshal(NetworkUserGroup) database.Insert(NetworkUserGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) + } func DeleteNetworkRoles(netID string) { @@ -514,14 +516,25 @@ func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, n func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { gws = make(map[string]models.Node) - tagNodesMap := logic.GetTagMapWithNodes() accessPolices := logic.ListUserPolicies(user) for _, policyI := range accessPolices { for _, dstI := range policyI.Dst { + if dstI.Value == "*" { + nodes, _ := logic.GetAllNodes() + for _, node := range nodes { + if node.IsIngressGateway { + gws[node.ID.String()] = node + } + } + return + } if nodes, ok := tagNodesMap[models.TagID(dstI.Value)]; ok { for _, node := range nodes { - gws[node.ID.String()] = node + if node.IsIngressGateway { + gws[node.ID.String()] = node + } + } } } @@ -1091,3 +1104,107 @@ func UpdateUserGwAccess(currentUser, changeUser models.User) { } } + +func CreateDefaultUserPolicies(netID models.NetworkID) { + if netID.String() == "" { + return + } + if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin))) { + defaultUserAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin)), + Name: models.NetworkAdmin.String(), + Default: true, + NetworkID: netID, + RuleType: models.UserPolicy, + Src: []models.AclPolicyTag{ + { + ID: models.UserRoleAclID, + Value: fmt.Sprintf("%s-%s", netID, models.NetworkAdmin), + }}, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + logic.InsertAcl(defaultUserAcl) + } + if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser))) { + defaultUserAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser)), + Name: models.NetworkUser.String(), + Default: true, + NetworkID: netID, + RuleType: models.UserPolicy, + Src: []models.AclPolicyTag{ + { + ID: models.UserRoleAclID, + Value: fmt.Sprintf("%s-%s", netID, models.NetworkUser), + }}, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + logic.InsertAcl(defaultUserAcl) + } + + if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin))) { + defaultUserAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin)), + Name: fmt.Sprintf("%s-grp", models.NetworkAdmin), + Default: true, + NetworkID: netID, + RuleType: models.UserPolicy, + Src: []models.AclPolicyTag{ + { + ID: models.UserGroupAclID, + Value: fmt.Sprintf("%s-%s-grp", netID, models.NetworkAdmin), + }}, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + logic.InsertAcl(defaultUserAcl) + } + + if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser))) { + defaultUserAcl := models.Acl{ + ID: models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser)), + Name: fmt.Sprintf("%s-grp", models.NetworkUser), + Default: true, + NetworkID: netID, + RuleType: models.UserPolicy, + Src: []models.AclPolicyTag{ + { + ID: models.UserGroupAclID, + Value: fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser), + }}, + Dst: []models.AclPolicyTag{ + { + ID: models.DeviceAclID, + Value: "*", + }}, + AllowedDirection: models.TrafficDirectionUni, + Enabled: true, + CreatedBy: "auto", + CreatedAt: time.Now().UTC(), + } + logic.InsertAcl(defaultUserAcl) + } +} From fc2b765d8e3e0401c9029aa8a490bbfcc890da3e Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 18 Oct 2024 17:58:47 +0400 Subject: [PATCH 075/169] fix rac gws via policies --- pro/logic/user_mgmt.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 97ab8d61c..fb70987c8 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -516,18 +516,21 @@ func HasNetworkRsrcScope(permissionTemplate models.UserRolePermissionTemplate, n func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { gws = make(map[string]models.Node) + nodes, err := logic.GetAllNodes() + if err != nil { + return + } tagNodesMap := logic.GetTagMapWithNodes() accessPolices := logic.ListUserPolicies(user) for _, policyI := range accessPolices { for _, dstI := range policyI.Dst { if dstI.Value == "*" { - nodes, _ := logic.GetAllNodes() - for _, node := range nodes { + networkNodes := logic.GetNetworkNodesMemory(nodes, policyI.NetworkID.String()) + for _, node := range networkNodes { if node.IsIngressGateway { gws[node.ID.String()] = node } } - return } if nodes, ok := tagNodesMap[models.TagID(dstI.Value)]; ok { for _, node := range nodes { From 5be8939e6e0f19a88ed28c2da6351c3215659641 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 19 Oct 2024 11:57:11 +0400 Subject: [PATCH 076/169] use acl policies to fetch rac nodes --- pro/controllers/users.go | 6 +- pro/logic/user_mgmt.go | 171 --------------------------------------- 2 files changed, 3 insertions(+), 174 deletions(-) diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 5bf8fc89c..cba131a87 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -834,7 +834,7 @@ func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) { userGws := make(map[string][]models.UserRemoteGws) networks := []models.Network{} networkMap := make(map[string]struct{}) - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) for _, node := range userGwNodes { network, err := logic.GetNetwork(node.Network) if err != nil { @@ -876,7 +876,7 @@ func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request) } userGws := []models.UserRAGs{} - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) for _, node := range userGwNodes { if node.Network != network { continue @@ -931,7 +931,7 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) { return } - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) if _, ok := userGwNodes[remoteGwID]; !ok { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden")) return diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index fb70987c8..2dab445cf 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -7,7 +7,6 @@ import ( "time" "github.com/gravitl/netmaker/database" - "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/mq" @@ -544,176 +543,6 @@ func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { } return } -func DoesUserHaveAccessToRAGNode(user models.User, node models.Node) bool { - userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user) - logger.Log(3, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope)) - _, allNetAccess := userGwAccessScope["*"] - if node.IsIngressGateway && !node.PendingDelete { - if allNetAccess { - return true - } else { - gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)] - scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID] - if !ok { - if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok { - return false - } - } - if scope.VPNaccess { - return true - } - - } - } - return false -} - -func GetUserRAGNodes(user models.User) (gws map[string]models.Node) { - gws = make(map[string]models.Node) - userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user) - logger.Log(3, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope)) - _, allNetAccess := userGwAccessScope["*"] - nodes, err := logic.GetAllNodes() - if err != nil { - return - } - for _, node := range nodes { - if node.IsIngressGateway && !node.PendingDelete { - if allNetAccess { - gws[node.ID.String()] = node - } else { - gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)] - scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID] - if !ok { - if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok { - continue - } - } - if scope.VPNaccess { - gws[node.ID.String()] = node - } - - } - } - } - return -} - -// GetUserNetworkRoles - get user network roles -func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope) { - gwAccess = make(map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope) - platformRole, err := logic.GetRole(user.PlatformRoleID) - if err != nil { - return - } - if platformRole.FullAccess { - gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope) - return - } - if _, ok := user.NetworkRoles[models.AllNetworks]; ok { - gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope) - } - if len(user.UserGroups) > 0 { - for gID := range user.UserGroups { - userG, err := GetUserGroup(gID) - if err != nil { - continue - } - for netID, roleMap := range userG.NetworkRoles { - for roleID := range roleMap { - role, err := logic.GetRole(roleID) - if err == nil { - if role.FullAccess { - gwAccess[netID] = map[models.RsrcID]models.RsrcPermissionScope{ - models.AllRemoteAccessGwRsrcID: { - Create: true, - Read: true, - Update: true, - VPNaccess: true, - Delete: true, - }, - models.AllExtClientsRsrcID: { - Create: true, - Read: true, - Update: true, - Delete: true, - }, - } - break - } - if rsrcsMap, ok := role.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok { - if permissions, ok := rsrcsMap[models.AllRemoteAccessGwRsrcID]; ok && permissions.VPNaccess { - if len(gwAccess[netID]) == 0 { - gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) - } - gwAccess[netID][models.AllRemoteAccessGwRsrcID] = permissions - break - } else { - for gwID, scope := range rsrcsMap { - if scope.VPNaccess { - if len(gwAccess[netID]) == 0 { - gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) - } - gwAccess[netID][gwID] = scope - } - } - } - - } - - } - } - } - } - } - for netID, roleMap := range user.NetworkRoles { - for roleID := range roleMap { - role, err := logic.GetRole(roleID) - if err == nil { - if role.FullAccess { - gwAccess[netID] = map[models.RsrcID]models.RsrcPermissionScope{ - models.AllRemoteAccessGwRsrcID: { - Create: true, - Read: true, - Update: true, - VPNaccess: true, - Delete: true, - }, - models.AllExtClientsRsrcID: { - Create: true, - Read: true, - Update: true, - Delete: true, - }, - } - break - } - if rsrcsMap, ok := role.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok { - if permissions, ok := rsrcsMap[models.AllRemoteAccessGwRsrcID]; ok && permissions.VPNaccess { - if len(gwAccess[netID]) == 0 { - gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) - } - gwAccess[netID][models.AllRemoteAccessGwRsrcID] = permissions - break - } else { - for gwID, scope := range rsrcsMap { - if scope.VPNaccess { - if len(gwAccess[netID]) == 0 { - gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) - } - gwAccess[netID][gwID] = scope - } - } - } - - } - - } - } - } - - return -} func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filteredNodes []models.Node) { From 57378d255aab4cced2b8627e2d6aa2d06b4374ab Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 19 Oct 2024 13:16:52 +0400 Subject: [PATCH 077/169] fix user policies --- logic/acls.go | 20 ++++++++++++-------- pro/logic/user_mgmt.go | 11 ++++++----- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 380a618a0..84fdd8d41 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -172,6 +172,9 @@ func IsAclPolicyValid(acl models.Acl) bool { if srcI.ID == "" || srcI.Value == "" { return false } + if srcI.Value == "*" { + continue + } if srcI.ID != models.UserAclID && srcI.ID != models.UserGroupAclID && srcI.ID != models.UserRoleAclID { return false @@ -183,18 +186,13 @@ func IsAclPolicyValid(acl models.Acl) bool { return false } } else if srcI.ID == models.UserRoleAclID { - if srcI.Value == "*" { - continue - } + _, err := GetRole(models.UserRoleID(srcI.Value)) if err != nil { return false } } else if srcI.ID == models.UserGroupAclID { - if srcI.Value == "*" { - continue - } err := IsGroupValid(models.UserGroupID(srcI.Value)) if err != nil { return false @@ -208,7 +206,7 @@ func IsAclPolicyValid(acl models.Acl) bool { return false } if dstI.ID == models.UserAclID || - dstI.ID == models.UserGroupAclID { + dstI.ID == models.UserGroupAclID || dstI.ID == models.UserRoleAclID { return false } if dstI.ID != models.DeviceAclID { @@ -359,6 +357,12 @@ func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl { acls = append(acls, acl) continue } + for netRole := range user.NetworkRoles { + if _, ok := srcMap[netRole.String()]; ok { + acls = append(acls, acl) + continue + } + } for userG := range user.UserGroups { if _, ok := srcMap[userG.String()]; ok { acls = append(acls, acl) @@ -458,7 +462,7 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { } } - return true + return false } // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 2dab445cf..5b338d163 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -956,8 +956,9 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: "*", - }}, + Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + }, + }, AllowedDirection: models.TrafficDirectionUni, Enabled: true, CreatedBy: "auto", @@ -980,7 +981,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: "*", + Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), }}, AllowedDirection: models.TrafficDirectionUni, Enabled: true, @@ -1005,7 +1006,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: "*", + Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), }}, AllowedDirection: models.TrafficDirectionUni, Enabled: true, @@ -1030,7 +1031,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: "*", + Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), }}, AllowedDirection: models.TrafficDirectionUni, Enabled: true, From 6b93163bd5140cf399d10496aae2cb2ac452f9f8 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sat, 19 Oct 2024 13:50:54 +0400 Subject: [PATCH 078/169] fix user policy acls --- controllers/ext_client.go | 4 +++- logic/acls.go | 6 +----- pro/controllers/users.go | 3 +++ pro/logic/user_mgmt.go | 8 ++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/controllers/ext_client.go b/controllers/ext_client.go index 09c5f5d52..3f1f9323b 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -452,7 +452,9 @@ func createExtClient(w http.ResponseWriter, r *http.Request) { extclient.OwnerID = userName extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID extclient.IngressGatewayID = nodeid - + extclient.Tags = make(map[models.TagID]struct{}) + extclient.Tags[models.TagID(fmt.Sprintf("%s.%s", extclient.Network, + models.RemoteAccessTagName))] = struct{}{} // set extclient dns to ingressdns if extclient dns is not explicitly set if (extclient.DNS == "") && (node.IngressDNS != "") { extclient.DNS = node.IngressDNS diff --git a/logic/acls.go b/logic/acls.go index 84fdd8d41..6a8d85761 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -83,7 +83,7 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { Src: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), }, }, Dst: []models.AclPolicyTag{ @@ -205,10 +205,6 @@ func IsAclPolicyValid(acl models.Acl) bool { if dstI.ID == "" || dstI.Value == "" { return false } - if dstI.ID == models.UserAclID || - dstI.ID == models.UserGroupAclID || dstI.ID == models.UserRoleAclID { - return false - } if dstI.ID != models.DeviceAclID { return false } diff --git a/pro/controllers/users.go b/pro/controllers/users.go index cba131a87..1202a953d 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -995,6 +995,9 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) { if err == nil { // check if parent network default ACL is enabled (yes) or not (no) userConf.Enabled = parentNetwork.DefaultACL == "yes" } + userConf.Tags = make(map[models.TagID]struct{}) + userConf.Tags[models.TagID(fmt.Sprintf("%s.%s", userConf.Network, + models.RemoteAccessTagName))] = struct{}{} if err = logic.CreateExtClient(&userConf); err != nil { slog.Error( "failed to create extclient", diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 5b338d163..4b1642b30 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -956,7 +956,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), }, }, AllowedDirection: models.TrafficDirectionUni, @@ -981,7 +981,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), }}, AllowedDirection: models.TrafficDirectionUni, Enabled: true, @@ -1006,7 +1006,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), }}, AllowedDirection: models.TrafficDirectionUni, Enabled: true, @@ -1031,7 +1031,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, "remote-access-gws"), + Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), }}, AllowedDirection: models.TrafficDirectionUni, Enabled: true, From 7fa65801039b63676ca8534b07a1ab8cd729f3a7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 21 Oct 2024 12:35:10 +0400 Subject: [PATCH 079/169] add ingress rules to peer update --- logic/extpeers.go | 17 +++++++++++++---- logic/peers.go | 11 ++++++++--- models/mqtt.go | 8 ++++---- pro/logic/failover.go | 2 +- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index e37b2be58..5f9d0f161 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -396,20 +396,29 @@ func ToggleExtClientConnectivity(client *models.ExtClient, enable bool) (models. return newClient, nil } -func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) { +func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, []net.IP, error) { var peers []wgtypes.PeerConfig var idsAndAddr []models.IDandAddr var egressRoutes []models.EgressNetworkRoutes + var extUserIps []net.IP extPeers, err := GetNetworkExtClients(node.Network) if err != nil { - return peers, idsAndAddr, egressRoutes, err + return peers, idsAndAddr, egressRoutes, extUserIps, err } host, err := GetHost(node.HostID.String()) if err != nil { - return peers, idsAndAddr, egressRoutes, err + return peers, idsAndAddr, egressRoutes, extUserIps, err } for _, extPeer := range extPeers { extPeer := extPeer + if extPeer.RemoteAccessClientID != "" { + if extPeer.AddressIPNet4().IP != nil { + extUserIps = append(extUserIps, extPeer.AddressIPNet4().IP) + } + if extPeer.AddressIPNet6().IP != nil { + extUserIps = append(extUserIps, extPeer.AddressIPNet6().IP) + } + } if !IsClientNodeAllowed(&extPeer, peer.ID.String()) { continue } @@ -479,7 +488,7 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA IsExtClient: true, }) } - return peers, idsAndAddr, egressRoutes, nil + return peers, idsAndAddr, egressRoutes, extUserIps, nil } diff --git a/logic/peers.go b/logic/peers.go index b2456826d..1ca771843 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -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{}, @@ -287,9 +288,13 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N var extPeers []wgtypes.PeerConfig var extPeerIDAndAddrs []models.IDandAddr var egressRoutes []models.EgressNetworkRoutes + var extUserIps []net.IP if node.IsIngressGateway { - extPeers, extPeerIDAndAddrs, egressRoutes, err = GetExtPeers(&node, &node) + extPeers, extPeerIDAndAddrs, egressRoutes, extUserIps, err = GetExtPeers(&node, &node) if err == nil { + hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ + UserIps: extUserIps, + } hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...) hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...) for _, extPeerIdAndAddr := range extPeerIDAndAddrs { @@ -421,7 +426,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet // handle ingress gateway peers if peer.IsIngressGateway { - extPeers, _, _, err := GetExtPeers(peer, node) + extPeers, _, _, _, err := GetExtPeers(peer, node) if err != nil { logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error()) } diff --git a/models/mqtt.go b/models/mqtt.go index c0d52d9c2..3463afe83 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -28,8 +28,7 @@ type HostPeerUpdate struct { // 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"` + UserIps []net.IP } // EgressInfo - struct for egress info @@ -77,8 +76,9 @@ 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"` + EgressInfo map[string]EgressInfo `json:"egress_info"` + IngressInfo map[string]IngressInfo `json:"ingress_info"` } // FailOverMeReq - struct for failover req diff --git a/pro/logic/failover.go b/pro/logic/failover.go index 788e09e0b..f90173e59 100644 --- a/pro/logic/failover.go +++ b/pro/logic/failover.go @@ -148,7 +148,7 @@ func GetFailOverPeerIps(peer, node *models.Node) []net.IPNet { } // handle ingress gateway peers if failOverpeer.IsIngressGateway { - extPeers, _, _, err := logic.GetExtPeers(&failOverpeer, node) + extPeers, _, _, _, err := logic.GetExtPeers(&failOverpeer, node) if err != nil { logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error()) } From cd2d026fc85feafb5ab421444f80c4dfbda50fe0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 21 Oct 2024 12:52:02 +0400 Subject: [PATCH 080/169] add ingress id to model --- logic/peers.go | 3 ++- models/mqtt.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 1ca771843..c65861eab 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -293,7 +293,8 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N extPeers, extPeerIDAndAddrs, egressRoutes, extUserIps, err = GetExtPeers(&node, &node) if err == nil { hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ - UserIps: extUserIps, + IngressID: node.ID.String(), + UserIps: extUserIps, } hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...) hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...) diff --git a/models/mqtt.go b/models/mqtt.go index 3463afe83..504c9859c 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -28,7 +28,8 @@ type HostPeerUpdate struct { // IngressInfo - struct for ingress info type IngressInfo struct { - UserIps []net.IP + IngressID string `json:"ingress_id"` + UserIps []net.IP `json:"user_ips"` } // EgressInfo - struct for egress info From 04c2039beb6ffa0af2027c9f23d28c3c9c4a23d7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 21 Oct 2024 14:58:40 +0400 Subject: [PATCH 081/169] add ingress gw status to peer update --- logic/peers.go | 1 + models/mqtt.go | 1 + 2 files changed, 2 insertions(+) diff --git a/logic/peers.go b/logic/peers.go index c65861eab..babd26b95 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -290,6 +290,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N var egressRoutes []models.EgressNetworkRoutes var extUserIps []net.IP if node.IsIngressGateway { + hostPeerUpdate.FwUpdate.IsIngressGw = true extPeers, extPeerIDAndAddrs, egressRoutes, extUserIps, err = GetExtPeers(&node, &node) if err == nil { hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ diff --git a/models/mqtt.go b/models/mqtt.go index 504c9859c..89ed8d3a8 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -78,6 +78,7 @@ type KeyUpdate struct { // FwUpdate - struct for firewall updates type FwUpdate struct { 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"` } From 3994183fe890d7427250ba397701faf92858933b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 21 Oct 2024 16:49:30 +0400 Subject: [PATCH 082/169] implement extclient to extclient acls --- logic/acls.go | 6 ++++ logic/extpeers.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++- logic/nodes.go | 2 +- logic/peers.go | 1 + models/mqtt.go | 7 +++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 6a8d85761..9ab8ed190 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -470,6 +470,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 { diff --git a/logic/extpeers.go b/logic/extpeers.go index 5f9d0f161..27d4d8fb7 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -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,50 @@ func ToggleExtClientConnectivity(client *models.ExtClient, enable bool) (models. return newClient, nil } +func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { + // fetch user access to static clients via policies + extclients := GetStaticNodesByNetwork(models.NetworkID(node.Network), true) + userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network)) + for _, userNodeI := range userNodes { + for _, extclient := range extclients { + if IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, extclient) { + if userNodeI.StaticNode.Address != "" { + rules = append(rules, models.FwRule{ + SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, + DstIP: extclient.StaticNode.AddressIPNet4().IP, + }) + } + if userNodeI.StaticNode.Address6 != "" { + rules = append(rules, models.FwRule{ + SrcIp: userNodeI.StaticNode.AddressIPNet6().IP, + DstIP: extclient.StaticNode.AddressIPNet6().IP, + }) + } + } + } + } + + for _, extclientI := range extclients { + for _, extclient := range extclients { + if IsNodeAllowedToCommunicate(extclientI, extclient) { + if extclientI.StaticNode.Address != "" { + rules = append(rules, models.FwRule{ + SrcIp: extclientI.StaticNode.AddressIPNet4().IP, + DstIP: extclient.StaticNode.AddressIPNet4().IP, + }) + } + if extclientI.StaticNode.Address6 != "" { + rules = append(rules, models.FwRule{ + SrcIp: extclientI.StaticNode.AddressIPNet6().IP, + DstIP: extclient.StaticNode.AddressIPNet6().IP, + }) + } + } + } + } + return +} + func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, []net.IP, error) { var peers []wgtypes.PeerConfig var idsAndAddr []models.IDandAddr @@ -512,6 +562,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 @@ -549,13 +602,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, diff --git a/logic/nodes.go b/logic/nodes.go index abc2f4acb..036abcca2 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -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{}{} } } diff --git a/logic/peers.go b/logic/peers.go index babd26b95..485ba3d61 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -296,6 +296,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ IngressID: node.ID.String(), UserIps: extUserIps, + Rules: GetFwRulesOnIngressGateway(node), } hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...) hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...) diff --git a/models/mqtt.go b/models/mqtt.go index 89ed8d3a8..028be4752 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -26,10 +26,17 @@ 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 { IngressID string `json:"ingress_id"` UserIps []net.IP `json:"user_ips"` + Rules []FwRule `json:"rules"` } // EgressInfo - struct for egress info From 1c9b986f0e7ebce04f16b7fb9c0ee7704206cc42 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 21 Oct 2024 19:48:13 +0400 Subject: [PATCH 083/169] add static node ips in the ingress update --- logic/extpeers.go | 15 +++++++++++++++ logic/peers.go | 7 ++++--- models/mqtt.go | 7 ++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 27d4d8fb7..f13fcec41 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -402,6 +402,19 @@ 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 extclients := GetStaticNodesByNetwork(models.NetworkID(node.Network), true) @@ -413,12 +426,14 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { rules = append(rules, models.FwRule{ SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, DstIP: extclient.StaticNode.AddressIPNet4().IP, + Allow: true, }) } if userNodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ SrcIp: userNodeI.StaticNode.AddressIPNet6().IP, DstIP: extclient.StaticNode.AddressIPNet6().IP, + Allow: true, }) } } diff --git a/logic/peers.go b/logic/peers.go index 485ba3d61..4456fbc18 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -294,9 +294,10 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N extPeers, extPeerIDAndAddrs, egressRoutes, extUserIps, err = GetExtPeers(&node, &node) if err == nil { hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ - IngressID: node.ID.String(), - UserIps: extUserIps, - Rules: GetFwRulesOnIngressGateway(node), + IngressID: node.ID.String(), + UserIps: extUserIps, + Rules: GetFwRulesOnIngressGateway(node), + StaticNodeIps: GetStaticNodeIps(node), } hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...) hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...) diff --git a/models/mqtt.go b/models/mqtt.go index 028be4752..2d978708b 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -34,9 +34,10 @@ type FwRule struct { // IngressInfo - struct for ingress info type IngressInfo struct { - IngressID string `json:"ingress_id"` - UserIps []net.IP `json:"user_ips"` - Rules []FwRule `json:"rules"` + IngressID string `json:"ingress_id"` + UserIps []net.IP `json:"user_ips"` + StaticNodeIps []net.IP `json:"static_node_ips"` + Rules []FwRule `json:"rules"` } // EgressInfo - struct for egress info From 148c1fdc8fe3ab7f699da2f932cbf42f7c639e58 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 22 Oct 2024 15:12:05 +0400 Subject: [PATCH 084/169] return all gws for admins --- pro/logic/user_mgmt.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 4b1642b30..2af61f90e 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -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 { From 6c52b68214d1f1cd0739154910540a082a7f15b7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 22 Oct 2024 19:54:23 +0400 Subject: [PATCH 085/169] fix ingress firewall updates --- controllers/ext_client.go | 3 +-- logic/acls.go | 3 +++ logic/extpeers.go | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/controllers/ext_client.go b/controllers/ext_client.go index 3f1f9323b..cc8bfadab 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -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"), diff --git a/logic/acls.go b/logic/acls.go index 9ab8ed190..1eaa16b41 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -445,6 +445,9 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { 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 { diff --git a/logic/extpeers.go b/logic/extpeers.go index f13fcec41..62c723d2f 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -428,6 +428,11 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { DstIP: extclient.StaticNode.AddressIPNet4().IP, Allow: true, }) + rules = append(rules, models.FwRule{ + SrcIp: extclient.StaticNode.AddressIPNet4().IP, + DstIP: userNodeI.StaticNode.AddressIPNet4().IP, + Allow: true, + }) } if userNodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ @@ -435,6 +440,11 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { DstIP: extclient.StaticNode.AddressIPNet6().IP, Allow: true, }) + rules = append(rules, models.FwRule{ + SrcIp: extclient.StaticNode.AddressIPNet6().IP, + DstIP: userNodeI.StaticNode.AddressIPNet6().IP, + Allow: true, + }) } } } @@ -442,17 +452,22 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { for _, extclientI := range extclients { for _, extclient := range extclients { + if extclient.StaticNode.ClientID == extclientI.StaticNode.ClientID { + continue + } if IsNodeAllowedToCommunicate(extclientI, extclient) { if extclientI.StaticNode.Address != "" { rules = append(rules, models.FwRule{ SrcIp: extclientI.StaticNode.AddressIPNet4().IP, DstIP: extclient.StaticNode.AddressIPNet4().IP, + Allow: true, }) } if extclientI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ SrcIp: extclientI.StaticNode.AddressIPNet6().IP, DstIP: extclient.StaticNode.AddressIPNet6().IP, + Allow: true, }) } } From dc7e262602307feddddaace59d4d9d2c13311ef3 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 07:48:32 +0400 Subject: [PATCH 086/169] add network info to ingress model --- logic/peers.go | 2 ++ models/mqtt.go | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 4456fbc18..af72dcf87 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -296,6 +296,8 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ IngressID: node.ID.String(), UserIps: extUserIps, + Network: node.NetworkRange, + Network6: node.NetworkRange6, Rules: GetFwRulesOnIngressGateway(node), StaticNodeIps: GetStaticNodeIps(node), } diff --git a/models/mqtt.go b/models/mqtt.go index 2d978708b..a27c36ecc 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -34,10 +34,12 @@ type FwRule struct { // IngressInfo - struct for ingress info type IngressInfo struct { - IngressID string `json:"ingress_id"` - UserIps []net.IP `json:"user_ips"` - StaticNodeIps []net.IP `json:"static_node_ips"` - Rules []FwRule `json:"rules"` + IngressID string `json:"ingress_id"` + Network net.IPNet `json:"network"` + Network6 net.IPNet `json:"network6"` + UserIps []net.IP `json:"user_ips"` + StaticNodeIps []net.IP `json:"static_node_ips"` + Rules []FwRule `json:"rules"` } // EgressInfo - struct for egress info From ffb75fa6c141ea9c94ecfb362ae0ed02f36d37b5 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 13:19:16 +0400 Subject: [PATCH 087/169] add allow rules for nodes --- logic/acls.go | 3 ++ logic/extpeers.go | 103 +++++++++++++++++++++++++++++++++------------- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 1eaa16b41..a17ea02d3 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -449,6 +449,9 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { peer = peer.StaticNode.ConvertToStaticNode() } policies := listPoliciesOfUser(*user, models.NetworkID(peer.Network)) + if userName == "abhi-rac" { + fmt.Printf("=====> POLICIES: %+v\n", policies) + } for _, policy := range policies { if !policy.Enabled { continue diff --git a/logic/extpeers.go b/logic/extpeers.go index 62c723d2f..83c604fed 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -417,42 +417,77 @@ func GetStaticNodeIps(node models.Node) (ips []net.IP) { func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { // fetch user access to static clients via policies - extclients := GetStaticNodesByNetwork(models.NetworkID(node.Network), true) + nodes, _ := GetNetworkNodes(node.Network) + nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...) userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network)) for _, userNodeI := range userNodes { - for _, extclient := range extclients { - if IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, extclient) { - if userNodeI.StaticNode.Address != "" { - rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, - DstIP: extclient.StaticNode.AddressIPNet4().IP, - Allow: true, - }) - rules = append(rules, models.FwRule{ - SrcIp: extclient.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: extclient.StaticNode.AddressIPNet6().IP, - Allow: true, - }) - rules = append(rules, models.FwRule{ - SrcIp: extclient.StaticNode.AddressIPNet6().IP, - DstIP: userNodeI.StaticNode.AddressIPNet6().IP, - Allow: true, - }) + 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, + }) + // rules = append(rules, models.FwRule{ + // SrcIp: peer.Address.IP, + // DstIP: userNodeI.StaticNode.AddressIPNet4().IP, + // Allow: true, + // }) + } + if userNodeI.StaticNode.Address6 != "" { + rules = append(rules, models.FwRule{ + SrcIp: userNodeI.StaticNode.AddressIPNet6().IP, + DstIP: peer.Address6.IP, + Allow: true, + }) + // rules = append(rules, models.FwRule{ + // SrcIp: peer.Address6.IP, + // DstIP: userNodeI.StaticNode.AddressIPNet6().IP, + // Allow: true, + // }) + } } + } } } - for _, extclientI := range extclients { - for _, extclient := range extclients { - if extclient.StaticNode.ClientID == extclientI.StaticNode.ClientID { + for _, extclientI := range nodes { + if !extclientI.IsStatic || extclientI.IsUserNode { + continue + } + for _, extclient := range nodes { + if extclient.StaticNode.ClientID == extclientI.StaticNode.ClientID || extclient.IsUserNode { continue } if IsNodeAllowedToCommunicate(extclientI, extclient) { @@ -462,6 +497,11 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { DstIP: extclient.StaticNode.AddressIPNet4().IP, Allow: true, }) + // rules = append(rules, models.FwRule{ + // SrcIp: extclient.StaticNode.AddressIPNet4().IP, + // DstIP: extclientI.StaticNode.AddressIPNet4().IP, + // Allow: true, + // }) } if extclientI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ @@ -469,6 +509,11 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { DstIP: extclient.StaticNode.AddressIPNet6().IP, Allow: true, }) + // rules = append(rules, models.FwRule{ + // SrcIp: extclient.StaticNode.AddressIPNet6().IP, + // DstIP: extclientI.StaticNode.AddressIPNet6().IP, + // Allow: true, + // }) } } } From c0f107b302ea008ad3f501a7ec253c1c6b4f12f9 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 14:15:13 +0400 Subject: [PATCH 088/169] remove userips usage, add allow all to fwupdate --- logic/acls.go | 3 +++ logic/extpeers.go | 9 +++++---- logic/peers.go | 24 ++++++++++++++---------- models/mqtt.go | 2 +- pro/logic/failover.go | 2 +- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index a17ea02d3..fb7e34e95 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -457,6 +457,9 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { continue } dstMap := convAclTagToValueMap(policy.Dst) + if _, ok := dstMap["*"]; ok { + return true + } for tagID := range peer.Tags { if _, ok := dstMap[tagID.String()]; ok { return true diff --git a/logic/extpeers.go b/logic/extpeers.go index 83c604fed..c1ada3b4e 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -417,6 +417,7 @@ func GetStaticNodeIps(node models.Node) (ips []net.IP) { 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)) @@ -521,18 +522,18 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { return } -func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, []net.IP, error) { +func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) { var peers []wgtypes.PeerConfig var idsAndAddr []models.IDandAddr var egressRoutes []models.EgressNetworkRoutes var extUserIps []net.IP extPeers, err := GetNetworkExtClients(node.Network) if err != nil { - return peers, idsAndAddr, egressRoutes, extUserIps, err + return peers, idsAndAddr, egressRoutes, err } host, err := GetHost(node.HostID.String()) if err != nil { - return peers, idsAndAddr, egressRoutes, extUserIps, err + return peers, idsAndAddr, egressRoutes, err } for _, extPeer := range extPeers { extPeer := extPeer @@ -613,7 +614,7 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA IsExtClient: true, }) } - return peers, idsAndAddr, egressRoutes, extUserIps, nil + return peers, idsAndAddr, egressRoutes, nil } diff --git a/logic/peers.go b/logic/peers.go index af72dcf87..fce82f9be 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -288,19 +288,23 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N var extPeers []wgtypes.PeerConfig var extPeerIDAndAddrs []models.IDandAddr var egressRoutes []models.EgressNetworkRoutes - var extUserIps []net.IP if node.IsIngressGateway { hostPeerUpdate.FwUpdate.IsIngressGw = true - extPeers, extPeerIDAndAddrs, egressRoutes, extUserIps, err = GetExtPeers(&node, &node) + extPeers, extPeerIDAndAddrs, egressRoutes, err = GetExtPeers(&node, &node) if err == nil { - hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = models.IngressInfo{ - IngressID: node.ID.String(), - UserIps: extUserIps, - Network: node.NetworkRange, - Network6: node.NetworkRange6, - Rules: GetFwRulesOnIngressGateway(node), - StaticNodeIps: GetStaticNodeIps(node), + defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) + defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) + ingFwUpdate := models.IngressInfo{ + IngressID: node.ID.String(), + Network: node.NetworkRange, + Network6: node.NetworkRange6, + AllowAll: defaultDevicePolicy.Enabled && defaultUserPolicy.Default, } + if !ingFwUpdate.AllowAll { + ingFwUpdate.StaticNodeIps = GetStaticNodeIps(node) + ingFwUpdate.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 { @@ -432,7 +436,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet // handle ingress gateway peers if peer.IsIngressGateway { - extPeers, _, _, _, err := GetExtPeers(peer, node) + extPeers, _, _, err := GetExtPeers(peer, node) if err != nil { logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error()) } diff --git a/models/mqtt.go b/models/mqtt.go index a27c36ecc..3ff6043f7 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -37,9 +37,9 @@ type IngressInfo struct { IngressID string `json:"ingress_id"` Network net.IPNet `json:"network"` Network6 net.IPNet `json:"network6"` - UserIps []net.IP `json:"user_ips"` StaticNodeIps []net.IP `json:"static_node_ips"` Rules []FwRule `json:"rules"` + AllowAll bool `json:"allow_all"` } // EgressInfo - struct for egress info diff --git a/pro/logic/failover.go b/pro/logic/failover.go index f90173e59..788e09e0b 100644 --- a/pro/logic/failover.go +++ b/pro/logic/failover.go @@ -148,7 +148,7 @@ func GetFailOverPeerIps(peer, node *models.Node) []net.IPNet { } // handle ingress gateway peers if failOverpeer.IsIngressGateway { - extPeers, _, _, _, err := logic.GetExtPeers(&failOverpeer, node) + extPeers, _, _, err := logic.GetExtPeers(&failOverpeer, node) if err != nil { logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error()) } From d4da1774fff3fee418f5f160907b47f3f78860f0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 15:29:47 +0400 Subject: [PATCH 089/169] check default user policy --- logic/acls.go | 4 ++++ logic/extpeers.go | 9 --------- logic/peers.go | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index fb7e34e95..91d23b492 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -441,6 +441,10 @@ 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 diff --git a/logic/extpeers.go b/logic/extpeers.go index c1ada3b4e..3a836defe 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -526,7 +526,6 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA var peers []wgtypes.PeerConfig var idsAndAddr []models.IDandAddr var egressRoutes []models.EgressNetworkRoutes - var extUserIps []net.IP extPeers, err := GetNetworkExtClients(node.Network) if err != nil { return peers, idsAndAddr, egressRoutes, err @@ -537,14 +536,6 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA } for _, extPeer := range extPeers { extPeer := extPeer - if extPeer.RemoteAccessClientID != "" { - if extPeer.AddressIPNet4().IP != nil { - extUserIps = append(extUserIps, extPeer.AddressIPNet4().IP) - } - if extPeer.AddressIPNet6().IP != nil { - extUserIps = append(extUserIps, extPeer.AddressIPNet6().IP) - } - } if !IsClientNodeAllowed(&extPeer, peer.ID.String()) { continue } diff --git a/logic/peers.go b/logic/peers.go index fce82f9be..ca7154ecf 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -294,17 +294,17 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N if err == nil { defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) - ingFwUpdate := models.IngressInfo{ - IngressID: node.ID.String(), - Network: node.NetworkRange, - Network6: node.NetworkRange6, - AllowAll: defaultDevicePolicy.Enabled && defaultUserPolicy.Default, - } - if !ingFwUpdate.AllowAll { - ingFwUpdate.StaticNodeIps = GetStaticNodeIps(node) - ingFwUpdate.Rules = GetFwRulesOnIngressGateway(node) + 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.FwUpdate.IngressInfo[node.ID.String()] = ingFwUpdate hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...) hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...) for _, extPeerIdAndAddr := range extPeerIDAndAddrs { From 541bec71dea97d27f82c389efa4e0e59f715db97 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 15:55:04 +0400 Subject: [PATCH 090/169] fix default policy check --- logic/acls.go | 3 --- logic/peers.go | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 91d23b492..692c00d2b 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -453,9 +453,6 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { peer = peer.StaticNode.ConvertToStaticNode() } policies := listPoliciesOfUser(*user, models.NetworkID(peer.Network)) - if userName == "abhi-rac" { - fmt.Printf("=====> POLICIES: %+v\n", policies) - } for _, policy := range policies { if !policy.Enabled { continue diff --git a/logic/peers.go b/logic/peers.go index ca7154ecf..3589f005a 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -294,7 +294,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N if err == nil { defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) - if defaultDevicePolicy.Enabled && defaultUserPolicy.Enabled { + if !defaultDevicePolicy.Enabled || !defaultUserPolicy.Enabled { ingFwUpdate := models.IngressInfo{ IngressID: node.ID.String(), Network: node.NetworkRange, From f51f655f00aa19aa0a35742ccd2e8cbe29cbfc9b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 22:30:36 +0400 Subject: [PATCH 091/169] send peer updates on user updates and ingress gw --- controllers/node.go | 2 ++ controllers/user.go | 3 ++ logic/extpeers.go | 74 ++++++++++++++++++++++----------------------- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/controllers/node.go b/controllers/node.go index ab28ba96d..9a40680ea 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -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", diff --git a/controllers/user.go b/controllers/user.go index c48a1b1da..8f3375cc8 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -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() } diff --git a/logic/extpeers.go b/logic/extpeers.go index 3a836defe..53028c259 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -459,11 +459,6 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { DstIP: peer.Address.IP, Allow: true, }) - // rules = append(rules, models.FwRule{ - // SrcIp: peer.Address.IP, - // DstIP: userNodeI.StaticNode.AddressIPNet4().IP, - // Allow: true, - // }) } if userNodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ @@ -471,11 +466,6 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { DstIP: peer.Address6.IP, Allow: true, }) - // rules = append(rules, models.FwRule{ - // SrcIp: peer.Address6.IP, - // DstIP: userNodeI.StaticNode.AddressIPNet6().IP, - // Allow: true, - // }) } } @@ -483,39 +473,47 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { } } - for _, extclientI := range nodes { - if !extclientI.IsStatic || extclientI.IsUserNode { + for _, nodeI := range nodes { + if !nodeI.IsStatic || nodeI.IsUserNode { continue } - for _, extclient := range nodes { - if extclient.StaticNode.ClientID == extclientI.StaticNode.ClientID || extclient.IsUserNode { + for _, peer := range nodes { + if peer.StaticNode.ClientID == nodeI.StaticNode.ClientID || peer.IsUserNode { continue } - if IsNodeAllowedToCommunicate(extclientI, extclient) { - if extclientI.StaticNode.Address != "" { - rules = append(rules, models.FwRule{ - SrcIp: extclientI.StaticNode.AddressIPNet4().IP, - DstIP: extclient.StaticNode.AddressIPNet4().IP, - Allow: true, - }) - // rules = append(rules, models.FwRule{ - // SrcIp: extclient.StaticNode.AddressIPNet4().IP, - // DstIP: extclientI.StaticNode.AddressIPNet4().IP, - // Allow: true, - // }) - } - if extclientI.StaticNode.Address6 != "" { - rules = append(rules, models.FwRule{ - SrcIp: extclientI.StaticNode.AddressIPNet6().IP, - DstIP: extclient.StaticNode.AddressIPNet6().IP, - Allow: true, - }) - // rules = append(rules, models.FwRule{ - // SrcIp: extclient.StaticNode.AddressIPNet6().IP, - // DstIP: extclientI.StaticNode.AddressIPNet6().IP, - // Allow: true, - // }) + 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, + }) + } } + } } } From 0c882db508d11e18060a210bceaff16bbbff65f6 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 23 Oct 2024 22:31:16 +0400 Subject: [PATCH 092/169] send peer updates on user updates and ingress gw --- controllers/node.go | 1 + 1 file changed, 1 insertion(+) diff --git a/controllers/node.go b/controllers/node.go index 9a40680ea..d7f2e2569 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -751,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() } From 636b2ff1a779dce7fda90add317c4d6faadd42be Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 24 Oct 2024 12:47:53 +0400 Subject: [PATCH 093/169] create enrollment key on network creation --- logic/networks.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/logic/networks.go b/logic/networks.go index 14ad794e5..0cee5603c 100644 --- a/logic/networks.go +++ b/logic/networks.go @@ -8,9 +8,11 @@ import ( "sort" "strings" "sync" + "time" "github.com/c-robinson/iplib" validator "github.com/go-playground/validator/v10" + "github.com/google/uuid" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic/acls/nodeacls" @@ -233,6 +235,15 @@ func CreateNetwork(network models.Network) (models.Network, error) { storeNetworkInCache(network.NetID, network) } + _, _ = CreateEnrollmentKey( + 0, + time.Time{}, + []string{network.NetID}, + []string{network.NetID}, + true, + uuid.Nil, + ) + return network, nil } From 60ea2a76a6ae15362f44fcade51d03eb3648b11b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 24 Oct 2024 13:11:53 +0400 Subject: [PATCH 094/169] create enrollementkey for existing networks --- migrate/migrate.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/migrate/migrate.go b/migrate/migrate.go index 6612d4ddc..fb051f873 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -8,6 +8,7 @@ import ( "golang.org/x/exp/slog" + "github.com/google/uuid" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" @@ -122,6 +123,33 @@ func updateEnrollmentKeys() { } } + + existingKeys, err := logic.GetAllEnrollmentKeys() + if err != nil { + return + } + // check if any tags are duplicate + existingTags := make(map[string]struct{}) + for _, existingKey := range existingKeys { + for _, t := range existingKey.Tags { + existingTags[t] = struct{}{} + } + } + networks, _ := logic.GetNetworks() + for _, network := range networks { + if _, ok := existingTags[network.NetID]; ok { + continue + } + _, _ = logic.CreateEnrollmentKey( + 0, + time.Time{}, + []string{network.NetID}, + []string{network.NetID}, + true, + uuid.Nil, + ) + + } } func removeOldUserGrps() { From 470e9ddfe7bbedc0c12186eafc81035d93cb162a Mon Sep 17 00:00:00 2001 From: Vishal Dalwadi <51291657+VishalDalwadi@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:22:55 +0530 Subject: [PATCH 095/169] feat(go): update email template. (#3150) * feat(go): update email template. * feat(go): update email template. * feat(go): update email template. * feat(go): update email template. * feat(go): update email template. * feat(go): update email template. * feat(go): update email template. --- pro/controllers/users.go | 5 +- pro/email/invite.go | 83 +++-- pro/email/utils.go | 650 ++++++++------------------------------- 3 files changed, 171 insertions(+), 567 deletions(-) diff --git a/pro/controllers/users.go b/pro/controllers/users.go index d5ea4ddb0..87d69e4cd 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -250,8 +250,9 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) { // Set E-Mail body. You can set plain text or html with text/html e := email.UserInvitedMail{ - BodyBuilder: &email.EmailBodyBuilderWithH1HeadlineAndImage{}, - InviteURL: invite.InviteURL, + BodyBuilder: &email.EmailBodyBuilderWithH1HeadlineAndImage{}, + InviteURL: invite.InviteURL, + PlatformRoleID: invite.PlatformRoleID, } n := email.Notification{ RecipientMail: invite.Email, diff --git a/pro/email/invite.go b/pro/email/invite.go index 86018462c..721b3387e 100644 --- a/pro/email/invite.go +++ b/pro/email/invite.go @@ -2,65 +2,60 @@ package email import ( "fmt" + "github.com/gravitl/netmaker/models" + proLogic "github.com/gravitl/netmaker/pro/logic" "github.com/gravitl/netmaker/servercfg" ) // UserInvitedMail - mail for users that are invited to a tenant type UserInvitedMail struct { - BodyBuilder EmailBodyBuilder - InviteURL string + BodyBuilder EmailBodyBuilder + InviteURL string + PlatformRoleID string } // GetSubject - gets the subject of the email func (UserInvitedMail) GetSubject(info Notification) string { - return "You're invited to join Netmaker" + return "Connect to Your Secure Network Using Netmaker" } // GetBody - gets the body of the email func (invite UserInvitedMail) GetBody(info Notification) string { + downloadLink := "https://www.netmaker.io/download" + supportEmail := "support@netmaker.io" + + dashboardURL := fmt.Sprintf("https://dashboard.%s", servercfg.GetNmBaseDomain()) if servercfg.DeployedByOperator() { - return invite.BodyBuilder. - WithParagraph("Hi there,"). - WithParagraph("
"). - WithParagraph("Great news! Your colleague has invited you to join their Netmaker SaaS Tenant."). - WithParagraph("Click the button to accept your invitation:"). - WithParagraph("
"). - WithParagraph(fmt.Sprintf("Accept Invitation", invite.InviteURL)). - WithParagraph("
"). - WithParagraph("Why you'll love Netmaker:"). - WithParagraph("

    "). - WithParagraph("
  • Blazing-fast connections with our WireGuard®-powered mesh VPN
  • "). - WithParagraph("
  • Seamless multi-cloud and hybrid-cloud networking
  • "). - WithParagraph("
  • Automated Kubernetes networking across any infrastructure
  • "). - WithParagraph("
  • Enterprise-grade security with simple management
  • "). - WithParagraph("
"). - WithParagraph("Got questions? Our team is here to help you every step of the way."). - WithParagraph("
"). - WithParagraph("Welcome aboard,"). - WithParagraph("

The Netmaker Team

"). - WithParagraph("P.S. Curious to learn more before accepting? Check out our quick start tutorial at netmaker.io/tutorials"). - Build() + dashboardURL = fmt.Sprintf("%s/dashboard?tenant_id=%s", proLogic.GetAccountsUIHost(), servercfg.GetNetmakerTenantID()) + } + + content := invite.BodyBuilder. + WithParagraph("Hi,"). + WithParagraph("You've been invited to access a secure network via Netmaker's Remote Access Client (RAC). Follow these simple steps to get connected:"). + WithHtml("
    "). + WithHtml(fmt.Sprintf("
  1. Click here to accept your invitation and setup your account.
  2. ", invite.InviteURL)). + WithHtml("
    "). + WithHtml(fmt.Sprintf("
  3. Download the Remote Access Client (RAC).
  4. ", downloadLink)) + + if invite.PlatformRoleID == models.AdminRole.String() || invite.PlatformRoleID == models.PlatformUser.String() { + content = content. + WithHtml("
    "). + WithHtml(fmt.Sprintf("
  5. Access the Netmaker Dashboard - use it to manage your network settings and view network status.
  6. ", dashboardURL)) + } + + connectionID := servercfg.GetNetmakerTenantID() + if !servercfg.DeployedByOperator() { + connectionID = fmt.Sprintf("api.%s", servercfg.GetNmBaseDomain()) } - return invite.BodyBuilder. - WithParagraph("Hi there,"). - WithParagraph("
    "). - WithParagraph("Great news! Your colleague has invited you to join their Netmaker network."). - WithParagraph("Click the button to accept your invitation:"). - WithParagraph("
    "). - WithParagraph(fmt.Sprintf("Accept Invitation", invite.InviteURL)). - WithParagraph("
    "). - WithParagraph("Why you'll love Netmaker:"). - WithParagraph("
      "). - WithParagraph("
    • Blazing-fast connections with our WireGuard®-powered mesh VPN
    • "). - WithParagraph("
    • Seamless multi-cloud and hybrid-cloud networking
    • "). - WithParagraph("
    • Automated Kubernetes networking across any infrastructure
    • "). - WithParagraph("
    • Enterprise-grade security with simple management
    • "). - WithParagraph("
    "). - WithParagraph("Got questions? Our team is here to help you every step of the way."). - WithParagraph("
    "). - WithParagraph("Welcome aboard,"). - WithParagraph("

    The Netmaker Team

    "). - WithParagraph("P.S. Curious to learn more before accepting? Check out our quick start tutorial at netmaker.io/tutorials"). + return content. + WithHtml("
"). + WithParagraph("Important Information:"). + WithHtml("
    "). + WithHtml(fmt.Sprintf("
  • When connecting through RAC, please enter your server connection ID: %s.
  • ", connectionID)). + WithHtml("
"). + WithParagraph(fmt.Sprintf("If you have any questions or need assistance, please contact our support team at %s.", supportEmail, supportEmail)). + WithParagraph("Best Regards,"). + WithParagraph("The Netmaker Team"). Build() } diff --git a/pro/email/utils.go b/pro/email/utils.go index b689a8beb..4ab221d6a 100644 --- a/pro/email/utils.go +++ b/pro/email/utils.go @@ -4,27 +4,20 @@ import "strings" // mail related images hosted on github var ( - nLogoTeal = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/N_Teal.png" netmakerLogoTeal = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/netmaker-logo-2.png" - netmakerMeshLogo = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/netmaker-mesh.png" - linkedinIcon = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/linkedin2x.png" - discordIcon = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/discord-logo-png-7617.png" - githubIcon = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/Octocat.png" - mailIcon = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/icons8-mail-24.png" - addressIcon = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/icons8-address-16.png" - linkIcon = "https://raw.githubusercontent.com/gravitl/netmaker/netmaker_logos/img/logos/icons8-hyperlink-64.png" ) type EmailBodyBuilder interface { WithHeadline(text string) EmailBodyBuilder WithParagraph(text string) EmailBodyBuilder + WithHtml(text string) EmailBodyBuilder WithSignature() EmailBodyBuilder Build() string } type EmailBodyBuilderWithH1HeadlineAndImage struct { headline string - paragraphs []string + bodyContent []string hasSignature bool } @@ -34,7 +27,12 @@ func (b *EmailBodyBuilderWithH1HeadlineAndImage) WithHeadline(text string) Email } func (b *EmailBodyBuilderWithH1HeadlineAndImage) WithParagraph(text string) EmailBodyBuilder { - b.paragraphs = append(b.paragraphs, text) + b.bodyContent = append(b.bodyContent, styledParagraph(text)) + return b +} + +func (b *EmailBodyBuilderWithH1HeadlineAndImage) WithHtml(text string) EmailBodyBuilder { + b.bodyContent = append(b.bodyContent, text) return b } @@ -44,524 +42,134 @@ func (b *EmailBodyBuilderWithH1HeadlineAndImage) WithSignature() EmailBodyBuilde } func (b *EmailBodyBuilderWithH1HeadlineAndImage) Build() string { - // map paragraphs to styled paragraphs - styledParagraphsSlice := make([]string, len(b.paragraphs)) - for i, paragraph := range b.paragraphs { - styledParagraphsSlice[i] = styledParagraph(paragraph) - } - // join styled paragraphs - styledParagraphsString := strings.Join(styledParagraphsSlice, "") + bodyContent := strings.Join(b.bodyContent, "") - signature := "" - if b.hasSignature { - signature = styledSignature() - } + // TODO: Edit design to add signature. + //signature := "" + //if b.hasSignature { + // signature = styledSignature() + //} return ` - - - - - - - - - - - - - - - - - - - - ` + signature + ` - ` + + + + + + Simple Transactional Email + + + + + + + + + + + +` +} + +func styledParagraph(text string) string { + return `

` + text + `

` } From ce7c164e09fb1582d1b12563c3940e61734ffbf9 Mon Sep 17 00:00:00 2001 From: Aceix Date: Thu, 24 Oct 2024 09:54:00 +0000 Subject: [PATCH 096/169] fix(NET-1540): add cfg to autoclose connections on rac, when logged out (#3130) only auto-disconnect non-admin users when JWT expires on RAC and RAC_AUTO_DISABLE is set --- logic/jwts.go | 5 +++-- models/user_mgmt.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/logic/jwts.go b/logic/jwts.go index 41181fcd6..a70bbbd2d 100644 --- a/logic/jwts.go +++ b/logic/jwts.go @@ -56,8 +56,9 @@ func CreateJWT(uuid string, macAddress string, network string) (response string, func CreateUserJWT(username string, role models.UserRoleID) (response string, err error) { expirationTime := time.Now().Add(servercfg.GetServerConfig().JwtValidityDuration) claims := &models.UserClaims{ - UserName: username, - Role: role, + UserName: username, + Role: role, + RacAutoDisable: servercfg.GetRacAutoDisable() && (role != models.SuperAdminRole && role != models.AdminRole), RegisteredClaims: jwt.RegisteredClaims{ Issuer: "Netmaker", Subject: fmt.Sprintf("user|%s", username), diff --git a/models/user_mgmt.go b/models/user_mgmt.go index a87a0f4b8..6c8887e9d 100644 --- a/models/user_mgmt.go +++ b/models/user_mgmt.go @@ -177,8 +177,9 @@ type UserAuthParams struct { // UserClaims - user claims struct type UserClaims struct { - Role UserRoleID - UserName string + Role UserRoleID + UserName string + RacAutoDisable bool jwt.RegisteredClaims } From fcf94e56522cd605e64f6afd6707e361995e35f2 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 24 Oct 2024 14:02:39 +0400 Subject: [PATCH 097/169] use name generator --- go.mod | 1 + go.sum | 2 + models/names.go | 234 ++---------------------------------------------- 3 files changed, 8 insertions(+), 229 deletions(-) diff --git a/go.mod b/go.mod index e2b53e6bc..b8f75be15 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( ) require ( + github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e github.com/guumaster/tablewriter v0.0.10 github.com/matryer/is v1.4.1 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 9f0434ce8..db5488d2d 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e h1:XmA6L9IPRdUr28a+SK/oMchGgQy159wvzXA5tJ7l+40= +github.com/goombaio/namegenerator v0.0.0-20181006234301-989e774b106e/go.mod h1:AFIo+02s+12CEg8Gzz9kzhCbmbq6JcKNrhHffCGA9z4= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= diff --git a/models/names.go b/models/names.go index edf9b48cc..75f6a16c6 100644 --- a/models/names.go +++ b/models/names.go @@ -1,242 +1,18 @@ package models import ( - "math/rand" "time" -) - -// NAMES - list of names 4-7 chars in length -var NAMES = []string{ - "logic", - "warrant", - "iconic", - "threat", - "strike", - "boy", - "vital", - "unity", - "audio", - "schemer", - "depth", - "gravitl", - "mystic", - "donkey", - "atomic", - "turtle", - "monkey", - "rabbit", - "static", - "mosaic", - "elite", - "stonks", - "doggy", - "python", - "mohawk", - "arctic", - "rival", - "vibes", - "delay", - "bridge", - "weeble", - "combat", - "animal", - "wobble", - "rubble", - "bucket", - "proof", - "worker", - "beetle", - "racket", - "equal", - "panda", - "antics", - "strong", - "forum", - "koala", - "anchor", - "ornery", - "indigo", - "schism", - "dragon", - "knight", - "bishop", - "laser", - "rhino", - "clutch", - "shark", - "leader", - "young", - "robot", - "squish", - "chimp", - "rocket", - "space", - "queen", - "royalty", - "flush", - "earth", - "planet", - "heart", - "droplet", - "dillon", - "saturn", - "pluto", - "school", - "alien", - "matte", - "dingo", - "meercat", - "cookie", - "snack", - "goose", - "pepper", - "melissa", - "alex", - "elon", - "yeet", - "meh", - "walrus", - "avatar", - "chicken", - "proton", - "mohawk", - "tattoo", - "zebra", - "star", - "butter", - "tango", - "homie", - "rambo", - "cosmo", - "bubbles", - "hulk", - "pluto", - "scooby", - "thanos", - "yoda", - "draco", - "goofy", - "ditto", - "puff", - "duck", - "mouse", - "akita", - "water", - "hound", - "baby", - "spider", - "squid", - "roach", - "crab", - "cougar", - "cyborg", - "android", - "being", - "ninja", - "unicorn", - "zombie", - "warrior", - "zamboni", - "life", - "marine", - "node", - "mother", - "father", - "tesla", -} -// SMALL_NAMES - list of small (4 char or less) names -var SMALL_NAMES = []string{ - "ace", - "odd", - "hot", - "ill", - "root", - "sudo", - "moon", - "beef", - "bro", - "dank", - "red", - "gold", - "big", - "old", - "og", - "best", - "blue", - "lil", - "mom", - "bot", - "evil", - "good", - "holy", - "rad", - "bad", - "sad", - "mad", - "chad", - "pre", - "post", - "foot", - "soft", - "hard", - "lite", - "dark", - "true", - "toy", - "soy", - "rude", - "nice", - "fun", - "fat", - "pro", - "sly", - "tan", - "pet", - "fine", - "main", - "last", - "wide", - "free", - "open", - "poor", - "rich", - "next", - "real", - "long", - "huge", - "wild", - "sick", - "weak", - "firm", - "pink", - "okay", - "dull", - "loud", - "lazy", - "dumb", - "tidy", - "idle", - "bony", - "cute", - "oily", - "lame", - "mega", - "limp", - "wavy", - "edgy", - "nosy", - "zany", - "base", - "cold", -} + "github.com/goombaio/namegenerator" +) var logoString = retrieveLogo() // GenerateNodeName - generates a random node name func GenerateNodeName() string { - rng := rand.New(rand.NewSource(time.Now().UnixNano())) - return SMALL_NAMES[rng.Intn(len(SMALL_NAMES))] + "-" + NAMES[rng.Intn(len(NAMES))] + seed := time.Now().UTC().UnixNano() + nameGenerator := namegenerator.NewNameGenerator(seed) + return nameGenerator.Generate() } // RetrieveLogo - retrieves the ascii art logo for Netmaker From 1cf828961d8e9ad4afe70106c71b61a1d4dcdc00 Mon Sep 17 00:00:00 2001 From: the_aceix Date: Thu, 24 Oct 2024 05:26:35 +0000 Subject: [PATCH 098/169] fix(NET-1613): patch api responses fot create and update tags --- controllers/tags.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/controllers/tags.go b/controllers/tags.go index 2def88f68..f073f382a 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -130,7 +130,13 @@ func createTag(w http.ResponseWriter, r *http.Request) { } }() - logic.ReturnSuccessResponseWithJson(w, r, req, "created tag successfully") + var res models.TagListRespNodes = models.TagListRespNodes{ + Tag: tag, + UsedByCnt: len(req.TaggedNodes), + TaggedNodes: req.TaggedNodes, + } + + logic.ReturnSuccessResponseWithJson(w, r, res, "created tag successfully") } // @Summary Update Tag @@ -175,7 +181,14 @@ func updateTag(w http.ResponseWriter, r *http.Request) { logic.DeleteTag(updateTag.ID) } go logic.UpdateTag(updateTag, newID) - logic.ReturnSuccessResponse(w, r, "updating tags") + + var res models.TagListRespNodes = models.TagListRespNodes{ + Tag: tag, + UsedByCnt: len(updateTag.TaggedNodes), + TaggedNodes: updateTag.TaggedNodes, + } + + logic.ReturnSuccessResponseWithJson(w, r, res, "updated tags") } // @Summary Delete Tag From 10de931a866f744bc83ffdaf822694991e827e33 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 24 Oct 2024 15:16:59 +0400 Subject: [PATCH 099/169] fix extclient validation err messages --- controllers/ext_client.go | 2 +- controllers/regex.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/ext_client.go b/controllers/ext_client.go index 09c5f5d52..a76bd1c91 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -752,7 +752,7 @@ func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bo //validate clientid if customExtClient.ClientID != "" { if err := isValid(customExtClient.ClientID, checkID); err != nil { - return fmt.Errorf("client validatation: %v", err) + return fmt.Errorf("client validation: %v", err) } } //extclient.ClientID = customExtClient.ClientID diff --git a/controllers/regex.go b/controllers/regex.go index 2c1f0c51e..3663e3731 100644 --- a/controllers/regex.go +++ b/controllers/regex.go @@ -7,9 +7,9 @@ import ( var ( errInvalidExtClientPubKey = errors.New("incorrect ext client public key") - errInvalidExtClientID = errors.New("ext client ID must be alphanumderic and/or dashes and less that 15 chars") - errInvalidExtClientExtraIP = errors.New("ext client extra ip must be a valid cidr") - errInvalidExtClientDNS = errors.New("ext client dns must be a valid ip address") + errInvalidExtClientID = errors.New("client ID must be alphanumderic and/or dashes and less that 15 chars") + errInvalidExtClientExtraIP = errors.New("client extra ip must be a valid cidr") + errInvalidExtClientDNS = errors.New("client dns must be a valid ip address") errDuplicateExtClientName = errors.New("duplicate client name") ) From 514e785f7b1f9a4372dd1281278d6344bd79ed0d Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 25 Oct 2024 16:15:41 +0400 Subject: [PATCH 100/169] ignore disabled policies for users --- pro/logic/user_mgmt.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 2af61f90e..f4bff8107 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -530,6 +530,9 @@ func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { tagNodesMap := logic.GetTagMapWithNodes() accessPolices := logic.ListUserPolicies(user) for _, policyI := range accessPolices { + if !policyI.Enabled { + continue + } for _, dstI := range policyI.Dst { if dstI.Value == "*" { networkNodes := logic.GetNetworkNodesMemory(nodes, policyI.NetworkID.String()) From 79048868d9988fc7bd2aa086f035936aae4ce6c0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 25 Oct 2024 16:17:55 +0400 Subject: [PATCH 101/169] fix client validation messages --- controllers/regex.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/regex.go b/controllers/regex.go index 3663e3731..488e7dbc6 100644 --- a/controllers/regex.go +++ b/controllers/regex.go @@ -6,8 +6,8 @@ import ( ) var ( - errInvalidExtClientPubKey = errors.New("incorrect ext client public key") - errInvalidExtClientID = errors.New("client ID must be alphanumderic and/or dashes and less that 15 chars") + errInvalidExtClientPubKey = errors.New("incorrect client public key") + errInvalidExtClientID = errors.New("node name must be alphanumderic and/or dashes and less that 15 chars") errInvalidExtClientExtraIP = errors.New("client extra ip must be a valid cidr") errInvalidExtClientDNS = errors.New("client dns must be a valid ip address") errDuplicateExtClientName = errors.New("duplicate client name") From 502a15ea14e83d84fce2a86fd5229c352a801fbd Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 27 Oct 2024 23:00:36 +0400 Subject: [PATCH 102/169] ignore setting up rules when default poliy is enabled --- logic/extpeers.go | 112 ++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 49 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 53028c259..a207e2fcf 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -403,8 +403,17 @@ func ToggleExtClientConnectivity(client *models.ExtClient, enable bool) (models. } func GetStaticNodeIps(node models.Node) (ips []net.IP) { + defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) + defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) + extclients := GetStaticNodesByNetwork(models.NetworkID(node.Network), false) for _, extclient := range extclients { + if extclient.IsUserNode && defaultUserPolicy.Enabled { + continue + } + if !extclient.IsUserNode && defaultDevicePolicy.Enabled { + continue + } if extclient.StaticNode.Address != "" { ips = append(ips, extclient.StaticNode.AddressIPNet4().IP) } @@ -417,62 +426,67 @@ func GetStaticNodeIps(node models.Node) (ips []net.IP) { func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { // fetch user access to static clients via policies - + defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) + defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) 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, - }) - } + if !defaultUserPolicy.Enabled { + 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, + }) + } + } + } } } } - + if defaultDevicePolicy.Enabled { + return + } for _, nodeI := range nodes { if !nodeI.IsStatic || nodeI.IsUserNode { continue From bf88a80ea244591511bb218233a24aacefdb9d95 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Sun, 27 Oct 2024 23:31:30 +0400 Subject: [PATCH 103/169] avoid gateway role migration --- pro/controllers/users.go | 8 +-- pro/logic/user_mgmt.go | 148 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 4 deletions(-) diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 1202a953d..07686fee1 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -834,7 +834,7 @@ func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) { userGws := make(map[string][]models.UserRemoteGws) networks := []models.Network{} networkMap := make(map[string]struct{}) - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) for _, node := range userGwNodes { network, err := logic.GetNetwork(node.Network) if err != nil { @@ -876,7 +876,7 @@ func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request) } userGws := []models.UserRAGs{} - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) for _, node := range userGwNodes { if node.Network != network { continue @@ -931,7 +931,7 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) { return } - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) if _, ok := userGwNodes[remoteGwID]; !ok { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden")) return @@ -1075,7 +1075,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) for _, extClient := range allextClients { node, ok := userGwNodes[extClient.IngressGatewayID] if !ok { diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index f4bff8107..f5e07c015 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -7,6 +7,7 @@ import ( "time" "github.com/gravitl/netmaker/database" + "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/mq" @@ -555,6 +556,153 @@ func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { return } +func GetUserRAGNodes(user models.User) (gws map[string]models.Node) { + gws = make(map[string]models.Node) + userGwAccessScope := GetUserNetworkRolesWithRemoteVPNAccess(user) + logger.Log(3, fmt.Sprintf("User Gw Access Scope: %+v", userGwAccessScope)) + _, allNetAccess := userGwAccessScope["*"] + nodes, err := logic.GetAllNodes() + if err != nil { + return + } + for _, node := range nodes { + if node.IsIngressGateway && !node.PendingDelete { + if allNetAccess { + gws[node.ID.String()] = node + } else { + gwRsrcMap := userGwAccessScope[models.NetworkID(node.Network)] + scope, ok := gwRsrcMap[models.AllRemoteAccessGwRsrcID] + if !ok { + if scope, ok = gwRsrcMap[models.RsrcID(node.ID.String())]; !ok { + continue + } + } + if scope.VPNaccess { + gws[node.ID.String()] = node + } + + } + } + } + return +} + +// GetUserNetworkRoles - get user network roles +func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope) { + gwAccess = make(map[models.NetworkID]map[models.RsrcID]models.RsrcPermissionScope) + platformRole, err := logic.GetRole(user.PlatformRoleID) + if err != nil { + return + } + if platformRole.FullAccess { + gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope) + return + } + if _, ok := user.NetworkRoles[models.AllNetworks]; ok { + gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope) + } + if len(user.UserGroups) > 0 { + for gID := range user.UserGroups { + userG, err := GetUserGroup(gID) + if err != nil { + continue + } + for netID, roleMap := range userG.NetworkRoles { + for roleID := range roleMap { + role, err := logic.GetRole(roleID) + if err == nil { + if role.FullAccess { + gwAccess[netID] = map[models.RsrcID]models.RsrcPermissionScope{ + models.AllRemoteAccessGwRsrcID: { + Create: true, + Read: true, + Update: true, + VPNaccess: true, + Delete: true, + }, + models.AllExtClientsRsrcID: { + Create: true, + Read: true, + Update: true, + Delete: true, + }, + } + break + } + if rsrcsMap, ok := role.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok { + if permissions, ok := rsrcsMap[models.AllRemoteAccessGwRsrcID]; ok && permissions.VPNaccess { + if len(gwAccess[netID]) == 0 { + gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) + } + gwAccess[netID][models.AllRemoteAccessGwRsrcID] = permissions + break + } else { + for gwID, scope := range rsrcsMap { + if scope.VPNaccess { + if len(gwAccess[netID]) == 0 { + gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) + } + gwAccess[netID][gwID] = scope + } + } + } + + } + + } + } + } + } + } + for netID, roleMap := range user.NetworkRoles { + for roleID := range roleMap { + role, err := logic.GetRole(roleID) + if err == nil { + if role.FullAccess { + gwAccess[netID] = map[models.RsrcID]models.RsrcPermissionScope{ + models.AllRemoteAccessGwRsrcID: { + Create: true, + Read: true, + Update: true, + VPNaccess: true, + Delete: true, + }, + models.AllExtClientsRsrcID: { + Create: true, + Read: true, + Update: true, + Delete: true, + }, + } + break + } + if rsrcsMap, ok := role.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok { + if permissions, ok := rsrcsMap[models.AllRemoteAccessGwRsrcID]; ok && permissions.VPNaccess { + if len(gwAccess[netID]) == 0 { + gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) + } + gwAccess[netID][models.AllRemoteAccessGwRsrcID] = permissions + break + } else { + for gwID, scope := range rsrcsMap { + if scope.VPNaccess { + if len(gwAccess[netID]) == 0 { + gwAccess[netID] = make(map[models.RsrcID]models.RsrcPermissionScope) + } + gwAccess[netID][gwID] = scope + } + } + } + + } + + } + } + } + + return +} + func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filteredNodes []models.Node) { nodesMap := make(map[string]struct{}) From 20302f7701cc857dab5e25584acf98f05c73506b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 28 Oct 2024 09:41:09 +0400 Subject: [PATCH 104/169] fix default policy check on static node network --- logic/acls.go | 28 ++++++------ logic/extpeers.go | 107 +++++++++++++++++++++++++--------------------- 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 692c00d2b..cb5587717 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -441,6 +441,9 @@ 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 { + if peer.IsStatic { + peer = peer.StaticNode.ConvertToStaticNode() + } acl, _ := GetDefaultPolicy(models.NetworkID(peer.Network), models.UserPolicy) if acl.Enabled { return true @@ -449,9 +452,7 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { 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 { @@ -473,6 +474,12 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { + if node.IsStatic { + node = node.StaticNode.ConvertToStaticNode() + } + if peer.IsStatic { + peer = peer.StaticNode.ConvertToStaticNode() + } // check default policy if all allowed return true defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) if err == nil { @@ -480,12 +487,7 @@ 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 { @@ -494,10 +496,10 @@ func IsNodeAllowedToCommunicate(node, peer models.Node) bool { } srcMap := convAclTagToValueMap(policy.Src) dstMap := convAclTagToValueMap(policy.Dst) - fmt.Printf("\n======> SRCMAP: %+v\n", srcMap) - fmt.Printf("\n======> DSTMAP: %+v\n", dstMap) - fmt.Printf("\n======> node Tags: %+v\n", node.Tags) - fmt.Printf("\n======> peer Tags: %+v\n", peer.Tags) + // fmt.Printf("\n======> SRCMAP: %+v\n", srcMap) + // fmt.Printf("\n======> DSTMAP: %+v\n", dstMap) + // fmt.Printf("\n======> node Tags: %+v\n", node.Tags) + // fmt.Printf("\n======> peer Tags: %+v\n", peer.Tags) for tagID := range node.Tags { if _, ok := dstMap[tagID.String()]; ok { if _, ok := srcMap["*"]; ok { diff --git a/logic/extpeers.go b/logic/extpeers.go index a207e2fcf..305b449ae 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -426,64 +426,73 @@ func GetStaticNodeIps(node models.Node) (ips []net.IP) { func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { // fetch user access to static clients via policies - defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) + //defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) nodes, _ := GetNetworkNodes(node.Network) nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...) - if !defaultUserPolicy.Enabled { - 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, - }) - } + //fmt.Printf("=====> NODES: %+v \n\n", nodes) + userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network)) + //fmt.Printf("=====> USER NODES %+v \n\n", userNodes) + 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, + }) + } } + } } } + if defaultDevicePolicy.Enabled { return } From 5e62e7e7496bb4ee5bf389c0a1bb5684629ec089 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 28 Oct 2024 10:53:12 +0400 Subject: [PATCH 105/169] check default user policy --- logic/extpeers.go | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 305b449ae..0e1a70960 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -426,7 +426,7 @@ func GetStaticNodeIps(node models.Node) (ips []net.IP) { func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { // fetch user access to static clients via policies - //defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) + defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) nodes, _ := GetNetworkNodes(node.Network) nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...) @@ -438,18 +438,16 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { 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, - }) - + if !defaultUserPolicy.Enabled { + 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, @@ -457,12 +455,13 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { }) } if userNodeI.StaticNode.Address6 != "" { - - rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet6().IP, - DstIP: peer.StaticNode.AddressIPNet6().IP, - Allow: true, - }) + if !defaultUserPolicy.Enabled { + 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, @@ -473,11 +472,13 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { } else { if userNodeI.StaticNode.Address != "" { - rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, - DstIP: peer.Address.IP, - Allow: true, - }) + if !defaultUserPolicy.Enabled { + rules = append(rules, models.FwRule{ + SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, + DstIP: peer.Address.IP, + Allow: true, + }) + } } if userNodeI.StaticNode.Address6 != "" { From f7b78ccad66fa9c40b14dca577a7d006c41b2cf8 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 28 Oct 2024 11:39:16 +0400 Subject: [PATCH 106/169] remove user role from acl policy types --- controllers/acls.go | 2 +- logic/acls.go | 23 +++++----- models/acl.go | 6 +-- pro/logic/user_mgmt.go | 98 +++++++++++++++++++++--------------------- 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 4fdd05175..02bdbe5d9 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -44,7 +44,7 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) { }, SrcGroupTypes: []models.AclGroupType{ models.UserAclID, - models.UserRoleAclID, + //models.UserRoleAclID, models.UserGroupAclID, models.DeviceAclID, }, diff --git a/logic/acls.go b/logic/acls.go index cb5587717..d2d657848 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -56,10 +56,10 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { ID: models.UserGroupAclID, Value: "*", }, - { - ID: models.UserRoleAclID, - Value: "*", - }, + // { + // ID: models.UserRoleAclID, + // Value: "*", + // }, }, Dst: []models.AclPolicyTag{{ ID: models.DeviceAclID, @@ -175,8 +175,9 @@ func IsAclPolicyValid(acl models.Acl) bool { if srcI.Value == "*" { continue } - if srcI.ID != models.UserAclID && - srcI.ID != models.UserGroupAclID && srcI.ID != models.UserRoleAclID { + if srcI.ID != models.UserAclID { + // && srcI.ID != models.UserGroupAclID && srcI.ID != models.UserRoleAclID + return false } // check if user group is valid @@ -185,12 +186,12 @@ func IsAclPolicyValid(acl models.Acl) bool { if err != nil { return false } - } else if srcI.ID == models.UserRoleAclID { + // } else if srcI.ID == models.UserRoleAclID { - _, err := GetRole(models.UserRoleID(srcI.Value)) - if err != nil { - return false - } + // _, err := GetRole(models.UserRoleID(srcI.Value)) + // if err != nil { + // return false + // } } else if srcI.ID == models.UserGroupAclID { err := IsGroupValid(models.UserGroupID(srcI.Value)) diff --git a/models/acl.go b/models/acl.go index 1200536b1..83007d5e1 100644 --- a/models/acl.go +++ b/models/acl.go @@ -44,9 +44,9 @@ type AclPolicyTag struct { type AclGroupType string const ( - UserAclID AclGroupType = "user" - UserGroupAclID AclGroupType = "user-group" - UserRoleAclID AclGroupType = "user-role" + UserAclID AclGroupType = "user" + UserGroupAclID AclGroupType = "user-group" + //UserRoleAclID AclGroupType = "user-role" DeviceAclID AclGroupType = "tag" NetmakerIPAclID AclGroupType = "ip" NetmakerSubNetRangeAClID AclGroupType = "ipset" diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index f5e07c015..7673673b6 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -1100,55 +1100,55 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { if netID.String() == "" { return } - if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin))) { - defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin)), - Name: models.NetworkAdmin.String(), - Default: true, - NetworkID: netID, - RuleType: models.UserPolicy, - Src: []models.AclPolicyTag{ - { - ID: models.UserRoleAclID, - Value: fmt.Sprintf("%s-%s", netID, models.NetworkAdmin), - }}, - Dst: []models.AclPolicyTag{ - { - ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), - }, - }, - AllowedDirection: models.TrafficDirectionUni, - Enabled: true, - CreatedBy: "auto", - CreatedAt: time.Now().UTC(), - } - logic.InsertAcl(defaultUserAcl) - } - if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser))) { - defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser)), - Name: models.NetworkUser.String(), - Default: true, - NetworkID: netID, - RuleType: models.UserPolicy, - Src: []models.AclPolicyTag{ - { - ID: models.UserRoleAclID, - Value: fmt.Sprintf("%s-%s", netID, models.NetworkUser), - }}, - Dst: []models.AclPolicyTag{ - { - ID: models.DeviceAclID, - Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), - }}, - AllowedDirection: models.TrafficDirectionUni, - Enabled: true, - CreatedBy: "auto", - CreatedAt: time.Now().UTC(), - } - logic.InsertAcl(defaultUserAcl) - } + // if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin))) { + // defaultUserAcl := models.Acl{ + // ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin)), + // Name: models.NetworkAdmin.String(), + // Default: true, + // NetworkID: netID, + // RuleType: models.UserPolicy, + // Src: []models.AclPolicyTag{ + // { + // ID: models.UserRoleAclID, + // Value: fmt.Sprintf("%s-%s", netID, models.NetworkAdmin), + // }}, + // Dst: []models.AclPolicyTag{ + // { + // ID: models.DeviceAclID, + // Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), + // }, + // }, + // AllowedDirection: models.TrafficDirectionUni, + // Enabled: true, + // CreatedBy: "auto", + // CreatedAt: time.Now().UTC(), + // } + // logic.InsertAcl(defaultUserAcl) + // } + // if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser))) { + // defaultUserAcl := models.Acl{ + // ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser)), + // Name: models.NetworkUser.String(), + // Default: true, + // NetworkID: netID, + // RuleType: models.UserPolicy, + // Src: []models.AclPolicyTag{ + // { + // ID: models.UserRoleAclID, + // Value: fmt.Sprintf("%s-%s", netID, models.NetworkUser), + // }}, + // Dst: []models.AclPolicyTag{ + // { + // ID: models.DeviceAclID, + // Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), + // }}, + // AllowedDirection: models.TrafficDirectionUni, + // Enabled: true, + // CreatedBy: "auto", + // CreatedAt: time.Now().UTC(), + // } + // logic.InsertAcl(defaultUserAcl) + // } if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin))) { defaultUserAcl := models.Acl{ From 4eacadbb27925dd89427dc16a9a7440be9a496b1 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 28 Oct 2024 16:18:50 +0400 Subject: [PATCH 107/169] convert network roles to groups, deprecate RAG roles --- controllers/hosts.go | 13 -------- logic/gateway.go | 24 -------------- logic/hosts.go | 2 +- logic/user_mgmt.go | 5 +++ main.go | 1 + migrate/migrate.go | 72 ++++++------------------------------------ models/user_mgmt.go | 5 ++- pro/initialize.go | 2 ++ pro/logic/migrate.go | 54 +++++++++++++++++++++++++++++++ pro/logic/user_mgmt.go | 48 +++++++++++++++++++++++++--- 10 files changed, 120 insertions(+), 106 deletions(-) create mode 100644 pro/logic/migrate.go diff --git a/controllers/hosts.go b/controllers/hosts.go index dbfbc6d51..a1015cf95 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -253,19 +253,6 @@ func updateHost(w http.ResponseWriter, r *http.Request) { newHost := newHostData.ConvertAPIHostToNMHost(currHost) - if newHost.Name != currHost.Name { - // update any rag role ids - for _, nodeID := range newHost.Nodes { - node, err := logic.GetNodeByID(nodeID) - if err == nil && node.IsIngressGateway { - role, err := logic.GetRole(models.GetRAGRoleID(node.Network, currHost.ID.String())) - if err == nil { - role.UiName = models.GetRAGRoleName(node.Network, newHost.Name) - logic.UpdateRole(role) - } - } - } - } logic.UpdateHost(newHost, currHost) // update the in memory struct values if err = logic.UpsertHost(newHost); err != nil { logger.Log(0, r.Header.Get("user"), "failed to update a host:", err.Error()) diff --git a/logic/gateway.go b/logic/gateway.go index ba7521976..ab68a4362 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -188,30 +188,6 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq if err != nil { return models.Node{}, err } - // create network role for this gateway - CreateRole(models.UserRolePermissionTemplate{ - ID: models.GetRAGRoleID(node.Network, host.ID.String()), - UiName: models.GetRAGRoleName(node.Network, host.Name), - NetworkID: models.NetworkID(node.Network), - Default: true, - NetworkLevelAccess: map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope{ - models.RemoteAccessGwRsrc: { - models.RsrcID(node.ID.String()): models.RsrcPermissionScope{ - Read: true, - VPNaccess: true, - }, - }, - models.ExtClientsRsrc: { - models.AllExtClientsRsrcID: models.RsrcPermissionScope{ - Read: true, - Create: true, - Update: true, - Delete: true, - SelfOnly: true, - }, - }, - }, - }) err = SetNetworkNodesLastModified(netid) return node, err } diff --git a/logic/hosts.go b/logic/hosts.go index 48482e045..f8a310bf3 100644 --- a/logic/hosts.go +++ b/logic/hosts.go @@ -294,7 +294,7 @@ func UpdateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) if err == nil && node.IsIngressGateway { role, err := GetRole(models.GetRAGRoleID(node.Network, currHost.ID.String())) if err == nil { - role.UiName = models.GetRAGRoleName(node.Network, newHost.Name) + role.Name = models.GetRAGRoleName(node.Network, newHost.Name) UpdateRole(role) } } diff --git a/logic/user_mgmt.go b/logic/user_mgmt.go index 62ba22bf7..3e22bb50c 100644 --- a/logic/user_mgmt.go +++ b/logic/user_mgmt.go @@ -46,11 +46,16 @@ var IsNetworkRolesValid = func(networkRoles map[models.NetworkID]map[models.User return nil } +var MigrateUserRoleAndGroups = func(u models.User) { + +} + var UpdateUserGwAccess = func(currentUser, changeUser models.User) {} var UpdateRole = func(r models.UserRolePermissionTemplate) error { return nil } var InitialiseRoles = userRolesInit +var IntialiseGroups = func() {} var DeleteNetworkRoles = func(netID string) {} var CreateDefaultNetworkRolesAndGroups = func(netID models.NetworkID) {} var CreateDefaultUserPolicies = func(netID models.NetworkID) {} diff --git a/main.go b/main.go index 027b51c72..cbfe67ddc 100644 --- a/main.go +++ b/main.go @@ -103,6 +103,7 @@ func initialize() { // Client Mode Prereq Check logic.SetJWTSecret() logic.InitialiseRoles() + logic.IntialiseGroups() err = serverctl.SetDefaults() if err != nil { logger.FatalLog("error setting defaults: ", err.Error()) diff --git a/migrate/migrate.go b/migrate/migrate.go index eda7a7d33..1df7461ef 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -178,7 +178,10 @@ func updateNodes() { node.Tags[tagID] = struct{}{} logic.UpsertNode(&node) } - + host, err := logic.GetHost(node.HostID.String()) + if err == nil { + go logic.DeleteRole(models.GetRAGRoleID(node.Network, host.ID.String()), true) + } } if node.IsEgressGateway { egressRanges, update := removeInterGw(node.EgressGatewayRanges) @@ -356,42 +359,8 @@ func syncUsers() { // create default network user roles for existing networks if servercfg.IsPro { networks, _ := logic.GetNetworks() - nodes, err := logic.GetAllNodes() - if err == nil { - for _, netI := range networks { - logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(netI.NetID)) - networkNodes := logic.GetNetworkNodesMemory(nodes, netI.NetID) - for _, networkNodeI := range networkNodes { - if networkNodeI.IsIngressGateway { - h, err := logic.GetHost(networkNodeI.HostID.String()) - if err == nil { - logic.CreateRole(models.UserRolePermissionTemplate{ - ID: models.GetRAGRoleID(networkNodeI.Network, h.ID.String()), - UiName: models.GetRAGRoleName(networkNodeI.Network, h.Name), - NetworkID: models.NetworkID(netI.NetID), - NetworkLevelAccess: map[models.RsrcType]map[models.RsrcID]models.RsrcPermissionScope{ - models.RemoteAccessGwRsrc: { - models.RsrcID(networkNodeI.ID.String()): models.RsrcPermissionScope{ - Read: true, - VPNaccess: true, - }, - }, - models.ExtClientsRsrc: { - models.AllExtClientsRsrcID: models.RsrcPermissionScope{ - Read: true, - Create: true, - Update: true, - Delete: true, - SelfOnly: true, - }, - }, - }, - }) - } - - } - } - } + for _, netI := range networks { + logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(netI.NetID)) } } @@ -429,34 +398,11 @@ func syncUsers() { user.PlatformRoleID = models.ServiceUser } logic.UpsertUser(user) - if len(user.RemoteGwIDs) > 0 { - // define user roles for network - // assign relevant network role to user - for remoteGwID := range user.RemoteGwIDs { - gwNode, err := logic.GetNodeByID(remoteGwID) - if err != nil { - continue - } - h, err := logic.GetHost(gwNode.HostID.String()) - if err != nil { - continue - } - r, err := logic.GetRole(models.GetRAGRoleID(gwNode.Network, h.ID.String())) - if err != nil { - continue - } - if netRoles, ok := user.NetworkRoles[models.NetworkID(gwNode.Network)]; ok { - netRoles[r.ID] = struct{}{} - } else { - user.NetworkRoles[models.NetworkID(gwNode.Network)] = map[models.UserRoleID]struct{}{ - r.ID: {}, - } - } - } - logic.UpsertUser(user) - } + logic.MigrateUserRoleAndGroups(user) + } } + } func createDefaultTagsAndPolicies() { diff --git a/models/user_mgmt.go b/models/user_mgmt.go index a87a0f4b8..d97e25328 100644 --- a/models/user_mgmt.go +++ b/models/user_mgmt.go @@ -116,8 +116,9 @@ type RsrcPermissionScope struct { type UserRolePermissionTemplate struct { ID UserRoleID `json:"id"` - UiName string `json:"ui_name"` + Name string `json:"name"` Default bool `json:"default"` + MetaData string `json:"meta_data"` DenyDashboardAccess bool `json:"deny_dashboard_access"` FullAccess bool `json:"full_access"` NetworkID NetworkID `json:"network_id"` @@ -132,6 +133,8 @@ type CreateGroupReq struct { type UserGroup struct { ID UserGroupID `json:"id"` + Default bool `json:"default"` + Name string `json:"name"` NetworkRoles map[NetworkID]map[UserRoleID]struct{} `json:"network_roles"` MetaData string `json:"meta_data"` } diff --git a/pro/initialize.go b/pro/initialize.go index 66a498235..496758cbf 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -136,6 +136,8 @@ func InitPro() { logic.InitialiseRoles = proLogic.UserRolesInit logic.UpdateUserGwAccess = proLogic.UpdateUserGwAccess logic.CreateDefaultUserPolicies = proLogic.CreateDefaultUserPolicies + logic.MigrateUserRoleAndGroups = proLogic.MigrateUserRoleAndGroups + logic.IntialiseGroups = proLogic.UserGroupsInit } func retrieveProLogo() string { diff --git a/pro/logic/migrate.go b/pro/logic/migrate.go new file mode 100644 index 000000000..d30e71e06 --- /dev/null +++ b/pro/logic/migrate.go @@ -0,0 +1,54 @@ +package logic + +import ( + "fmt" + + "github.com/gravitl/netmaker/logic" + "github.com/gravitl/netmaker/models" +) + +func MigrateUserRoleAndGroups(user models.User) { + var err error + if len(user.RemoteGwIDs) > 0 { + // define user roles for network + // assign relevant network role to user + for remoteGwID := range user.RemoteGwIDs { + gwNode, err := logic.GetNodeByID(remoteGwID) + if err != nil { + continue + } + var g models.UserGroup + if user.PlatformRoleID == models.ServiceUser { + g, err = GetUserGroup(models.UserGroupID(fmt.Sprintf("%s-%s-grp", gwNode.Network, models.NetworkUser))) + } else { + g, err = GetUserGroup(models.UserGroupID(fmt.Sprintf("%s-%s-grp", + gwNode.Network, models.NetworkAdmin))) + } + if err != nil { + continue + } + user.UserGroups[g.ID] = struct{}{} + + } + } + if len(user.NetworkRoles) > 0 { + for netID := range user.NetworkRoles { + var g models.UserGroup + if user.PlatformRoleID == models.ServiceUser { + g, err = GetUserGroup(models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser))) + } else { + g, err = GetUserGroup(models.UserGroupID(fmt.Sprintf("%s-%s-grp", + netID, models.NetworkAdmin))) + } + if err != nil { + continue + } + user.UserGroups[g.ID] = struct{}{} + if err != nil { + continue + } + } + + } + logic.UpsertUser(user) +} diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 7673673b6..6faa9084c 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -30,6 +30,8 @@ var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)), + Name: "Network Admins", + MetaData: "Users with this role can manage all your networks configuration including adding and removing devices.", Default: true, FullAccess: true, NetworkID: models.AllNetworks, @@ -37,6 +39,8 @@ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ var NetworkUserAllPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)), + Name: "Network Users", + MetaData: "Users with this role Cannot access the admin console, but can connect to nodes in your networks via RAC.", Default: true, FullAccess: false, NetworkID: models.AllNetworks, @@ -75,12 +79,44 @@ func UserRolesInit() { } +func UserGroupsInit() { + // create default network groups + var NetworkGlobalAdminGroup = models.UserGroup{ + ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin)), + Default: true, + Name: "Network Admin Group", + MetaData: "Users in this group can manage all your networks configuration including adding and removing devices.", + NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ + models.NetworkID("*"): { + models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)): {}, + }, + }, + } + var NetworkGlobalUserGroup = models.UserGroup{ + ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkUser)), + Name: "Network User Group", + Default: true, + NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ + models.NetworkID("*"): { + models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {}, + }, + }, + MetaData: "Users in this group cannot access the admin console, but can connect to nodes in your networks via RAC.", + } + d, _ := json.Marshal(NetworkGlobalAdminGroup) + database.Insert(NetworkGlobalAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) + d, _ = json.Marshal(NetworkGlobalUserGroup) + database.Insert(NetworkGlobalUserGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) +} + func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { if netID.String() == "" { return } var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)), + Name: fmt.Sprintf("%s Admin", netID), + MetaData: fmt.Sprintf("Users with this role can manage your network `%s` configuration including adding and removing devices.", netID), Default: true, NetworkID: netID, FullAccess: true, @@ -89,6 +125,8 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)), + Name: fmt.Sprintf("%s User", netID), + MetaData: fmt.Sprintf("Users Cannot access the admin console, but can connect to nodes in your network `%s` via RAC.", netID), Default: true, FullAccess: false, NetworkID: netID, @@ -118,22 +156,24 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { // create default network groups var NetworkAdminGroup = models.UserGroup{ - ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkAdmin)), + ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkAdmin)), + Name: fmt.Sprintf("%s Admin Group", netID), NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ netID: { models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)): {}, }, }, - MetaData: "The network group was automatically created by Netmaker.", + MetaData: fmt.Sprintf("User in this group can manage your network `%s` configuration including adding and removing devices.", netID), } var NetworkUserGroup = models.UserGroup{ - ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser)), + ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser)), + Name: fmt.Sprintf("%s User Group", netID), NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ netID: { models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {}, }, }, - MetaData: "The network group was automatically created by Netmaker.", + MetaData: fmt.Sprintf("Users in this group cannot access the admin console, but can connect to nodes in your network `%s` via RAC.", netID), } d, _ = json.Marshal(NetworkAdminGroup) database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) From a954f87c9d51ca2223ff8474b2bcd13ffbdd0328 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 28 Oct 2024 16:53:02 +0400 Subject: [PATCH 108/169] deprecate rag role --- logic/gateway.go | 6 +----- logic/hosts.go | 14 +------------- logic/nodes.go | 4 ---- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/logic/gateway.go b/logic/gateway.go index ab68a4362..3c700d7b0 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -242,11 +242,7 @@ func DeleteIngressGateway(nodeid string) (models.Node, []models.ExtClient, error if err != nil { return models.Node{}, removedClients, err } - host, err := GetHost(node.HostID.String()) - if err != nil { - return models.Node{}, removedClients, err - } - go DeleteRole(models.GetRAGRoleID(node.Network, host.ID.String()), true) + err = SetNetworkNodesLastModified(node.Network) return node, removedClients, err } diff --git a/logic/hosts.go b/logic/hosts.go index f8a310bf3..8fd125c52 100644 --- a/logic/hosts.go +++ b/logic/hosts.go @@ -287,19 +287,7 @@ func UpdateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) currHost.IsStaticPort = newHost.IsStaticPort currHost.IsStatic = newHost.IsStatic currHost.MTU = newHost.MTU - if newHost.Name != currHost.Name { - // update any rag role ids - for _, nodeID := range newHost.Nodes { - node, err := GetNodeByID(nodeID) - if err == nil && node.IsIngressGateway { - role, err := GetRole(models.GetRAGRoleID(node.Network, currHost.ID.String())) - if err == nil { - role.Name = models.GetRAGRoleName(node.Network, newHost.Name) - UpdateRole(role) - } - } - } - } + currHost.Name = newHost.Name if len(newHost.NatType) > 0 && newHost.NatType != currHost.NatType { currHost.NatType = newHost.NatType diff --git a/logic/nodes.go b/logic/nodes.go index 036abcca2..d482ac377 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -196,10 +196,6 @@ func DeleteNode(node *models.Node, purge bool) error { if err := DeleteGatewayExtClients(node.ID.String(), node.Network); err != nil { slog.Error("failed to delete ext clients", "nodeid", node.ID.String(), "error", err.Error()) } - host, err := GetHost(node.HostID.String()) - if err == nil { - go DeleteRole(models.GetRAGRoleID(node.Network, host.ID.String()), true) - } } if node.IsRelayed { // cleanup node from relayednodes on relay node From 2cc54d949c4ed2b9cba66e8bb86c16c1ea4de35b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 08:51:27 +0400 Subject: [PATCH 109/169] remove user role from policy types --- controllers/acls.go | 1 - logic/acls.go | 14 +----------- models/acl.go | 5 ++-- pro/controllers/users.go | 8 +++---- pro/logic/user_mgmt.go | 49 ---------------------------------------- 5 files changed, 7 insertions(+), 70 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 02bdbe5d9..b588aeed1 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -44,7 +44,6 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) { }, SrcGroupTypes: []models.AclGroupType{ models.UserAclID, - //models.UserRoleAclID, models.UserGroupAclID, models.DeviceAclID, }, diff --git a/logic/acls.go b/logic/acls.go index d2d657848..9b077e5ab 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -56,10 +56,6 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { ID: models.UserGroupAclID, Value: "*", }, - // { - // ID: models.UserRoleAclID, - // Value: "*", - // }, }, Dst: []models.AclPolicyTag{{ ID: models.DeviceAclID, @@ -175,9 +171,7 @@ func IsAclPolicyValid(acl models.Acl) bool { if srcI.Value == "*" { continue } - if srcI.ID != models.UserAclID { - // && srcI.ID != models.UserGroupAclID && srcI.ID != models.UserRoleAclID - + if srcI.ID != models.UserAclID && srcI.ID != models.UserGroupAclID { return false } // check if user group is valid @@ -186,12 +180,6 @@ func IsAclPolicyValid(acl models.Acl) bool { if err != nil { return false } - // } else if srcI.ID == models.UserRoleAclID { - - // _, err := GetRole(models.UserRoleID(srcI.Value)) - // if err != nil { - // return false - // } } else if srcI.ID == models.UserGroupAclID { err := IsGroupValid(models.UserGroupID(srcI.Value)) diff --git a/models/acl.go b/models/acl.go index 83007d5e1..f0bc2a6cf 100644 --- a/models/acl.go +++ b/models/acl.go @@ -44,9 +44,8 @@ type AclPolicyTag struct { type AclGroupType string const ( - UserAclID AclGroupType = "user" - UserGroupAclID AclGroupType = "user-group" - //UserRoleAclID AclGroupType = "user-role" + UserAclID AclGroupType = "user" + UserGroupAclID AclGroupType = "user-group" DeviceAclID AclGroupType = "tag" NetmakerIPAclID AclGroupType = "ip" NetmakerSubNetRangeAClID AclGroupType = "ipset" diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 07686fee1..1202a953d 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -834,7 +834,7 @@ func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) { userGws := make(map[string][]models.UserRemoteGws) networks := []models.Network{} networkMap := make(map[string]struct{}) - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) for _, node := range userGwNodes { network, err := logic.GetNetwork(node.Network) if err != nil { @@ -876,7 +876,7 @@ func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request) } userGws := []models.UserRAGs{} - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) for _, node := range userGwNodes { if node.Network != network { continue @@ -931,7 +931,7 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) { return } - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) if _, ok := userGwNodes[remoteGwID]; !ok { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden")) return @@ -1075,7 +1075,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - userGwNodes := proLogic.GetUserRAGNodes(*user) + userGwNodes := proLogic.GetUserRAGNodesV1(*user) for _, extClient := range allextClients { node, ok := userGwNodes[extClient.IngressGatewayID] if !ok { diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 6faa9084c..25413c33b 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -1140,55 +1140,6 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { if netID.String() == "" { return } - // if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin))) { - // defaultUserAcl := models.Acl{ - // ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkAdmin)), - // Name: models.NetworkAdmin.String(), - // Default: true, - // NetworkID: netID, - // RuleType: models.UserPolicy, - // Src: []models.AclPolicyTag{ - // { - // ID: models.UserRoleAclID, - // Value: fmt.Sprintf("%s-%s", netID, models.NetworkAdmin), - // }}, - // Dst: []models.AclPolicyTag{ - // { - // ID: models.DeviceAclID, - // Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), - // }, - // }, - // AllowedDirection: models.TrafficDirectionUni, - // Enabled: true, - // CreatedBy: "auto", - // CreatedAt: time.Now().UTC(), - // } - // logic.InsertAcl(defaultUserAcl) - // } - // if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser))) { - // defaultUserAcl := models.Acl{ - // ID: models.AclID(fmt.Sprintf("%s.%s", netID, models.NetworkUser)), - // Name: models.NetworkUser.String(), - // Default: true, - // NetworkID: netID, - // RuleType: models.UserPolicy, - // Src: []models.AclPolicyTag{ - // { - // ID: models.UserRoleAclID, - // Value: fmt.Sprintf("%s-%s", netID, models.NetworkUser), - // }}, - // Dst: []models.AclPolicyTag{ - // { - // ID: models.DeviceAclID, - // Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName), - // }}, - // AllowedDirection: models.TrafficDirectionUni, - // Enabled: true, - // CreatedBy: "auto", - // CreatedAt: time.Now().UTC(), - // } - // logic.InsertAcl(defaultUserAcl) - // } if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin))) { defaultUserAcl := models.Acl{ From ebc3e90301b47a1ad00e20ce48cd8b77493ad337 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 12:41:40 +0400 Subject: [PATCH 110/169] add extclient egress ranges --- controllers/acls.go | 13 ++--- logic/acls.go | 53 +++++++++---------- logic/extpeers.go | 112 +++++++++++++++++++++++++++++++++-------- logic/peers.go | 3 +- models/acl.go | 18 +------ models/mqtt.go | 17 ++++--- pro/logic/user_mgmt.go | 14 +++--- 7 files changed, 137 insertions(+), 93 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index b588aeed1..49593b785 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -7,6 +7,7 @@ import ( "net/url" "time" + "github.com/google/uuid" "github.com/gorilla/mux" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" @@ -128,7 +129,7 @@ func createAcl(w http.ResponseWriter, r *http.Request) { } acl := req - acl.GetID(req.NetworkID, req.Name) + acl.ID = uuid.New().String() acl.CreatedBy = user.UserName acl.CreatedAt = time.Now().UTC() acl.Default = false @@ -187,14 +188,6 @@ func updateAcl(w http.ResponseWriter, r *http.Request) { } if !acl.Default && updateAcl.NewName != "" { //check if policy exists with same name - id := models.FormatAclID(updateAcl.NetworkID, updateAcl.NewName) - _, err := logic.GetAcl(id) - if err == nil { - logic.ReturnErrorResponse(w, r, - logic.FormatError(errors.New("policy already exists with name "+updateAcl.NewName), "badrequest")) - return - } - updateAcl.ID = id updateAcl.Acl.Name = updateAcl.NewName } err = logic.UpdateAcl(updateAcl.Acl, acl) @@ -218,7 +211,7 @@ func deleteAcl(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("acl id is required"), "badrequest")) return } - acl, err := logic.GetAcl(models.AclID(aclID)) + acl, err := logic.GetAcl(aclID) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return diff --git a/logic/acls.go b/logic/acls.go index 9b077e5ab..fbb3a7e40 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -16,10 +16,11 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { if netID.String() == "" { return } - if !IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes"))) { + if !IsAclExists(fmt.Sprintf("%s.%s", netID, "all-nodes")) { defaultDeviceAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-nodes")), - Name: "all-nodes", + ID: fmt.Sprintf("%s.%s", netID, "all-nodes"), + Name: "All Nodes", + MetaData: "This Policy allows all nodes in the network to communicate with each other", Default: true, NetworkID: netID, RuleType: models.DevicePolicy, @@ -40,11 +41,12 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { } InsertAcl(defaultDeviceAcl) } - if !IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, "all-users"))) { + if !IsAclExists(fmt.Sprintf("%s.%s", netID, "all-users")) { defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-users")), + ID: fmt.Sprintf("%s.%s", netID, "all-users"), Default: true, - Name: "all-users", + Name: "All Users", + MetaData: "This policy gives access to everything in the network for an user", NetworkID: netID, RuleType: models.UserPolicy, Src: []models.AclPolicyTag{ @@ -69,11 +71,11 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { InsertAcl(defaultUserAcl) } - if !IsAclExists(models.AclID(fmt.Sprintf("%s.%s", netID, "all-remote-access-gws"))) { + if !IsAclExists(fmt.Sprintf("%s.%s", netID, "all-remote-access-gws")) { defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s", netID, "all-remote-access-gws")), + ID: fmt.Sprintf("%s.%s", netID, "all-remote-access-gws"), Default: true, - Name: "all-remote-access-gws", + Name: "All Remote Access Gateways", NetworkID: netID, RuleType: models.DevicePolicy, Src: []models.AclPolicyTag{ @@ -115,15 +117,10 @@ func ValidateCreateAclReq(req models.Acl) error { if err != nil { return errors.New("failed to get network details for " + req.NetworkID.String()) } - err = CheckIDSyntax(req.Name) - if err != nil { - return err - } - req.GetID(req.NetworkID, req.Name) - _, err = GetAcl(req.ID) - if err == nil { - return errors.New("acl exists already with name " + req.Name) - } + // err = CheckIDSyntax(req.Name) + // if err != nil { + // return err + // } return nil } @@ -133,13 +130,13 @@ func InsertAcl(a models.Acl) error { if err != nil { return err } - return database.Insert(a.ID.String(), string(d), database.ACLS_TABLE_NAME) + return database.Insert(a.ID, string(d), database.ACLS_TABLE_NAME) } // GetAcl - gets acl info by id -func GetAcl(aID models.AclID) (models.Acl, error) { +func GetAcl(aID string) (models.Acl, error) { a := models.Acl{} - d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID.String()) + d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID) if err != nil { return a, err } @@ -151,7 +148,7 @@ func GetAcl(aID models.AclID) (models.Acl, error) { } // IsAclExists - checks if acl exists -func IsAclExists(aclID models.AclID) bool { +func IsAclExists(aclID string) bool { _, err := GetAcl(aclID) return err == nil } @@ -252,15 +249,11 @@ func UpdateAcl(newAcl, acl models.Acl) error { acl.Dst = newAcl.Dst } acl.Enabled = newAcl.Enabled - if acl.ID != newAcl.ID { - database.DeleteRecord(database.ACLS_TABLE_NAME, acl.ID.String()) - acl.ID = newAcl.ID - } d, err := json.Marshal(acl) if err != nil { return err } - return database.Insert(acl.ID.String(), string(d), database.ACLS_TABLE_NAME) + return database.Insert(acl.ID, string(d), database.ACLS_TABLE_NAME) } // UpsertAcl - upserts acl @@ -269,12 +262,12 @@ func UpsertAcl(acl models.Acl) error { if err != nil { return err } - return database.Insert(acl.ID.String(), string(d), database.ACLS_TABLE_NAME) + return database.Insert(acl.ID, string(d), database.ACLS_TABLE_NAME) } // DeleteAcl - deletes acl policy func DeleteAcl(a models.Acl) error { - return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID.String()) + return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID) } // GetDefaultPolicy - fetches default policy in the network by ruleType @@ -283,7 +276,7 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo if ruleType == models.DevicePolicy { aclID = "all-nodes" } - acl, err := GetAcl(models.AclID(fmt.Sprintf("%s.%s", netID, aclID))) + acl, err := GetAcl(fmt.Sprintf("%s.%s", netID, aclID)) if err != nil { return models.Acl{}, errors.New("default rule not found") } diff --git a/logic/extpeers.go b/logic/extpeers.go index 0e1a70960..a84c3a7ef 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -443,39 +443,62 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { if userNodeI.StaticNode.Address != "" { if !defaultUserPolicy.Enabled { rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, - DstIP: peer.StaticNode.AddressIPNet4().IP, + SrcIP: userNodeI.StaticNode.AddressIPNet4(), + DstIP: peer.StaticNode.AddressIPNet4(), Allow: true, }) } rules = append(rules, models.FwRule{ - SrcIp: peer.StaticNode.AddressIPNet4().IP, - DstIP: userNodeI.StaticNode.AddressIPNet4().IP, + SrcIP: peer.StaticNode.AddressIPNet4(), + DstIP: userNodeI.StaticNode.AddressIPNet4(), Allow: true, }) } if userNodeI.StaticNode.Address6 != "" { if !defaultUserPolicy.Enabled { rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet6().IP, - DstIP: peer.StaticNode.AddressIPNet6().IP, + SrcIP: userNodeI.StaticNode.AddressIPNet6(), + DstIP: peer.StaticNode.AddressIPNet6(), Allow: true, }) } rules = append(rules, models.FwRule{ - SrcIp: peer.StaticNode.AddressIPNet6().IP, - DstIP: userNodeI.StaticNode.AddressIPNet6().IP, + SrcIP: peer.StaticNode.AddressIPNet6(), + DstIP: userNodeI.StaticNode.AddressIPNet6(), Allow: true, }) } + if len(peer.StaticNode.ExtraAllowedIPs) > 0 { + for _, additionalAllowedIPNet := range peer.StaticNode.ExtraAllowedIPs { + _, ipNet, err := net.ParseCIDR(additionalAllowedIPNet) + if err != nil { + continue + } + if ipNet.IP.To4() != nil { + rules = append(rules, models.FwRule{ + SrcIP: userNodeI.StaticNode.AddressIPNet4(), + DstIP: *ipNet, + Allow: true, + }) + } else { + rules = append(rules, models.FwRule{ + SrcIP: userNodeI.StaticNode.AddressIPNet6(), + DstIP: *ipNet, + Allow: true, + }) + } + + } + + } } else { if userNodeI.StaticNode.Address != "" { if !defaultUserPolicy.Enabled { rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet4().IP, - DstIP: peer.Address.IP, + SrcIP: userNodeI.StaticNode.AddressIPNet4(), + DstIP: peer.Address, Allow: true, }) } @@ -483,8 +506,8 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { if userNodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ - SrcIp: userNodeI.StaticNode.AddressIPNet6().IP, - DstIP: peer.Address6.IP, + SrcIP: userNodeI.StaticNode.AddressIPNet6(), + DstIP: peer.Address6, Allow: true, }) } @@ -509,30 +532,53 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { if peer.IsStatic { if nodeI.StaticNode.Address != "" { rules = append(rules, models.FwRule{ - SrcIp: nodeI.StaticNode.AddressIPNet4().IP, - DstIP: peer.StaticNode.AddressIPNet4().IP, + SrcIP: nodeI.StaticNode.AddressIPNet4(), + DstIP: peer.StaticNode.AddressIPNet4(), Allow: true, }) } if nodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ - SrcIp: nodeI.StaticNode.AddressIPNet6().IP, - DstIP: peer.StaticNode.AddressIPNet6().IP, + SrcIP: nodeI.StaticNode.AddressIPNet6(), + DstIP: peer.StaticNode.AddressIPNet6(), Allow: true, }) } + if len(peer.StaticNode.ExtraAllowedIPs) > 0 { + for _, additionalAllowedIPNet := range peer.StaticNode.ExtraAllowedIPs { + _, ipNet, err := net.ParseCIDR(additionalAllowedIPNet) + if err != nil { + continue + } + if ipNet.IP.To4() != nil { + rules = append(rules, models.FwRule{ + SrcIP: nodeI.StaticNode.AddressIPNet4(), + DstIP: *ipNet, + Allow: true, + }) + } else { + rules = append(rules, models.FwRule{ + SrcIP: nodeI.StaticNode.AddressIPNet6(), + DstIP: *ipNet, + Allow: true, + }) + } + + } + + } } else { if nodeI.StaticNode.Address != "" { rules = append(rules, models.FwRule{ - SrcIp: nodeI.StaticNode.AddressIPNet4().IP, - DstIP: peer.Address.IP, + SrcIP: nodeI.StaticNode.AddressIPNet4(), + DstIP: peer.Address, Allow: true, }) } if nodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ - SrcIp: nodeI.StaticNode.AddressIPNet6().IP, - DstIP: peer.Address6.IP, + SrcIP: nodeI.StaticNode.AddressIPNet6(), + DstIP: peer.Address6, Allow: true, }) } @@ -642,8 +688,30 @@ func getExtPeerEgressRoute(node models.Node, extPeer models.ExtClient) (egressRo return } -func getExtpeersExtraRoutes(node models.Node, network string) (egressRoutes []models.EgressNetworkRoutes) { - extPeers, err := GetNetworkExtClients(network) +func getExtpeerEgressRanges(node models.Node) (ranges []net.IPNet) { + extPeers, err := GetNetworkExtClients(node.Network) + if err != nil { + return + } + for _, extPeer := range extPeers { + if len(extPeer.ExtraAllowedIPs) == 0 { + continue + } + if !IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), node) { + continue + } + for _, allowedRange := range extPeer.ExtraAllowedIPs { + _, ipnet, err := net.ParseCIDR(allowedRange) + if err == nil { + ranges = append(ranges, *ipnet) + } + } + } + +} + +func getExtpeersExtraRoutes(node models.Node) (egressRoutes []models.EgressNetworkRoutes) { + extPeers, err := GetNetworkExtClients(node.Network) if err != nil { return } diff --git a/logic/peers.go b/logic/peers.go index 3589f005a..339d9f04c 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -183,7 +183,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N }) } if peer.IsIngressGateway { - hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(node, peer.Network)...) + hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(node)...) } _, isFailOverPeer := node.FailOverPeers[peer.ID.String()] if servercfg.IsPro { @@ -301,6 +301,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N Network6: node.NetworkRange6, AllowAll: defaultDevicePolicy.Enabled && defaultUserPolicy.Default, StaticNodeIps: GetStaticNodeIps(node), + EgressRanges: getExtpeerEgressRanges(node), Rules: GetFwRulesOnIngressGateway(node), } hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = ingFwUpdate diff --git a/models/acl.go b/models/acl.go index f0bc2a6cf..d8c302ca9 100644 --- a/models/acl.go +++ b/models/acl.go @@ -1,24 +1,9 @@ package models import ( - "fmt" "time" ) -type AclID string - -func (aID AclID) String() string { - return string(aID) -} - -func (a *Acl) GetID(netID NetworkID, name string) { - a.ID = AclID(fmt.Sprintf("%s.%s", netID.String(), name)) -} - -func FormatAclID(netID NetworkID, name string) AclID { - return AclID(fmt.Sprintf("%s.%s", netID.String(), name)) -} - // AllowedTrafficDirection - allowed direction of traffic type AllowedTrafficDirection int @@ -66,8 +51,9 @@ type AclPolicy struct { } type Acl struct { - ID AclID `json:"id"` + ID string `json:"id"` Default bool `json:"default"` + MetaData string `json:"meta_data"` Name string `json:"name"` NetworkID NetworkID `json:"network_id"` RuleType AclPolicyType `json:"policy_type"` diff --git a/models/mqtt.go b/models/mqtt.go index 3ff6043f7..f8d594daa 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -27,19 +27,20 @@ type HostPeerUpdate struct { } type FwRule struct { - SrcIp net.IP - DstIP net.IP + SrcIP net.IPNet + DstIP net.IPNet Allow bool } // IngressInfo - struct for ingress info type IngressInfo struct { - 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"` + 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"` + EgressRanges []net.IPNet `json:"egress_ranges"` } // EgressInfo - struct for egress info diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 25413c33b..c40afa676 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -1141,10 +1141,11 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { return } - if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin))) { + if !logic.IsAclExists(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin)) { defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin)), - Name: fmt.Sprintf("%s-grp", models.NetworkAdmin), + ID: fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin), + Name: "Network Admin", + MetaData: "This Policy allows all network admins to communicate with all remote access gateways", Default: true, NetworkID: netID, RuleType: models.UserPolicy, @@ -1166,10 +1167,11 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { logic.InsertAcl(defaultUserAcl) } - if !logic.IsAclExists(models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser))) { + if !logic.IsAclExists(fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser)) { defaultUserAcl := models.Acl{ - ID: models.AclID(fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser)), - Name: fmt.Sprintf("%s-grp", models.NetworkUser), + ID: fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser), + Name: "Network User", + MetaData: "This Policy allows all network users to communicate with all remote access gateways", Default: true, NetworkID: netID, RuleType: models.UserPolicy, From dc24e359cb9b536bb1c704185ab53994971ba8bf Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 12:42:45 +0400 Subject: [PATCH 111/169] fix return error --- logic/extpeers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index a84c3a7ef..2fb35c5e3 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -707,7 +707,7 @@ func getExtpeerEgressRanges(node models.Node) (ranges []net.IPNet) { } } } - + return } func getExtpeersExtraRoutes(node models.Node) (egressRoutes []models.EgressNetworkRoutes) { From 8e5a3d02c36c1691bdf81f7913af2e24147a63b7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 12:56:11 +0400 Subject: [PATCH 112/169] set egress6 ranges --- logic/extpeers.go | 9 +++++++-- logic/peers.go | 2 +- models/mqtt.go | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 2fb35c5e3..fd5e98b2b 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -688,7 +688,7 @@ func getExtPeerEgressRoute(node models.Node, extPeer models.ExtClient) (egressRo return } -func getExtpeerEgressRanges(node models.Node) (ranges []net.IPNet) { +func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []net.IPNet) { extPeers, err := GetNetworkExtClients(node.Network) if err != nil { return @@ -703,7 +703,12 @@ func getExtpeerEgressRanges(node models.Node) (ranges []net.IPNet) { for _, allowedRange := range extPeer.ExtraAllowedIPs { _, ipnet, err := net.ParseCIDR(allowedRange) if err == nil { - ranges = append(ranges, *ipnet) + if ipnet.IP.To4() != nil { + ranges = append(ranges, *ipnet) + } else { + ranges6 = append(ranges6, *ipnet) + } + } } } diff --git a/logic/peers.go b/logic/peers.go index 339d9f04c..5e86b37a3 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -301,9 +301,9 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N Network6: node.NetworkRange6, AllowAll: defaultDevicePolicy.Enabled && defaultUserPolicy.Default, StaticNodeIps: GetStaticNodeIps(node), - EgressRanges: getExtpeerEgressRanges(node), Rules: GetFwRulesOnIngressGateway(node), } + ingFwUpdate.EgressRanges, ingFwUpdate.EgressRanges6 = getExtpeerEgressRanges(node) hostPeerUpdate.FwUpdate.IngressInfo[node.ID.String()] = ingFwUpdate } hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...) diff --git a/models/mqtt.go b/models/mqtt.go index f8d594daa..395820a93 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -41,6 +41,7 @@ type IngressInfo struct { Rules []FwRule `json:"rules"` AllowAll bool `json:"allow_all"` EgressRanges []net.IPNet `json:"egress_ranges"` + EgressRanges6 []net.IPNet `json:"egress_ranges6"` } // EgressInfo - struct for egress info From a0735e8203ddbaadbafd9c3546d2342929a9acc2 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 12:59:24 +0400 Subject: [PATCH 113/169] chnage egress range type to string --- logic/extpeers.go | 6 +++--- models/mqtt.go | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index fd5e98b2b..9ba504094 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -688,7 +688,7 @@ func getExtPeerEgressRoute(node models.Node, extPeer models.ExtClient) (egressRo return } -func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []net.IPNet) { +func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []string) { extPeers, err := GetNetworkExtClients(node.Network) if err != nil { return @@ -704,9 +704,9 @@ func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []net.IPNet) { _, ipnet, err := net.ParseCIDR(allowedRange) if err == nil { if ipnet.IP.To4() != nil { - ranges = append(ranges, *ipnet) + ranges = append(ranges, allowedRange) } else { - ranges6 = append(ranges6, *ipnet) + ranges6 = append(ranges6, allowedRange) } } diff --git a/models/mqtt.go b/models/mqtt.go index 395820a93..9c6abd67c 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -34,14 +34,14 @@ type FwRule struct { // IngressInfo - struct for ingress info type IngressInfo struct { - 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"` - EgressRanges []net.IPNet `json:"egress_ranges"` - EgressRanges6 []net.IPNet `json:"egress_ranges6"` + 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"` + EgressRanges []string `json:"egress_ranges"` + EgressRanges6 []string `json:"egress_ranges6"` } // EgressInfo - struct for egress info From 2ee3cefc189a383a9998c208ac814f7893694414 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 13:00:28 +0400 Subject: [PATCH 114/169] Revert "chnage egress range type to string" This reverts commit a0735e8203ddbaadbafd9c3546d2342929a9acc2. --- logic/extpeers.go | 6 +++--- models/mqtt.go | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 9ba504094..fd5e98b2b 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -688,7 +688,7 @@ func getExtPeerEgressRoute(node models.Node, extPeer models.ExtClient) (egressRo return } -func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []string) { +func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []net.IPNet) { extPeers, err := GetNetworkExtClients(node.Network) if err != nil { return @@ -704,9 +704,9 @@ func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []string) { _, ipnet, err := net.ParseCIDR(allowedRange) if err == nil { if ipnet.IP.To4() != nil { - ranges = append(ranges, allowedRange) + ranges = append(ranges, *ipnet) } else { - ranges6 = append(ranges6, allowedRange) + ranges6 = append(ranges6, *ipnet) } } diff --git a/models/mqtt.go b/models/mqtt.go index 9c6abd67c..395820a93 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -34,14 +34,14 @@ type FwRule struct { // IngressInfo - struct for ingress info type IngressInfo struct { - 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"` - EgressRanges []string `json:"egress_ranges"` - EgressRanges6 []string `json:"egress_ranges6"` + 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"` + EgressRanges []net.IPNet `json:"egress_ranges"` + EgressRanges6 []net.IPNet `json:"egress_ranges6"` } // EgressInfo - struct for egress info From 5c15f3d9ebd6703ab922fda52e803496d9b2966d Mon Sep 17 00:00:00 2001 From: Max Ma Date: Tue, 29 Oct 2024 00:53:45 -0900 Subject: [PATCH 115/169] NET-1603: Manage DNS NM changes (#3124) * add switch for manage dns * manage DNS sync publish * add dns sync api * add manageDNS field in peerUpdate * add default dns for extClent if manage dns enabled * add DEFAULT_DOMAIN for internal DNS lookup * move DNSSync to peerUpdate * fix empty host in network issue * sync up dns when custom dns add/delete * fix custom DNS ip4/ipv6 validator issue --- config/config.go | 2 ++ controllers/dns.go | 48 +++++++++++++++++++++++++++++++ controllers/ext_client.go | 16 +++++++++++ logic/peers.go | 1 + models/dnsEntry.go | 4 +-- models/mqtt.go | 1 + models/structs.go | 2 ++ mq/publishers.go | 56 ++++++++++++++++++++++++++++++++++++ scripts/netmaker.default.env | 2 ++ servercfg/serverconf.go | 38 +++++++++++++++++++++++- servercfg/serverconf_test.go | 29 +++++++++++++++++++ 11 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 servercfg/serverconf_test.go diff --git a/config/config.go b/config/config.go index 061109f6d..f9acaf980 100644 --- a/config/config.go +++ b/config/config.go @@ -100,6 +100,8 @@ type ServerConfig struct { SmtpHost string `json:"smtp_host"` SmtpPort int `json:"smtp_port"` MetricInterval string `yaml:"metric_interval"` + ManageDNS bool `yaml:"manage_dns"` + DefaultDomain string `yaml:"default_domain"` } // SQLConfig - Generic SQL Config diff --git a/controllers/dns.go b/controllers/dns.go index b1fc71fc3..cc1d70abf 100644 --- a/controllers/dns.go +++ b/controllers/dns.go @@ -11,6 +11,7 @@ import ( "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/servercfg" ) @@ -24,6 +25,8 @@ func dnsHandlers(r *mux.Router) { Methods(http.MethodGet) r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))). Methods(http.MethodGet) + r.HandleFunc("/api/dns/adm/{network}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncDNS))). + Methods(http.MethodPost) r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))). Methods(http.MethodPost) r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))). @@ -147,6 +150,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) { var entry models.DNSEntry var params = mux.Vars(r) + netID := params["network"] _ = json.NewDecoder(r.Body).Decode(&entry) entry.Network = params["network"] @@ -176,6 +180,10 @@ func createDNS(w http.ResponseWriter, r *http.Request) { } } + if servercfg.GetManageDNS() { + mq.SendDNSSyncByNetwork(netID) + } + logger.Log(1, "new DNS record added:", entry.Name) logger.Log(2, r.Header.Get("user"), fmt.Sprintf("DNS entry is set: %+v", entry)) @@ -197,6 +205,7 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) { // get params var params = mux.Vars(r) + netID := params["network"] entrytext := params["domain"] + "." + params["network"] err := logic.DeleteDNS(params["domain"], params["network"]) @@ -216,6 +225,10 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) { } } + if servercfg.GetManageDNS() { + mq.SendDNSSyncByNetwork(netID) + } + json.NewEncoder(w).Encode(entrytext + " deleted.") } @@ -264,3 +277,38 @@ func pushDNS(w http.ResponseWriter, r *http.Request) { logger.Log(1, r.Header.Get("user"), "pushed DNS updates to nameserver") json.NewEncoder(w).Encode("DNS Pushed to CoreDNS") } + +// @Summary Sync DNS entries for a given network +// @Router /api/dns/adm/{network}/sync [post] +// @Tags DNS +// @Accept json +// @Success 200 {string} string "DNS Sync completed successfully" +// @Failure 400 {object} models.ErrorResponse +// @Failure 500 {object} models.ErrorResponse +func syncDNS(w http.ResponseWriter, r *http.Request) { + // Set header + w.Header().Set("Content-Type", "application/json") + if !servercfg.GetManageDNS() { + logic.ReturnErrorResponse( + w, + r, + logic.FormatError(errors.New("manage DNS is set to false"), "badrequest"), + ) + return + } + var params = mux.Vars(r) + netID := params["network"] + k, err := logic.GetDNS(netID) + if err == nil && len(k) > 0 { + err = mq.PushSyncDNS(k) + } + + if err != nil { + logger.Log(0, r.Header.Get("user"), + fmt.Sprintf("Failed to Sync DNS entries to network %s: %v", netID, err)) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + logger.Log(1, r.Header.Get("user"), "DNS Sync complelted successfully") + json.NewEncoder(w).Encode("DNS Sync completed successfully") +} diff --git a/controllers/ext_client.go b/controllers/ext_client.go index 09c5f5d52..988306e11 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -287,6 +287,22 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { } else if gwnode.IngressDNS != "" { defaultDNS = "DNS = " + gwnode.IngressDNS } + if servercfg.GetManageDNS() { + if gwnode.Address6.IP != nil { + if defaultDNS == "" { + defaultDNS = "DNS = " + gwnode.Address6.IP.String() + } else { + defaultDNS = defaultDNS + ", " + gwnode.Address6.IP.String() + } + } + if gwnode.Address.IP != nil { + if defaultDNS == "" { + defaultDNS = "DNS = " + gwnode.Address.IP.String() + } else { + defaultDNS = defaultDNS + ", " + gwnode.Address.IP.String() + } + } + } defaultMTU := 1420 if host.MTU != 0 { diff --git a/logic/peers.go b/logic/peers.go index 77e76a2a9..87d477b93 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -391,6 +391,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N } } + hostPeerUpdate.ManageDNS = servercfg.GetManageDNS() return hostPeerUpdate, nil } diff --git a/models/dnsEntry.go b/models/dnsEntry.go index 11e9dd6b4..596d92258 100644 --- a/models/dnsEntry.go +++ b/models/dnsEntry.go @@ -42,8 +42,8 @@ type DNSUpdate struct { // DNSEntry - a DNS entry represented as struct type DNSEntry struct { - Address string `json:"address" validate:"ip"` - Address6 string `json:"address6"` + Address string `json:"address" validate:"omitempty,ip"` + Address6 string `json:"address6" validate:"omitempty,ip"` Name string `json:"name" validate:"required,name_unique,min=1,max=192,whitespace"` Network string `json:"network" validate:"network_exists"` } diff --git a/models/mqtt.go b/models/mqtt.go index c0d52d9c2..cb7cc4429 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -24,6 +24,7 @@ type HostPeerUpdate struct { FwUpdate FwUpdate `json:"fw_update"` ReplacePeers bool `json:"replace_peers"` EndpointDetection bool `json:"endpoint_detection"` + ManageDNS bool `yaml:"manage_dns"` } // IngressInfo - struct for ingress info diff --git a/models/structs.go b/models/structs.go index 3cc20ca47..2a723adf9 100644 --- a/models/structs.go +++ b/models/structs.go @@ -266,6 +266,8 @@ type ServerConfig struct { IsPro bool `yaml:"isee" json:"Is_EE"` TrafficKey []byte `yaml:"traffickey"` MetricInterval string `yaml:"metric_interval"` + ManageDNS bool `yaml:"manage_dns"` + DefaultDomain string `yaml:"default_domain"` } // User.NameInCharset - returns if name is in charset below or not diff --git a/mq/publishers.go b/mq/publishers.go index 099eb4a05..3b47390a8 100644 --- a/mq/publishers.go +++ b/mq/publishers.go @@ -23,6 +23,10 @@ func PublishPeerUpdate(replacePeers bool) error { return nil } + if servercfg.GetManageDNS() { + sendDNSSync() + } + hosts, err := logic.GetAllHosts() if err != nil { logger.Log(1, "err getting all hosts", err.Error()) @@ -249,3 +253,55 @@ func sendPeers() { } } } + +func SendDNSSyncByNetwork(network string) error { + + k, err := logic.GetDNS(network) + if err == nil && len(k) > 0 { + err = PushSyncDNS(k) + if err != nil { + slog.Warn("error publishing dns entry data for network ", network, err.Error()) + } + } + + return err +} + +func sendDNSSync() error { + + networks, err := logic.GetNetworks() + if err == nil && len(networks) > 0 { + for _, v := range networks { + k, err := logic.GetDNS(v.NetID) + if err == nil && len(k) > 0 { + err = PushSyncDNS(k) + if err != nil { + slog.Warn("error publishing dns entry data for network ", v.NetID, err.Error()) + } + } + } + return nil + } + return err +} + +func PushSyncDNS(dnsEntries []models.DNSEntry) error { + logger.Log(2, "----> Pushing Sync DNS") + data, err := json.Marshal(dnsEntries) + if err != nil { + return errors.New("failed to marshal DNS entries: " + err.Error()) + } + if mqclient == nil || !mqclient.IsConnectionOpen() { + return errors.New("cannot publish ... mqclient not connected") + } + if token := mqclient.Publish(fmt.Sprintf("host/dns/sync/%s", dnsEntries[0].Network), 0, true, data); !token.WaitTimeout(MQ_TIMEOUT*time.Second) || token.Error() != nil { + var err error + if token.Error() == nil { + err = errors.New("connection timeout") + } else { + err = token.Error() + } + return err + } + return nil +} diff --git a/scripts/netmaker.default.env b/scripts/netmaker.default.env index 26bb1bb98..e66c2e93c 100644 --- a/scripts/netmaker.default.env +++ b/scripts/netmaker.default.env @@ -90,4 +90,6 @@ EMAIL_SENDER_PASSWORD= PEER_UPDATE_BATCH=true # batch peer update size when PEER_UPDATE_BATCH is enabled PEER_UPDATE_BATCH_SIZE=50 +# default domain for internal DNS lookup +DEFAULT_DOMAIN=netmaker.hosted diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index 6736d0c59..b9955b042 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -5,13 +5,14 @@ import ( "io" "net/http" "os" + "regexp" "strconv" "strings" "time" "github.com/gravitl/netmaker/config" - "github.com/gravitl/netmaker/models" + "golang.org/x/exp/slog" ) // EmqxBrokerType denotes the broker type for EMQX MQTT @@ -92,6 +93,8 @@ func GetServerConfig() config.ServerConfig { cfg.JwtValidityDuration = GetJwtValidityDuration() cfg.RacAutoDisable = GetRacAutoDisable() cfg.MetricInterval = GetMetricInterval() + cfg.ManageDNS = GetManageDNS() + cfg.DefaultDomain = GetDefaultDomain() return cfg } @@ -136,6 +139,8 @@ func GetServerInfo() models.ServerConfig { cfg.Version = GetVersion() cfg.IsPro = IsPro cfg.MetricInterval = GetMetricInterval() + cfg.ManageDNS = GetManageDNS() + cfg.DefaultDomain = GetDefaultDomain() return cfg } @@ -650,6 +655,37 @@ func GetMetricInterval() string { return mi } +// GetManageDNS - if manage DNS enabled or not +func GetManageDNS() bool { + enabled := true + if os.Getenv("MANAGE_DNS") != "" { + enabled = os.Getenv("MANAGE_DNS") == "true" + } + return enabled +} + +// GetDefaultDomain - get the default domain +func GetDefaultDomain() string { + //default netmaker.hosted + domain := "netmaker.hosted" + if os.Getenv("DEFAULT_DOMAIN") != "" { + if validateDomain(os.Getenv("DEFAULT_DOMAIN")) { + domain = os.Getenv("DEFAULT_DOMAIN") + } else { + slog.Warn("invalid value, set to default domain: netmaker.hosted", "warn", os.Getenv("DEFAULT_DOMAIN")) + } + } + return domain +} + +func validateDomain(domain string) bool { + domainPattern := `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}` + + exp := regexp.MustCompile("^" + domainPattern + "$") + + return exp.MatchString(domain) +} + // GetBatchPeerUpdate - if batch peer update func GetBatchPeerUpdate() bool { enabled := true diff --git a/servercfg/serverconf_test.go b/servercfg/serverconf_test.go new file mode 100644 index 000000000..2e8e3de5c --- /dev/null +++ b/servercfg/serverconf_test.go @@ -0,0 +1,29 @@ +package servercfg + +import ( + "testing" + + "github.com/matryer/is" +) + +func TestValidateDomain(t *testing.T) { + + t.Run("", func(t *testing.T) { + is := is.New(t) + valid := validateDomain("netmaker.hosted") + is.Equal(valid, true) + }) + + t.Run("", func(t *testing.T) { + is := is.New(t) + valid := validateDomain("ipv4test1.hosted") + is.Equal(valid, true) + }) + + t.Run("", func(t *testing.T) { + is := is.New(t) + valid := validateDomain("ip_4?") + is.Equal(valid, false) + }) + +} From ffd0133468b13bf47c0b939e629235708d87b52b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 15:28:25 +0400 Subject: [PATCH 116/169] add middleware acl check --- controllers/acls.go | 2 +- controllers/middleware.go | 4 +++- pro/logic/user_mgmt.go | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index 49593b785..ee9777784 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -81,7 +81,7 @@ func aclDebug(w http.ResponseWriter, r *http.Request) { // @Success 200 {array} models.SuccessResponse // @Failure 500 {object} models.ErrorResponse func getAcls(w http.ResponseWriter, r *http.Request) { - netID, _ := url.QueryUnescape(r.URL.Query().Get("network")) + netID := r.URL.Query().Get("network") if netID == "" { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network id param is missing"), "badrequest")) return diff --git a/controllers/middleware.go b/controllers/middleware.go index 8c014fca8..283dbba65 100644 --- a/controllers/middleware.go +++ b/controllers/middleware.go @@ -29,6 +29,9 @@ func userMiddleWare(handler http.Handler) http.Handler { r.Header.Set("TARGET_RSRC_ID", "") r.Header.Set("RAC", "") r.Header.Set("NET_ID", params["network"]) + if r.URL.Query().Get("network") != "" { + r.Header.Set("NET_ID", r.URL.Query().Get("network")) + } if strings.Contains(route, "hosts") || strings.Contains(route, "nodes") { r.Header.Set("TARGET_RSRC", models.HostRsrc.String()) } @@ -105,7 +108,6 @@ func userMiddleWare(handler http.Handler) http.Handler { r.Header.Get("TARGET_RSRC") == models.UserRsrc.String()) { r.Header.Set("IS_GLOBAL_ACCESS", "yes") } - r.Header.Set("RSRC_TYPE", r.Header.Get("TARGET_RSRC")) handler.ServeHTTP(w, r) }) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index c40afa676..ce0f905c7 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -85,7 +85,7 @@ func UserGroupsInit() { ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin)), Default: true, Name: "Network Admin Group", - MetaData: "Users in this group can manage all your networks configuration including adding and removing devices.", + MetaData: "Users in this group can manage all your networks configuration.", NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ models.NetworkID("*"): { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)): {}, @@ -116,7 +116,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)), Name: fmt.Sprintf("%s Admin", netID), - MetaData: fmt.Sprintf("Users with this role can manage your network `%s` configuration including adding and removing devices.", netID), + MetaData: fmt.Sprintf("Users with this role can manage your network `%s` configuration.", netID), Default: true, NetworkID: netID, FullAccess: true, From 0246a7e32d54c8d1180b071c32fe021b81c9067a Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 16:29:57 +0400 Subject: [PATCH 117/169] add global grp to default acl policy --- pro/logic/user_mgmt.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index ce0f905c7..a08bcd926 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -1153,7 +1153,12 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { { ID: models.UserGroupAclID, Value: fmt.Sprintf("%s-%s-grp", netID, models.NetworkAdmin), - }}, + }, + { + ID: models.UserGroupAclID, + Value: "global-network-admin-grp", + }, + }, Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, @@ -1179,7 +1184,13 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { { ID: models.UserGroupAclID, Value: fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser), - }}, + }, + { + ID: models.UserGroupAclID, + Value: "global-network-user-grp", + }, + }, + Dst: []models.AclPolicyTag{ { ID: models.DeviceAclID, @@ -1192,4 +1203,5 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { } logic.InsertAcl(defaultUserAcl) } + } From 28523147626a67db5737db1532c26d8a10221138 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 20:24:31 +0400 Subject: [PATCH 118/169] fix global network role access --- pro/logic/security.go | 9 +++++++++ pro/logic/user_mgmt.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pro/logic/security.go b/pro/logic/security.go index 0bda7e026..fbe0105d8 100644 --- a/pro/logic/security.go +++ b/pro/logic/security.go @@ -82,8 +82,17 @@ func NetworkPermissionsCheck(username string, r *http.Request) error { } } for groupID := range user.UserGroups { + userG, err := GetUserGroup(groupID) if err == nil { + if netRoles, ok := userG.NetworkRoles[models.AllNetworks]; ok { + for netRoleID := range netRoles { + err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID, netID) + if err == nil { + return nil + } + } + } netRoles := userG.NetworkRoles[models.NetworkID(netID)] for netRoleID := range netRoles { err = checkNetworkAccessPermissions(netRoleID, username, r.Method, targetRsrc, targetRsrcID, netID) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index a08bcd926..f32bd63b2 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -87,7 +87,7 @@ func UserGroupsInit() { Name: "Network Admin Group", MetaData: "Users in this group can manage all your networks configuration.", NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ - models.NetworkID("*"): { + models.AllNetworks: { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)): {}, }, }, From ea46ea537856020d5993804fbe2fb908bd0efcc7 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 29 Oct 2024 22:57:58 +0400 Subject: [PATCH 119/169] fix extclient allowed Ips --- logic/clients.go | 2 +- logic/extpeers.go | 2 +- pro/logic/ext_acls.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/logic/clients.go b/logic/clients.go index 7331ee615..d9eca8c9d 100644 --- a/logic/clients.go +++ b/logic/clients.go @@ -32,7 +32,7 @@ var ( slog.Error("failed to get network acls", "error", err) return err } - networkAcls[acls.AclID(ec.ClientID)] = acls.ACL{} + networkAcls[acls.AclID(ec.ClientID)] = make(acls.ACL) for objId := range networkAcls { networkAcls[objId][acls.AclID(ec.ClientID)] = acls.Allowed networkAcls[acls.AclID(ec.ClientID)][objId] = acls.Allowed diff --git a/logic/extpeers.go b/logic/extpeers.go index fd5e98b2b..0a9dbc00c 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -69,7 +69,7 @@ func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) { } } } - extclients := GetGwExtclients(client.IngressGatewayID, client.Network) + extclients, _ := GetNetworkExtClients(client.Network) for _, extclient := range extclients { if extclient.ClientID == client.ClientID { continue diff --git a/pro/logic/ext_acls.go b/pro/logic/ext_acls.go index 6ea62dd41..3c626820c 100644 --- a/pro/logic/ext_acls.go +++ b/pro/logic/ext_acls.go @@ -62,7 +62,7 @@ func SetClientDefaultACLs(ec *models.ExtClient) error { slog.Error("failed to get network acls", "error", err) return err } - networkAcls[acls.AclID(ec.ClientID)] = acls.ACL{} + networkAcls[acls.AclID(ec.ClientID)] = make(acls.ACL) for i := range networkNodes { currNode := networkNodes[i] if network.DefaultACL == "no" || currNode.DefaultACL == "no" { From cd669774c043de8f273cf9fdf8ffc73ef4cc68f9 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 10:21:34 +0400 Subject: [PATCH 120/169] fix node addr mask --- logic/extpeers.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/logic/extpeers.go b/logic/extpeers.go index 0a9dbc00c..fcb422243 100644 --- a/logic/extpeers.go +++ b/logic/extpeers.go @@ -498,7 +498,10 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { if !defaultUserPolicy.Enabled { rules = append(rules, models.FwRule{ SrcIP: userNodeI.StaticNode.AddressIPNet4(), - DstIP: peer.Address, + DstIP: net.IPNet{ + IP: peer.Address.IP, + Mask: net.CIDRMask(32, 32), + }, Allow: true, }) } @@ -507,7 +510,10 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { if userNodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ SrcIP: userNodeI.StaticNode.AddressIPNet6(), - DstIP: peer.Address6, + DstIP: net.IPNet{ + IP: peer.Address6.IP, + Mask: net.CIDRMask(128, 128), + }, Allow: true, }) } @@ -571,14 +577,20 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { if nodeI.StaticNode.Address != "" { rules = append(rules, models.FwRule{ SrcIP: nodeI.StaticNode.AddressIPNet4(), - DstIP: peer.Address, + DstIP: net.IPNet{ + IP: peer.Address.IP, + Mask: net.CIDRMask(32, 32), + }, Allow: true, }) } if nodeI.StaticNode.Address6 != "" { rules = append(rules, models.FwRule{ SrcIP: nodeI.StaticNode.AddressIPNet6(), - DstIP: peer.Address6, + DstIP: net.IPNet{ + IP: peer.Address6.IP, + Mask: net.CIDRMask(128, 128), + }, Allow: true, }) } From 2426b5fd39a3c6ebb57e6b343c068a9290c6634e Mon Sep 17 00:00:00 2001 From: Max Ma Date: Tue, 29 Oct 2024 22:48:57 -0900 Subject: [PATCH 121/169] fix metric bytes sent/recv issue (#3166) --- models/metrics.go | 20 +++++++++++--------- pro/logic/metrics.go | 13 ++++++++----- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/models/metrics.go b/models/metrics.go index 686e3e969..459c7f17c 100644 --- a/models/metrics.go +++ b/models/metrics.go @@ -14,15 +14,17 @@ type Metrics struct { // Metric - holds a metric for data between nodes type Metric struct { - NodeName string `json:"node_name" bson:"node_name" yaml:"node_name"` - Uptime int64 `json:"uptime" bson:"uptime" yaml:"uptime"` - TotalTime int64 `json:"totaltime" bson:"totaltime" yaml:"totaltime"` - Latency int64 `json:"latency" bson:"latency" yaml:"latency"` - TotalReceived int64 `json:"totalreceived" bson:"totalreceived" yaml:"totalreceived"` - TotalSent int64 `json:"totalsent" bson:"totalsent" yaml:"totalsent"` - ActualUptime time.Duration `json:"actualuptime" bson:"actualuptime" yaml:"actualuptime"` - PercentUp float64 `json:"percentup" bson:"percentup" yaml:"percentup"` - Connected bool `json:"connected" bson:"connected" yaml:"connected"` + NodeName string `json:"node_name" bson:"node_name" yaml:"node_name"` + Uptime int64 `json:"uptime" bson:"uptime" yaml:"uptime"` + TotalTime int64 `json:"totaltime" bson:"totaltime" yaml:"totaltime"` + Latency int64 `json:"latency" bson:"latency" yaml:"latency"` + TotalReceived int64 `json:"totalreceived" bson:"totalreceived" yaml:"totalreceived"` + LastTotalReceived int64 `json:"lasttotalreceived" bson:"lasttotalreceived" yaml:"lasttotalreceived"` + TotalSent int64 `json:"totalsent" bson:"totalsent" yaml:"totalsent"` + LastTotalSent int64 `json:"lasttotalsent" bson:"lasttotalsent" yaml:"lasttotalsent"` + ActualUptime time.Duration `json:"actualuptime" bson:"actualuptime" yaml:"actualuptime"` + PercentUp float64 `json:"percentup" bson:"percentup" yaml:"percentup"` + Connected bool `json:"connected" bson:"connected" yaml:"connected"` } // IDandAddr - struct to hold ID and primary Address diff --git a/pro/logic/metrics.go b/pro/logic/metrics.go index dfcd4d6a2..81e61018c 100644 --- a/pro/logic/metrics.go +++ b/pro/logic/metrics.go @@ -2,7 +2,6 @@ package logic import ( "encoding/json" - "math" "sync" "time" @@ -209,15 +208,17 @@ func updateNodeMetrics(currentNode *models.Node, newMetrics *models.Metrics) { currMetric.TotalTime += oldMetric.TotalTime currMetric.Uptime += oldMetric.Uptime // get the total uptime for this connection - if currMetric.TotalReceived < oldMetric.TotalReceived { + totalRecv := currMetric.TotalReceived + totalSent := currMetric.TotalSent + if currMetric.TotalReceived < oldMetric.TotalReceived && currMetric.TotalReceived < oldMetric.LastTotalReceived { currMetric.TotalReceived += oldMetric.TotalReceived } else { - currMetric.TotalReceived += int64(math.Abs(float64(currMetric.TotalReceived) - float64(oldMetric.TotalReceived))) + currMetric.TotalReceived = currMetric.TotalReceived - oldMetric.LastTotalReceived + oldMetric.TotalReceived } - if currMetric.TotalSent < oldMetric.TotalSent { + if currMetric.TotalSent < oldMetric.TotalSent && currMetric.TotalSent < oldMetric.LastTotalSent { currMetric.TotalSent += oldMetric.TotalSent } else { - currMetric.TotalSent += int64(math.Abs(float64(currMetric.TotalSent) - float64(oldMetric.TotalSent))) + currMetric.TotalSent = currMetric.TotalSent - oldMetric.LastTotalSent + oldMetric.TotalSent } if currMetric.Uptime == 0 || currMetric.TotalTime == 0 { @@ -228,6 +229,8 @@ func updateNodeMetrics(currentNode *models.Node, newMetrics *models.Metrics) { totalUpMinutes := currMetric.Uptime * ncutils.CheckInInterval currMetric.ActualUptime = time.Duration(totalUpMinutes) * time.Minute delete(oldMetrics.Connectivity, k) // remove from old data + currMetric.LastTotalReceived = totalRecv + currMetric.LastTotalSent = totalSent newMetrics.Connectivity[k] = currMetric } From 0ddbf7958e6a357a12e9a912d9e70a50ac3777a9 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 12:02:42 +0400 Subject: [PATCH 122/169] fix rebase errors --- logic/networks.go | 1 + migrate/migrate.go | 1 + 2 files changed, 2 insertions(+) diff --git a/logic/networks.go b/logic/networks.go index 0cee5603c..1a50fa791 100644 --- a/logic/networks.go +++ b/logic/networks.go @@ -240,6 +240,7 @@ func CreateNetwork(network models.Network) (models.Network, error) { time.Time{}, []string{network.NetID}, []string{network.NetID}, + []models.TagID{}, true, uuid.Nil, ) diff --git a/migrate/migrate.go b/migrate/migrate.go index 4f528bff0..36e4534c6 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -146,6 +146,7 @@ func updateEnrollmentKeys() { time.Time{}, []string{network.NetID}, []string{network.NetID}, + []models.TagID{}, true, uuid.Nil, ) From 6a4464aaa39eb01e7e194a9ec345f79a20927558 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 12:03:43 +0400 Subject: [PATCH 123/169] fix rebase errors --- logic/networks.go | 1 + migrate/migrate.go | 1 + 2 files changed, 2 insertions(+) diff --git a/logic/networks.go b/logic/networks.go index 0cee5603c..1a50fa791 100644 --- a/logic/networks.go +++ b/logic/networks.go @@ -240,6 +240,7 @@ func CreateNetwork(network models.Network) (models.Network, error) { time.Time{}, []string{network.NetID}, []string{network.NetID}, + []models.TagID{}, true, uuid.Nil, ) diff --git a/migrate/migrate.go b/migrate/migrate.go index bae461b75..9ed214092 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -146,6 +146,7 @@ func updateEnrollmentKeys() { time.Time{}, []string{network.NetID}, []string{network.NetID}, + []models.TagID{}, true, uuid.Nil, ) From 5375a8eefa6026b744e1b3f9e837f127b6fb334b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 12:31:15 +0400 Subject: [PATCH 124/169] fix user roles and groups descriptions --- pro/logic/user_mgmt.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index f32bd63b2..2c08ba065 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -31,7 +31,7 @@ var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)), Name: "Network Admins", - MetaData: "Users with this role can manage all your networks configuration including adding and removing devices.", + MetaData: "Can manage all your networks configuration including adding and removing devices.", Default: true, FullAccess: true, NetworkID: models.AllNetworks, @@ -40,7 +40,7 @@ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ var NetworkUserAllPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)), Name: "Network Users", - MetaData: "Users with this role Cannot access the admin console, but can connect to nodes in your networks via RAC.", + MetaData: "Cannot access the admin console, but can connect to nodes in your networks via Remote Access Client.", Default: true, FullAccess: false, NetworkID: models.AllNetworks, @@ -85,7 +85,7 @@ func UserGroupsInit() { ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin)), Default: true, Name: "Network Admin Group", - MetaData: "Users in this group can manage all your networks configuration.", + MetaData: "Can manage all your networks configuration.", NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ models.AllNetworks: { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)): {}, @@ -101,7 +101,7 @@ func UserGroupsInit() { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {}, }, }, - MetaData: "Users in this group cannot access the admin console, but can connect to nodes in your networks via RAC.", + MetaData: "Cannot access the admin console, but can connect to nodes in your networks via Remote Access Client.", } d, _ := json.Marshal(NetworkGlobalAdminGroup) database.Insert(NetworkGlobalAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) @@ -116,7 +116,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)), Name: fmt.Sprintf("%s Admin", netID), - MetaData: fmt.Sprintf("Users with this role can manage your network `%s` configuration.", netID), + MetaData: fmt.Sprintf("Can manage your network `%s` configuration.", netID), Default: true, NetworkID: netID, FullAccess: true, @@ -126,7 +126,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)), Name: fmt.Sprintf("%s User", netID), - MetaData: fmt.Sprintf("Users Cannot access the admin console, but can connect to nodes in your network `%s` via RAC.", netID), + MetaData: fmt.Sprintf("Cannot access the admin console, but can connect to nodes in your network `%s` via Remote Access Client.", netID), Default: true, FullAccess: false, NetworkID: netID, @@ -163,7 +163,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)): {}, }, }, - MetaData: fmt.Sprintf("User in this group can manage your network `%s` configuration including adding and removing devices.", netID), + MetaData: fmt.Sprintf("Can manage your network `%s` configuration including adding and removing devices.", netID), } var NetworkUserGroup = models.UserGroup{ ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser)), @@ -173,7 +173,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {}, }, }, - MetaData: fmt.Sprintf("Users in this group cannot access the admin console, but can connect to nodes in your network `%s` via RAC.", netID), + MetaData: fmt.Sprintf("Cannot access the admin console, but can connect to nodes in your network `%s` via Remote Access Client.", netID), } d, _ = json.Marshal(NetworkAdminGroup) database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) From 046e88366fdaf513037ba622e1d2b087c786561e Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 12:42:29 +0400 Subject: [PATCH 125/169] update release version v0.26.0 --- .github/ISSUE_TEMPLATE/bug-report.yml | 1 + compose/docker-compose.netclient.yml | 2 +- k8s/client/netclient-daemonset.yaml | 2 +- k8s/client/netclient.yaml | 2 +- k8s/server/netmaker-ui.yaml | 2 +- main.go | 2 +- release.md | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 3533bccd0..09fb90c10 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -31,6 +31,7 @@ body: label: Version description: What version are you running? options: + - v0.26.0 - v0.25.0 - v0.24.3 - v0.24.2 diff --git a/compose/docker-compose.netclient.yml b/compose/docker-compose.netclient.yml index a488fa006..da6fc14f4 100644 --- a/compose/docker-compose.netclient.yml +++ b/compose/docker-compose.netclient.yml @@ -3,7 +3,7 @@ version: "3.4" services: netclient: container_name: netclient - image: 'gravitl/netclient:v0.25.0' + image: 'gravitl/netclient:v0.26.0' hostname: netmaker-1 network_mode: host restart: on-failure diff --git a/k8s/client/netclient-daemonset.yaml b/k8s/client/netclient-daemonset.yaml index f1a3f407d..cc7b744a0 100644 --- a/k8s/client/netclient-daemonset.yaml +++ b/k8s/client/netclient-daemonset.yaml @@ -16,7 +16,7 @@ spec: hostNetwork: true containers: - name: netclient - image: gravitl/netclient:v0.25.0 + image: gravitl/netclient:v0.26.0 env: - name: TOKEN value: "TOKEN_VALUE" diff --git a/k8s/client/netclient.yaml b/k8s/client/netclient.yaml index 8ab9ec97b..9aa3f396d 100644 --- a/k8s/client/netclient.yaml +++ b/k8s/client/netclient.yaml @@ -28,7 +28,7 @@ spec: # - "" containers: - name: netclient - image: gravitl/netclient:v0.25.0 + image: gravitl/netclient:v0.26.0 env: - name: TOKEN value: "TOKEN_VALUE" diff --git a/k8s/server/netmaker-ui.yaml b/k8s/server/netmaker-ui.yaml index 5600bea41..3212ec10a 100644 --- a/k8s/server/netmaker-ui.yaml +++ b/k8s/server/netmaker-ui.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: netmaker-ui - image: gravitl/netmaker-ui:v0.25.0 + image: gravitl/netmaker-ui:v0.26.0 ports: - containerPort: 443 env: diff --git a/main.go b/main.go index 027b51c72..cf37e6afd 100644 --- a/main.go +++ b/main.go @@ -27,7 +27,7 @@ import ( "golang.org/x/exp/slog" ) -var version = "v0.25.0" +var version = "v0.26.0" // @title NetMaker // @version 0.24.3 diff --git a/release.md b/release.md index 7f32b5843..3aec5059c 100644 --- a/release.md +++ b/release.md @@ -1,4 +1,4 @@ -# Netmaker v0.25.0 +# Netmaker v0.26.0 ## Whats New ✨ - Advanced User Management with Network Roles and Groups From cd6019165171a01b57e18341d05a98d1562f79ec Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 12:48:00 +0400 Subject: [PATCH 126/169] update release tag on readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fcd2b5ffe..260c92376 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@

- + From 169ae8fd02d8b1c9d403843bd3be73163cc49141 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 13:02:53 +0400 Subject: [PATCH 127/169] update global group names --- pro/logic/user_mgmt.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 2c08ba065..8fc0f5d30 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -84,7 +84,7 @@ func UserGroupsInit() { var NetworkGlobalAdminGroup = models.UserGroup{ ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin)), Default: true, - Name: "Network Admin Group", + Name: "All Networks Admin Group", MetaData: "Can manage all your networks configuration.", NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ models.AllNetworks: { @@ -94,7 +94,7 @@ func UserGroupsInit() { } var NetworkGlobalUserGroup = models.UserGroup{ ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkUser)), - Name: "Network User Group", + Name: "All Networks User Group", Default: true, NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ models.NetworkID("*"): { From 8c6772420f59464b8f2f531a9d36ce88d532e9e0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 13:11:32 +0400 Subject: [PATCH 128/169] refer new new user role fields --- pro/logic/user_mgmt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 8fc0f5d30..1f9f42531 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -560,7 +560,7 @@ func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) { if err != nil { return } - if user.IsAdmin || user.IsSuperAdmin { + if user.PlatformRoleID == models.AdminRole || user.PlatformRoleID == models.SuperAdminRole { for _, node := range nodes { if node.IsIngressGateway { gws[node.ID.String()] = node From e1cc0a24ddd8c88c4d7b07e1d83821a83833d712 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 15:24:23 +0400 Subject: [PATCH 129/169] control user access to gw by roles --- pro/controllers/users.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 801219575..7d933296c 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -835,7 +835,7 @@ func getUserRemoteAccessNetworks(w http.ResponseWriter, r *http.Request) { userGws := make(map[string][]models.UserRemoteGws) networks := []models.Network{} networkMap := make(map[string]struct{}) - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) for _, node := range userGwNodes { network, err := logic.GetNetwork(node.Network) if err != nil { @@ -877,7 +877,7 @@ func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request) } userGws := []models.UserRAGs{} - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) for _, node := range userGwNodes { if node.Network != network { continue @@ -932,7 +932,7 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) { return } - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) if _, ok := userGwNodes[remoteGwID]; !ok { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access denied"), "forbidden")) return @@ -1076,7 +1076,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - userGwNodes := proLogic.GetUserRAGNodesV1(*user) + userGwNodes := proLogic.GetUserRAGNodes(*user) for _, extClient := range allextClients { node, ok := userGwNodes[extClient.IngressGatewayID] if !ok { From 56d5c85da7240c9561316595ab0dd35e99b8e193 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 15:58:55 +0400 Subject: [PATCH 130/169] block default key deletion,delete default key on network deletion --- controllers/enrollmentkeys.go | 3 ++- controllers/tags.go | 1 + logic/enrollmentkey.go | 29 ++++++++++++++++++++++++++--- logic/enrollmentkey_test.go | 30 +++++++++++++++--------------- logic/networks.go | 12 ++++++++++++ migrate/migrate.go | 1 + models/enrollment_key.go | 1 + 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/controllers/enrollmentkeys.go b/controllers/enrollmentkeys.go index 9d7fbe432..1ab9498ea 100644 --- a/controllers/enrollmentkeys.go +++ b/controllers/enrollmentkeys.go @@ -72,7 +72,7 @@ func getEnrollmentKeys(w http.ResponseWriter, r *http.Request) { func deleteEnrollmentKey(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) keyID := params["keyID"] - err := logic.DeleteEnrollmentKey(keyID) + err := logic.DeleteEnrollmentKey(keyID, false) if err != nil { logger.Log(0, r.Header.Get("user"), "failed to remove enrollment key: ", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) @@ -159,6 +159,7 @@ func createEnrollmentKey(w http.ResponseWriter, r *http.Request) { enrollmentKeyBody.Groups, enrollmentKeyBody.Unlimited, relayId, + false, ) if err != nil { logger.Log(0, r.Header.Get("user"), "failed to create enrollment key:", err.Error()) diff --git a/controllers/tags.go b/controllers/tags.go index 9b19aba36..633dab968 100644 --- a/controllers/tags.go +++ b/controllers/tags.go @@ -224,6 +224,7 @@ func deleteTag(w http.ResponseWriter, r *http.Request) { go func() { logic.RemoveDeviceTagFromAclPolicies(tag.ID, tag.Network) + logic.RemoveTagFromEnrollmentKeys(tag.ID) mq.PublishPeerUpdate(false) }() logic.ReturnSuccessResponse(w, r, "deleted tag "+tagID) diff --git a/logic/enrollmentkey.go b/logic/enrollmentkey.go index bf811a1a8..b479c302b 100644 --- a/logic/enrollmentkey.go +++ b/logic/enrollmentkey.go @@ -37,7 +37,7 @@ var ( ) // CreateEnrollmentKey - creates a new enrollment key in db -func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, groups []models.TagID, unlimited bool, relay uuid.UUID) (*models.EnrollmentKey, error) { +func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, groups []models.TagID, unlimited bool, relay uuid.UUID, defaultKey bool) (*models.EnrollmentKey, error) { newKeyID, err := getUniqueEnrollmentID() if err != nil { return nil, err @@ -152,11 +152,14 @@ func deleteEnrollmentkeyFromCache(key string) { } // DeleteEnrollmentKey - delete's a given enrollment key by value -func DeleteEnrollmentKey(value string) error { - _, err := GetEnrollmentKey(value) +func DeleteEnrollmentKey(value string, force bool) error { + key, err := GetEnrollmentKey(value) if err != nil { return err } + if key.Default && !force { + return errors.New("cannot delete default network key") + } err = database.DeleteRecord(database.ENROLLMENT_KEYS_TABLE_NAME, value) if err == nil { if servercfg.CacheEnabled() { @@ -311,3 +314,23 @@ func getEnrollmentKeysMap() (map[string]models.EnrollmentKey, error) { } return currentKeys, nil } + +func RemoveTagFromEnrollmentKeys(deletedTagID models.TagID) { + keys, _ := GetAllEnrollmentKeys() + for _, key := range keys { + newTags := []models.TagID{} + update := false + for _, tagID := range key.Groups { + if tagID == deletedTagID { + update = true + continue + } + newTags = append(newTags, tagID) + } + if update { + key.Groups = newTags + upsertEnrollmentKey(&key) + } + + } +} diff --git a/logic/enrollmentkey_test.go b/logic/enrollmentkey_test.go index 5e63df167..92b4c5e28 100644 --- a/logic/enrollmentkey_test.go +++ b/logic/enrollmentkey_test.go @@ -14,35 +14,35 @@ func TestCreateEnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() t.Run("Can_Not_Create_Key", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, false, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, false, uuid.Nil, false) assert.Nil(t, newKey) assert.NotNil(t, err) assert.ErrorIs(t, err, models.ErrInvalidEnrollmentKey) }) t.Run("Can_Create_Key_Uses", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil) + newKey, err := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil, false) assert.Nil(t, err) assert.Equal(t, 1, newKey.UsesRemaining) assert.True(t, newKey.IsValid()) }) t.Run("Can_Create_Key_Time", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Now().Add(time.Minute), nil, nil, nil, false, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Now().Add(time.Minute), nil, nil, nil, false, uuid.Nil, false) assert.Nil(t, err) assert.True(t, newKey.IsValid()) }) t.Run("Can_Create_Key_Unlimited", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, true, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, true, uuid.Nil, false) assert.Nil(t, err) assert.True(t, newKey.IsValid()) }) t.Run("Can_Create_Key_WithNetworks", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil, false) assert.Nil(t, err) assert.True(t, newKey.IsValid()) assert.True(t, len(newKey.Networks) == 2) }) t.Run("Can_Create_Key_WithTags", func(t *testing.T) { - newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, []string{"tag1", "tag2"}, nil, true, uuid.Nil) + newKey, err := CreateEnrollmentKey(0, time.Time{}, nil, []string{"tag1", "tag2"}, nil, true, uuid.Nil, false) assert.Nil(t, err) assert.True(t, newKey.IsValid()) assert.True(t, len(newKey.Tags) == 2) @@ -62,10 +62,10 @@ func TestCreateEnrollmentKey(t *testing.T) { func TestDelete_EnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) + newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil, false) t.Run("Can_Delete_Key", func(t *testing.T) { assert.True(t, newKey.IsValid()) - err := DeleteEnrollmentKey(newKey.Value) + err := DeleteEnrollmentKey(newKey.Value, false) assert.Nil(t, err) oldKey, err := GetEnrollmentKey(newKey.Value) assert.Equal(t, oldKey, models.EnrollmentKey{}) @@ -73,7 +73,7 @@ func TestDelete_EnrollmentKey(t *testing.T) { assert.Equal(t, err, EnrollmentErrors.NoKeyFound) }) t.Run("Can_Not_Delete_Invalid_Key", func(t *testing.T) { - err := DeleteEnrollmentKey("notakey") + err := DeleteEnrollmentKey("notakey", false) assert.NotNil(t, err) assert.Equal(t, err, EnrollmentErrors.NoKeyFound) }) @@ -83,7 +83,7 @@ func TestDelete_EnrollmentKey(t *testing.T) { func TestDecrement_EnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil) + newKey, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil, false) t.Run("Check_initial_uses", func(t *testing.T) { assert.True(t, newKey.IsValid()) assert.Equal(t, newKey.UsesRemaining, 1) @@ -107,9 +107,9 @@ func TestDecrement_EnrollmentKey(t *testing.T) { func TestUsability_EnrollmentKey(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - key1, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil) - key2, _ := CreateEnrollmentKey(0, time.Now().Add(time.Minute<<4), nil, nil, nil, false, uuid.Nil) - key3, _ := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, true, uuid.Nil) + key1, _ := CreateEnrollmentKey(1, time.Time{}, nil, nil, nil, false, uuid.Nil, false) + key2, _ := CreateEnrollmentKey(0, time.Now().Add(time.Minute<<4), nil, nil, nil, false, uuid.Nil, false) + key3, _ := CreateEnrollmentKey(0, time.Time{}, nil, nil, nil, true, uuid.Nil, false) t.Run("Check if valid use key can be used", func(t *testing.T) { assert.Equal(t, key1.UsesRemaining, 1) ok := TryToUseEnrollmentKey(key1) @@ -145,7 +145,7 @@ func removeAllEnrollments() { func TestTokenize_EnrollmentKeys(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) + newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil, false) const defaultValue = "MwE5MwE5MwE5MwE5MwE5MwE5MwE5MwE5" const b64value = "eyJzZXJ2ZXIiOiJhcGkubXlzZXJ2ZXIuY29tIiwidmFsdWUiOiJNd0U1TXdFNU13RTVNd0U1TXdFNU13RTVNd0U1TXdFNSJ9" const serverAddr = "api.myserver.com" @@ -178,7 +178,7 @@ func TestTokenize_EnrollmentKeys(t *testing.T) { func TestDeTokenize_EnrollmentKeys(t *testing.T) { database.InitializeDatabase() defer database.CloseDB() - newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil) + newKey, _ := CreateEnrollmentKey(0, time.Time{}, []string{"mynet", "skynet"}, nil, nil, true, uuid.Nil, false) const b64Value = "eyJzZXJ2ZXIiOiJhcGkubXlzZXJ2ZXIuY29tIiwidmFsdWUiOiJNd0U1TXdFNU13RTVNd0U1TXdFNU13RTVNd0U1TXdFNSJ9" const serverAddr = "api.myserver.com" diff --git a/logic/networks.go b/logic/networks.go index 1a50fa791..1617889d5 100644 --- a/logic/networks.go +++ b/logic/networks.go @@ -177,6 +177,17 @@ func DeleteNetwork(network string) error { if err != nil { logger.Log(1, "failed to remove the node acls during network delete for network,", network) } + // Delete default network enrollment key + keys, _ := GetAllEnrollmentKeys() + for _, key := range keys { + if key.Tags[0] == network { + if key.Default { + DeleteEnrollmentKey(key.Value, true) + break + } + + } + } nodeCount, err := GetNetworkNonServerNodeCount(network) if nodeCount == 0 || database.IsEmptyRecord(err) { // delete server nodes first then db records @@ -243,6 +254,7 @@ func CreateNetwork(network models.Network) (models.Network, error) { []models.TagID{}, true, uuid.Nil, + true, ) return network, nil diff --git a/migrate/migrate.go b/migrate/migrate.go index 36e4534c6..1c697873c 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -149,6 +149,7 @@ func updateEnrollmentKeys() { []models.TagID{}, true, uuid.Nil, + true, ) } diff --git a/models/enrollment_key.go b/models/enrollment_key.go index 5aa89c8a7..f133d7558 100644 --- a/models/enrollment_key.go +++ b/models/enrollment_key.go @@ -53,6 +53,7 @@ type EnrollmentKey struct { Type KeyType `json:"type"` Relay uuid.UUID `json:"relay"` Groups []TagID `json:"groups"` + Default bool `json:"default"` } // APIEnrollmentKey - used to create enrollment keys via API From 167d29a96ba4f846ff9e8259caf4c30c2c1179e1 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 19:22:05 +0400 Subject: [PATCH 131/169] remove * on default grp, add admins to admin net groups by default --- controllers/acls.go | 1 - logic/acls.go | 5 +++++ logic/user_mgmt.go | 2 ++ logic/users.go | 1 + migrate/migrate.go | 2 ++ pro/controllers/users.go | 4 ++++ pro/initialize.go | 1 + pro/logic/user_mgmt.go | 31 ++++++++++++++++++++++++++++--- 8 files changed, 43 insertions(+), 4 deletions(-) diff --git a/controllers/acls.go b/controllers/acls.go index ee9777784..727811fb5 100644 --- a/controllers/acls.go +++ b/controllers/acls.go @@ -28,7 +28,6 @@ func aclHandlers(r *mux.Router) { Methods(http.MethodDelete) r.HandleFunc("/api/v1/acls/debug", logic.SecurityCheck(true, http.HandlerFunc(aclDebug))). Methods(http.MethodGet) - } // @Summary List Acl Policy types diff --git a/logic/acls.go b/logic/acls.go index fbb3a7e40..53e0162d0 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -183,6 +183,11 @@ func IsAclPolicyValid(acl models.Acl) bool { if err != nil { return false } + // check if group belongs to this network + netGrps := GetUserGroupsInNetwork(acl.NetworkID) + if _, ok := netGrps[models.UserGroupID(srcI.Value)]; !ok { + return false + } } } diff --git a/logic/user_mgmt.go b/logic/user_mgmt.go index 3e22bb50c..43aa74a8a 100644 --- a/logic/user_mgmt.go +++ b/logic/user_mgmt.go @@ -59,6 +59,8 @@ var IntialiseGroups = func() {} var DeleteNetworkRoles = func(netID string) {} var CreateDefaultNetworkRolesAndGroups = func(netID models.NetworkID) {} var CreateDefaultUserPolicies = func(netID models.NetworkID) {} +var GetUserGroupsInNetwork = func(netID models.NetworkID) (networkGrps map[models.UserGroupID]models.UserGroup) { return } +var AddGlobalNetRolesToAdmins = func(u *models.User) {} // GetRole - fetches role template by id func GetRole(roleID models.UserRoleID) (models.UserRolePermissionTemplate, error) { diff --git a/logic/users.go b/logic/users.go index 168fd9282..f196de217 100644 --- a/logic/users.go +++ b/logic/users.go @@ -62,6 +62,7 @@ func SetUserDefaults(user *models.User) { if len(user.UserGroups) == 0 { user.UserGroups = make(map[models.UserGroupID]struct{}) } + AddGlobalNetRolesToAdmins(user) } // SortUsers - Sorts slice of Users by username diff --git a/migrate/migrate.go b/migrate/migrate.go index 1c697873c..02da7a3b6 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -398,6 +398,8 @@ func syncUsers() { if err == nil { for _, user := range users { user := user + logic.AddGlobalNetRolesToAdmins(&user) + logic.UpsertUser(user) if user.PlatformRoleID == models.AdminRole && !user.IsAdmin { user.IsAdmin = true logic.UpsertUser(user) diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 7d933296c..2e938611d 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -496,6 +496,10 @@ func deleteUserGroup(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to fetch group details"), "badrequest")) return } + if userG.Default { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot delete default user group"), "badrequest")) + return + } err = proLogic.DeleteUserGroup(models.UserGroupID(gid)) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) diff --git a/pro/initialize.go b/pro/initialize.go index 496758cbf..ef8ac6f27 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -138,6 +138,7 @@ func InitPro() { logic.CreateDefaultUserPolicies = proLogic.CreateDefaultUserPolicies logic.MigrateUserRoleAndGroups = proLogic.MigrateUserRoleAndGroups logic.IntialiseGroups = proLogic.UserGroupsInit + logic.AddGlobalNetRolesToAdmins = proLogic.AddGlobalNetRolesToAdmins } func retrieveProLogo() string { diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 1f9f42531..317ddc633 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -97,7 +97,7 @@ func UserGroupsInit() { Name: "All Networks User Group", Default: true, NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ - models.NetworkID("*"): { + models.NetworkID(models.AllNetworks): { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {}, }, }, @@ -1156,7 +1156,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { }, { ID: models.UserGroupAclID, - Value: "global-network-admin-grp", + Value: fmt.Sprintf("global-%s-grp", models.NetworkAdmin), }, }, Dst: []models.AclPolicyTag{ @@ -1187,7 +1187,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { }, { ID: models.UserGroupAclID, - Value: "global-network-user-grp", + Value: fmt.Sprintf("global-%s-grp", models.NetworkUser), }, }, @@ -1205,3 +1205,28 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { } } + +func GetUserGroupsInNetwork(netID models.NetworkID) (networkGrps map[models.UserGroupID]models.UserGroup) { + groups, _ := ListUserGroups() + networkGrps = make(map[models.UserGroupID]models.UserGroup) + for _, grp := range groups { + if _, ok := grp.NetworkRoles[models.AllNetworks]; ok { + networkGrps[grp.ID] = grp + continue + } + if _, ok := grp.NetworkRoles[netID]; ok { + networkGrps[grp.ID] = grp + } + } + return +} + +func AddGlobalNetRolesToAdmins(u *models.User) { + if u.PlatformRoleID != models.SuperAdminRole && u.PlatformRoleID != models.AdminRole { + return + } + if u.UserGroups == nil { + u.UserGroups = make(map[models.UserGroupID]struct{}) + } + u.UserGroups[models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin))] = struct{}{} +} From b85585ab9ec18adbeab11c52b71a922c8997d003 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 19:40:41 +0400 Subject: [PATCH 132/169] check for custom allow all --- logic/acls.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/logic/acls.go b/logic/acls.go index 53e0162d0..622b18a98 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -487,6 +487,11 @@ func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // fmt.Printf("\n======> DSTMAP: %+v\n", dstMap) // fmt.Printf("\n======> node Tags: %+v\n", node.Tags) // fmt.Printf("\n======> peer Tags: %+v\n", peer.Tags) + if _, ok := srcMap["*"]; ok { + if _, ok := dstMap["*"]; ok { + return true + } + } for tagID := range node.Tags { if _, ok := dstMap[tagID.String()]; ok { if _, ok := srcMap["*"]; ok { From 7fa87219c11c5e251ef12bda501465eee4ed6056 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 20:41:56 +0400 Subject: [PATCH 133/169] fix static check --- logic/acls.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 622b18a98..540205562 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -358,26 +358,6 @@ func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl { return acls } -// listUserPoliciesByNetwork - lists all acl user policies in a network -func listUserPoliciesByNetwork(netID models.NetworkID) []models.Acl { - data, err := database.FetchRecords(database.ACLS_TABLE_NAME) - if err != nil && !database.IsEmptyRecord(err) { - return []models.Acl{} - } - acls := []models.Acl{} - for _, dataI := range data { - acl := models.Acl{} - err := json.Unmarshal([]byte(dataI), &acl) - if err != nil { - continue - } - if acl.NetworkID == netID && acl.RuleType == models.UserPolicy { - acls = append(acls, acl) - } - } - return acls -} - // listDevicePolicies - lists all device policies in a network func listDevicePolicies(netID models.NetworkID) []models.Acl { data, err := database.FetchRecords(database.ACLS_TABLE_NAME) From 019f179b8535bff888efe506ceda6cc1cb2b84d9 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 20:55:51 +0400 Subject: [PATCH 134/169] update api docs version --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index cf37e6afd..a937b7e79 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ import ( var version = "v0.26.0" // @title NetMaker -// @version 0.24.3 +// @version 0.26.0 // @description NetMaker API Docs // @tag.name APIUsage // @tag.description.markdown From 1b035d980ead89a07892ab55e449a87b963a74be Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 30 Oct 2024 23:17:16 +0400 Subject: [PATCH 135/169] initialise group net func --- pro/initialize.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pro/initialize.go b/pro/initialize.go index ef8ac6f27..8d0c005cd 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -139,6 +139,7 @@ func InitPro() { logic.MigrateUserRoleAndGroups = proLogic.MigrateUserRoleAndGroups logic.IntialiseGroups = proLogic.UserGroupsInit logic.AddGlobalNetRolesToAdmins = proLogic.AddGlobalNetRolesToAdmins + logic.GetUserGroupsInNetwork = proLogic.GetUserGroupsInNetwork } func retrieveProLogo() string { From 4b99435cbca928a8a882908d42d93fdc5b3a58a3 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 31 Oct 2024 11:58:54 +0400 Subject: [PATCH 136/169] user roles and groups migration --- controllers/middleware.go | 3 +++ logic/auth.go | 2 +- logic/user_mgmt.go | 2 +- logic/users.go | 1 - migrate/migrate.go | 5 ++--- models/user_mgmt.go | 1 + pro/logic/migrate.go | 5 +---- pro/logic/user_mgmt.go | 3 ++- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/controllers/middleware.go b/controllers/middleware.go index 283dbba65..98cb85716 100644 --- a/controllers/middleware.go +++ b/controllers/middleware.go @@ -60,6 +60,9 @@ func userMiddleWare(handler http.Handler) http.Handler { if strings.Contains(route, "acls") { r.Header.Set("TARGET_RSRC", models.AclRsrc.String()) } + if strings.Contains(route, "tags") { + r.Header.Set("TARGET_RSRC", models.TagRsrc.String()) + } if strings.Contains(route, "extclients") { r.Header.Set("TARGET_RSRC", models.ExtClientsRsrc.String()) } diff --git a/logic/auth.go b/logic/auth.go index 3da9f605d..4a1873e66 100644 --- a/logic/auth.go +++ b/logic/auth.go @@ -186,7 +186,7 @@ func CreateUser(user *models.User) error { logger.Log(0, "failed to insert user", err.Error()) return err } - + AddGlobalNetRolesToAdmins(*user) return nil } diff --git a/logic/user_mgmt.go b/logic/user_mgmt.go index 43aa74a8a..56395c78c 100644 --- a/logic/user_mgmt.go +++ b/logic/user_mgmt.go @@ -60,7 +60,7 @@ var DeleteNetworkRoles = func(netID string) {} var CreateDefaultNetworkRolesAndGroups = func(netID models.NetworkID) {} var CreateDefaultUserPolicies = func(netID models.NetworkID) {} var GetUserGroupsInNetwork = func(netID models.NetworkID) (networkGrps map[models.UserGroupID]models.UserGroup) { return } -var AddGlobalNetRolesToAdmins = func(u *models.User) {} +var AddGlobalNetRolesToAdmins = func(u models.User) {} // GetRole - fetches role template by id func GetRole(roleID models.UserRoleID) (models.UserRolePermissionTemplate, error) { diff --git a/logic/users.go b/logic/users.go index f196de217..168fd9282 100644 --- a/logic/users.go +++ b/logic/users.go @@ -62,7 +62,6 @@ func SetUserDefaults(user *models.User) { if len(user.UserGroups) == 0 { user.UserGroups = make(map[models.UserGroupID]struct{}) } - AddGlobalNetRolesToAdmins(user) } // SortUsers - Sorts slice of Users by username diff --git a/migrate/migrate.go b/migrate/migrate.go index 02da7a3b6..0c2d4245f 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -398,8 +398,7 @@ func syncUsers() { if err == nil { for _, user := range users { user := user - logic.AddGlobalNetRolesToAdmins(&user) - logic.UpsertUser(user) + logic.AddGlobalNetRolesToAdmins(user) if user.PlatformRoleID == models.AdminRole && !user.IsAdmin { user.IsAdmin = true logic.UpsertUser(user) @@ -409,6 +408,7 @@ func syncUsers() { logic.UpsertUser(user) } if user.PlatformRoleID.String() != "" { + logic.MigrateUserRoleAndGroups(user) continue } user.AuthType = models.BasicAuth @@ -431,7 +431,6 @@ func syncUsers() { } logic.UpsertUser(user) logic.MigrateUserRoleAndGroups(user) - } } diff --git a/models/user_mgmt.go b/models/user_mgmt.go index 57986402e..7debd6e22 100644 --- a/models/user_mgmt.go +++ b/models/user_mgmt.go @@ -62,6 +62,7 @@ const ( EnrollmentKeysRsrc RsrcType = "enrollment_key" UserRsrc RsrcType = "users" AclRsrc RsrcType = "acl" + TagRsrc RsrcType = "tag" DnsRsrc RsrcType = "dns" FailOverRsrc RsrcType = "fail_over" MetricRsrc RsrcType = "metrics" diff --git a/pro/logic/migrate.go b/pro/logic/migrate.go index d30e71e06..f7875f846 100644 --- a/pro/logic/migrate.go +++ b/pro/logic/migrate.go @@ -28,7 +28,6 @@ func MigrateUserRoleAndGroups(user models.User) { continue } user.UserGroups[g.ID] = struct{}{} - } } if len(user.NetworkRoles) > 0 { @@ -44,9 +43,7 @@ func MigrateUserRoleAndGroups(user models.User) { continue } user.UserGroups[g.ID] = struct{}{} - if err != nil { - continue - } + user.NetworkRoles = make(map[models.NetworkID]map[models.UserRoleID]struct{}) } } diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 317ddc633..289d751d6 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -1221,7 +1221,7 @@ func GetUserGroupsInNetwork(netID models.NetworkID) (networkGrps map[models.User return } -func AddGlobalNetRolesToAdmins(u *models.User) { +func AddGlobalNetRolesToAdmins(u models.User) { if u.PlatformRoleID != models.SuperAdminRole && u.PlatformRoleID != models.AdminRole { return } @@ -1229,4 +1229,5 @@ func AddGlobalNetRolesToAdmins(u *models.User) { u.UserGroups = make(map[models.UserGroupID]struct{}) } u.UserGroups[models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin))] = struct{}{} + logic.UpsertUser(u) } From 42b8a03660af642e23f550dcc26372be1e17258b Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 31 Oct 2024 12:06:14 +0400 Subject: [PATCH 137/169] fix user migration --- migrate/migrate.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migrate/migrate.go b/migrate/migrate.go index 0c2d4245f..fe151c0c1 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -398,7 +398,6 @@ func syncUsers() { if err == nil { for _, user := range users { user := user - logic.AddGlobalNetRolesToAdmins(user) if user.PlatformRoleID == models.AdminRole && !user.IsAdmin { user.IsAdmin = true logic.UpsertUser(user) @@ -409,6 +408,7 @@ func syncUsers() { } if user.PlatformRoleID.String() != "" { logic.MigrateUserRoleAndGroups(user) + logic.AddGlobalNetRolesToAdmins(user) continue } user.AuthType = models.BasicAuth @@ -430,6 +430,7 @@ func syncUsers() { user.PlatformRoleID = models.ServiceUser } logic.UpsertUser(user) + logic.AddGlobalNetRolesToAdmins(user) logic.MigrateUserRoleAndGroups(user) } } From df3662f0ccfaa9a8b3426d04b7e5ae4c8dfa5007 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 31 Oct 2024 15:13:29 +0400 Subject: [PATCH 138/169] check for custom all policies --- logic/acls.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 540205562..0bbb2bdf0 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -54,10 +54,6 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { ID: models.UserAclID, Value: "*", }, - { - ID: models.UserGroupAclID, - Value: "*", - }, }, Dst: []models.AclPolicyTag{{ ID: models.DeviceAclID, @@ -285,6 +281,27 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo if err != nil { return models.Acl{}, errors.New("default rule not found") } + if acl.Enabled { + return acl, nil + } + // check if there are any custom all policies + policies, _ := ListAcls(netID) + for _, policy := range policies { + if !policy.Enabled { + continue + } + if policy.RuleType == ruleType { + dstMap := convAclTagToValueMap(policy.Dst) + srcMap := convAclTagToValueMap(policy.Dst) + if _, ok := srcMap["*"]; ok { + if _, ok := dstMap["*"]; ok { + return policy, nil + } + } + } + + } + return acl, nil } @@ -467,11 +484,6 @@ func IsNodeAllowedToCommunicate(node, peer models.Node) bool { // fmt.Printf("\n======> DSTMAP: %+v\n", dstMap) // fmt.Printf("\n======> node Tags: %+v\n", node.Tags) // fmt.Printf("\n======> peer Tags: %+v\n", peer.Tags) - if _, ok := srcMap["*"]; ok { - if _, ok := dstMap["*"]; ok { - return true - } - } for tagID := range node.Tags { if _, ok := dstMap[tagID.String()]; ok { if _, ok := srcMap["*"]; ok { From 811956bb4e8c92680979cea2594bf1f8107753c0 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 1 Nov 2024 16:35:44 +0400 Subject: [PATCH 139/169] set default value on model --- logic/enrollmentkey.go | 1 + 1 file changed, 1 insertion(+) diff --git a/logic/enrollmentkey.go b/logic/enrollmentkey.go index b479c302b..25cf0d6d3 100644 --- a/logic/enrollmentkey.go +++ b/logic/enrollmentkey.go @@ -52,6 +52,7 @@ func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string Type: models.Undefined, Relay: relay, Groups: groups, + Default: defaultKey, } if uses > 0 { k.UsesRemaining = uses From 3e90dbe75afb3e693875ccfa6bce1faa64e09ee5 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 1 Nov 2024 16:58:37 +0400 Subject: [PATCH 140/169] comment default dns setting for extclients --- controllers/ext_client.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/controllers/ext_client.go b/controllers/ext_client.go index a978513e1..aabb5103e 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -287,22 +287,22 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { } else if gwnode.IngressDNS != "" { defaultDNS = "DNS = " + gwnode.IngressDNS } - if servercfg.GetManageDNS() { - if gwnode.Address6.IP != nil { - if defaultDNS == "" { - defaultDNS = "DNS = " + gwnode.Address6.IP.String() - } else { - defaultDNS = defaultDNS + ", " + gwnode.Address6.IP.String() - } - } - if gwnode.Address.IP != nil { - if defaultDNS == "" { - defaultDNS = "DNS = " + gwnode.Address.IP.String() - } else { - defaultDNS = defaultDNS + ", " + gwnode.Address.IP.String() - } - } - } + // if servercfg.GetManageDNS() { + // if gwnode.Address6.IP != nil { + // if defaultDNS == "" { + // defaultDNS = "DNS = " + gwnode.Address6.IP.String() + // } else { + // defaultDNS = defaultDNS + ", " + gwnode.Address6.IP.String() + // } + // } + // if gwnode.Address.IP != nil { + // if defaultDNS == "" { + // defaultDNS = "DNS = " + gwnode.Address.IP.String() + // } else { + // defaultDNS = defaultDNS + ", " + gwnode.Address.IP.String() + // } + // } + // } defaultMTU := 1420 if host.MTU != 0 { From e36eef476a9e89c813259c4df47d56dc86285894 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 12:38:08 +0400 Subject: [PATCH 141/169] perform acl operations on cloned map --- logic/acls/nodeacls/retrieve.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/logic/acls/nodeacls/retrieve.go b/logic/acls/nodeacls/retrieve.go index d5fa68c40..195ac4971 100644 --- a/logic/acls/nodeacls/retrieve.go +++ b/logic/acls/nodeacls/retrieve.go @@ -3,6 +3,7 @@ package nodeacls import ( "encoding/json" "fmt" + "maps" "sync" "github.com/gravitl/netmaker/logic/acls" @@ -20,8 +21,9 @@ func AreNodesAllowed(networkID NetworkID, node1, node2 NodeID) bool { } var allowed bool acls.AclMutex.Lock() - currNetworkACLNode1 := currentNetworkACL[acls.AclID(node1)] - currNetworkACLNode2 := currentNetworkACL[acls.AclID(node2)] + currNetAclCopy := maps.Clone(currentNetworkACL) + currNetworkACLNode1 := currNetAclCopy[acls.AclID(node1)] + currNetworkACLNode2 := currNetAclCopy[acls.AclID(node2)] acls.AclMutex.Unlock() allowed = currNetworkACLNode1.IsAllowed(acls.AclID(node2)) && currNetworkACLNode2.IsAllowed(acls.AclID(node1)) return allowed From 38cb4d86e4d2eaeac90843859d67bcb436a79e93 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 12:46:08 +0400 Subject: [PATCH 142/169] return clone of map --- logic/acls/common.go | 5 +++-- logic/acls/nodeacls/retrieve.go | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/logic/acls/common.go b/logic/acls/common.go index 9296e3b80..bb35123a3 100644 --- a/logic/acls/common.go +++ b/logic/acls/common.go @@ -2,6 +2,7 @@ package acls import ( "encoding/json" + "maps" "sync" "github.com/gravitl/netmaker/database" @@ -133,7 +134,7 @@ func fetchACLContainer(containerID ContainerID) (ACLContainer, error) { defer AclMutex.RUnlock() if servercfg.CacheEnabled() { if aclContainer, ok := fetchAclContainerFromCache(containerID); ok { - return aclContainer, nil + return maps.Clone(aclContainer), nil } } aclJson, err := fetchACLContainerJson(ContainerID(containerID)) @@ -147,7 +148,7 @@ func fetchACLContainer(containerID ContainerID) (ACLContainer, error) { if servercfg.CacheEnabled() { storeAclContainerInCache(containerID, currentNetworkACL) } - return currentNetworkACL, nil + return maps.Clone(currentNetworkACL), nil } // fetchACLContainerJson - fetch the current ACL of given container except in json string diff --git a/logic/acls/nodeacls/retrieve.go b/logic/acls/nodeacls/retrieve.go index 195ac4971..4411c5b22 100644 --- a/logic/acls/nodeacls/retrieve.go +++ b/logic/acls/nodeacls/retrieve.go @@ -21,9 +21,8 @@ func AreNodesAllowed(networkID NetworkID, node1, node2 NodeID) bool { } var allowed bool acls.AclMutex.Lock() - currNetAclCopy := maps.Clone(currentNetworkACL) - currNetworkACLNode1 := currNetAclCopy[acls.AclID(node1)] - currNetworkACLNode2 := currNetAclCopy[acls.AclID(node2)] + currNetworkACLNode1 := currentNetworkACL[acls.AclID(node1)] + currNetworkACLNode2 := currentNetworkACL[acls.AclID(node2)] acls.AclMutex.Unlock() allowed = currNetworkACLNode1.IsAllowed(acls.AclID(node2)) && currNetworkACLNode2.IsAllowed(acls.AclID(node1)) return allowed @@ -69,5 +68,5 @@ func FetchAllACLs(networkID NetworkID) (acls.ACLContainer, error) { if err != nil { return nil, err } - return currentNetworkACL, nil + return maps.Clone(currentNetworkACL), nil } From bab772f562dc4a2af2bc7e1e92121a14fe126912 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 13:02:20 +0400 Subject: [PATCH 143/169] set last checkin status --- logic/nodes.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/logic/nodes.go b/logic/nodes.go index d482ac377..34eebe2e4 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -423,9 +423,8 @@ func SetNodeDefaults(node *models.Node, resetConnected bool) { } node.SetLastModified() - if node.LastCheckIn.IsZero() { - node.SetLastCheckIn() - } + node.SetLastCheckIn() + if resetConnected { node.SetDefaultConnected() } From 64b6a11e52cc642bec0d176a02f6fccefed81f89 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 13:13:21 +0400 Subject: [PATCH 144/169] option of turn off stun --- config/config.go | 1 + models/structs.go | 1 + scripts/netmaker.default.env | 3 ++- servercfg/serverconf.go | 10 ++++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index f9acaf980..6991650f3 100644 --- a/config/config.go +++ b/config/config.go @@ -102,6 +102,7 @@ type ServerConfig struct { MetricInterval string `yaml:"metric_interval"` ManageDNS bool `yaml:"manage_dns"` DefaultDomain string `yaml:"default_domain"` + StunStatus bool `yaml:"stun_status"` } // SQLConfig - Generic SQL Config diff --git a/models/structs.go b/models/structs.go index 2a723adf9..e22473e2d 100644 --- a/models/structs.go +++ b/models/structs.go @@ -268,6 +268,7 @@ type ServerConfig struct { MetricInterval string `yaml:"metric_interval"` ManageDNS bool `yaml:"manage_dns"` DefaultDomain string `yaml:"default_domain"` + StunStatus bool `yaml:"stun_status"` } // User.NameInCharset - returns if name is in charset below or not diff --git a/scripts/netmaker.default.env b/scripts/netmaker.default.env index e66c2e93c..b0e3d08cd 100644 --- a/scripts/netmaker.default.env +++ b/scripts/netmaker.default.env @@ -92,4 +92,5 @@ PEER_UPDATE_BATCH=true PEER_UPDATE_BATCH_SIZE=50 # default domain for internal DNS lookup DEFAULT_DOMAIN=netmaker.hosted - +# config to turn off Stun +STUN_STATUS=true diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index b9955b042..984a54925 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -95,6 +95,7 @@ func GetServerConfig() config.ServerConfig { cfg.MetricInterval = GetMetricInterval() cfg.ManageDNS = GetManageDNS() cfg.DefaultDomain = GetDefaultDomain() + cfg.StunStatus = GetSTUNStatus() return cfg } @@ -141,6 +142,7 @@ func GetServerInfo() models.ServerConfig { cfg.MetricInterval = GetMetricInterval() cfg.ManageDNS = GetManageDNS() cfg.DefaultDomain = GetDefaultDomain() + cfg.StunStatus = GetSTUNStatus() return cfg } @@ -846,6 +848,14 @@ func GetAllowedEmailDomains() string { return allowedDomains } +func GetSTUNStatus() bool { + s := true + if os.Getenv("STUN_STATUS") != "" { + s = os.Getenv("STUN_STATUS") == "true" + } + return s +} + // GetNmBaseDomain - fetches nm base domain func GetNmBaseDomain() string { return os.Getenv("NM_DOMAIN") From f24f3d84ab71ea8099408dc2d36dc0a923c63b90 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 13:36:28 +0400 Subject: [PATCH 145/169] ignore non-rac clients in auto disable hook --- pro/remote_access_client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pro/remote_access_client.go b/pro/remote_access_client.go index c46115bc8..35d2c3027 100644 --- a/pro/remote_access_client.go +++ b/pro/remote_access_client.go @@ -47,6 +47,9 @@ func racAutoDisableHook() error { continue } for _, client := range clients { + if client.RemoteAccessClientID == "" { + continue + } if (client.OwnerID == user.UserName) && user.PlatformRoleID != models.SuperAdminRole && user.PlatformRoleID != models.AdminRole && From 9609d87a87481fca3d152ebdafc86f293b61c3cd Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 15:50:17 +0400 Subject: [PATCH 146/169] skip clients loop when admin --- pro/remote_access_client.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pro/remote_access_client.go b/pro/remote_access_client.go index 35d2c3027..16a38a85f 100644 --- a/pro/remote_access_client.go +++ b/pro/remote_access_client.go @@ -43,6 +43,10 @@ func racAutoDisableHook() error { currentTime := time.Now() validityDuration := servercfg.GetJwtValidityDuration() for _, user := range users { + if user.PlatformRoleID == models.AdminRole || + user.PlatformRoleID == models.SuperAdminRole { + continue + } if !currentTime.After(user.LastLoginTime.Add(validityDuration)) { continue } @@ -51,8 +55,6 @@ func racAutoDisableHook() error { continue } if (client.OwnerID == user.UserName) && - user.PlatformRoleID != models.SuperAdminRole && - user.PlatformRoleID != models.AdminRole && client.Enabled { slog.Info(fmt.Sprintf("disabling ext client %s for user %s due to RAC autodisabling", client.ClientID, client.OwnerID)) if err := disableExtClient(&client); err != nil { From 14d2d3cefb3e26775a342e6042a0e765c2a3f20c Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 16:00:17 +0400 Subject: [PATCH 147/169] Revert "option of turn off stun" This reverts commit 64b6a11e52cc642bec0d176a02f6fccefed81f89. --- config/config.go | 1 - models/structs.go | 1 - scripts/netmaker.default.env | 3 +-- servercfg/serverconf.go | 10 ---------- 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/config/config.go b/config/config.go index 6991650f3..f9acaf980 100644 --- a/config/config.go +++ b/config/config.go @@ -102,7 +102,6 @@ type ServerConfig struct { MetricInterval string `yaml:"metric_interval"` ManageDNS bool `yaml:"manage_dns"` DefaultDomain string `yaml:"default_domain"` - StunStatus bool `yaml:"stun_status"` } // SQLConfig - Generic SQL Config diff --git a/models/structs.go b/models/structs.go index e22473e2d..2a723adf9 100644 --- a/models/structs.go +++ b/models/structs.go @@ -268,7 +268,6 @@ type ServerConfig struct { MetricInterval string `yaml:"metric_interval"` ManageDNS bool `yaml:"manage_dns"` DefaultDomain string `yaml:"default_domain"` - StunStatus bool `yaml:"stun_status"` } // User.NameInCharset - returns if name is in charset below or not diff --git a/scripts/netmaker.default.env b/scripts/netmaker.default.env index b0e3d08cd..e66c2e93c 100644 --- a/scripts/netmaker.default.env +++ b/scripts/netmaker.default.env @@ -92,5 +92,4 @@ PEER_UPDATE_BATCH=true PEER_UPDATE_BATCH_SIZE=50 # default domain for internal DNS lookup DEFAULT_DOMAIN=netmaker.hosted -# config to turn off Stun -STUN_STATUS=true + diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index 984a54925..b9955b042 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -95,7 +95,6 @@ func GetServerConfig() config.ServerConfig { cfg.MetricInterval = GetMetricInterval() cfg.ManageDNS = GetManageDNS() cfg.DefaultDomain = GetDefaultDomain() - cfg.StunStatus = GetSTUNStatus() return cfg } @@ -142,7 +141,6 @@ func GetServerInfo() models.ServerConfig { cfg.MetricInterval = GetMetricInterval() cfg.ManageDNS = GetManageDNS() cfg.DefaultDomain = GetDefaultDomain() - cfg.StunStatus = GetSTUNStatus() return cfg } @@ -848,14 +846,6 @@ func GetAllowedEmailDomains() string { return allowedDomains } -func GetSTUNStatus() bool { - s := true - if os.Getenv("STUN_STATUS") != "" { - s = os.Getenv("STUN_STATUS") == "true" - } - return s -} - // GetNmBaseDomain - fetches nm base domain func GetNmBaseDomain() string { return os.Getenv("NM_DOMAIN") From c07b32d167a982b6be0395e382a55a97e1de499f Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Mon, 4 Nov 2024 16:58:03 +0400 Subject: [PATCH 148/169] fix all networks user grp --- logic/acls.go | 2 +- pro/logic/user_mgmt.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/logic/acls.go b/logic/acls.go index 0bbb2bdf0..81b1f0b45 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -292,7 +292,7 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo } if policy.RuleType == ruleType { dstMap := convAclTagToValueMap(policy.Dst) - srcMap := convAclTagToValueMap(policy.Dst) + srcMap := convAclTagToValueMap(policy.Src) if _, ok := srcMap["*"]; ok { if _, ok := dstMap["*"]; ok { return policy, nil diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 289d751d6..08836224a 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -640,6 +640,7 @@ func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[mode } if _, ok := user.NetworkRoles[models.AllNetworks]; ok { gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope) + return } if len(user.UserGroups) > 0 { for gID := range user.UserGroups { @@ -647,6 +648,10 @@ func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[mode if err != nil { continue } + if _, ok := userG.NetworkRoles[models.AllNetworks]; ok { + gwAccess[models.NetworkID("*")] = make(map[models.RsrcID]models.RsrcPermissionScope) + return + } for netID, roleMap := range userG.NetworkRoles { for roleID := range roleMap { role, err := logic.GetRole(roleID) From 2339b49878bfadb1e11f19def9a46d4f369410bc Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Tue, 5 Nov 2024 15:05:59 +0400 Subject: [PATCH 149/169] cannot update default groups --- pro/controllers/users.go | 5 +++++ pro/logic/user_mgmt.go | 17 ++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/pro/controllers/users.go b/pro/controllers/users.go index 2e938611d..31099d0ce 100644 --- a/pro/controllers/users.go +++ b/pro/controllers/users.go @@ -451,6 +451,10 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + if currUserG.Default { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update default user group"), "badrequest")) + return + } err = proLogic.ValidateUpdateGroupReq(userGroup) if err != nil { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) @@ -461,6 +465,7 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + // reset configs for service user go proLogic.UpdatesUserGwAccessOnGrpUpdates(currUserG.NetworkRoles, userGroup.NetworkRoles) logic.ReturnSuccessResponseWithJson(w, r, userGroup, "updated user group") diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 08836224a..631459247 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -31,7 +31,7 @@ var PlatformUserUserPermissionTemplate = models.UserRolePermissionTemplate{ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)), Name: "Network Admins", - MetaData: "Can manage all your networks configuration including adding and removing devices.", + MetaData: "can manage configuration of all networks", Default: true, FullAccess: true, NetworkID: models.AllNetworks, @@ -40,7 +40,7 @@ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ var NetworkUserAllPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)), Name: "Network Users", - MetaData: "Cannot access the admin console, but can connect to nodes in your networks via Remote Access Client.", + MetaData: "cannot access the admin console, but can connect to nodes in your networks via Remote Access Client.", Default: true, FullAccess: false, NetworkID: models.AllNetworks, @@ -85,7 +85,7 @@ func UserGroupsInit() { ID: models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin)), Default: true, Name: "All Networks Admin Group", - MetaData: "Can manage all your networks configuration.", + MetaData: "can manage configuration of all networks", NetworkRoles: map[models.NetworkID]map[models.UserRoleID]struct{}{ models.AllNetworks: { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkAdmin)): {}, @@ -101,7 +101,7 @@ func UserGroupsInit() { models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {}, }, }, - MetaData: "Cannot access the admin console, but can connect to nodes in your networks via Remote Access Client.", + MetaData: "cannot access the admin console, but can connect to nodes in your networks via Remote Access Client.", } d, _ := json.Marshal(NetworkGlobalAdminGroup) database.Insert(NetworkGlobalAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) @@ -116,7 +116,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { var NetworkAdminPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)), Name: fmt.Sprintf("%s Admin", netID), - MetaData: fmt.Sprintf("Can manage your network `%s` configuration.", netID), + MetaData: fmt.Sprintf("can manage your network `%s` configuration.", netID), Default: true, NetworkID: netID, FullAccess: true, @@ -126,7 +126,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{ ID: models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)), Name: fmt.Sprintf("%s User", netID), - MetaData: fmt.Sprintf("Cannot access the admin console, but can connect to nodes in your network `%s` via Remote Access Client.", netID), + MetaData: fmt.Sprintf("cannot access the admin console, but can connect to nodes in your network `%s` via Remote Access Client.", netID), Default: true, FullAccess: false, NetworkID: netID, @@ -163,7 +163,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkAdmin)): {}, }, }, - MetaData: fmt.Sprintf("Can manage your network `%s` configuration including adding and removing devices.", netID), + MetaData: fmt.Sprintf("can manage your network `%s` configuration including adding and removing devices.", netID), } var NetworkUserGroup = models.UserGroup{ ID: models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser)), @@ -173,7 +173,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {}, }, }, - MetaData: fmt.Sprintf("Cannot access the admin console, but can connect to nodes in your network `%s` via Remote Access Client.", netID), + MetaData: fmt.Sprintf("cannot access the admin console, but can connect to nodes in your network `%s` via Remote Access Client.", netID), } d, _ = json.Marshal(NetworkAdminGroup) database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) @@ -445,7 +445,6 @@ func ValidateCreateGroupReq(g models.UserGroup) error { return nil } func ValidateUpdateGroupReq(g models.UserGroup) error { - for networkID := range g.NetworkRoles { userRolesMap := g.NetworkRoles[networkID] for roleID := range userRolesMap { From 74579e467b391b8a2f5d87d1637c7c3dd4254162 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 6 Nov 2024 10:42:54 +0400 Subject: [PATCH 150/169] disable default pro setup --- pro/initialize.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pro/initialize.go b/pro/initialize.go index 8d0c005cd..f6ae65670 100644 --- a/pro/initialize.go +++ b/pro/initialize.go @@ -38,12 +38,12 @@ func InitPro() { controller.ListRoles = proControllers.ListRoles logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() { // == License Handling == - enableLicenseHook := false - licenseKeyValue := servercfg.GetLicenseKey() - netmakerTenantID := servercfg.GetNetmakerTenantID() - if licenseKeyValue != "" && netmakerTenantID != "" { - enableLicenseHook = true - } + enableLicenseHook := true + // licenseKeyValue := servercfg.GetLicenseKey() + // netmakerTenantID := servercfg.GetNetmakerTenantID() + // if licenseKeyValue != "" && netmakerTenantID != "" { + // enableLicenseHook = true + // } if !enableLicenseHook { err := initTrial() if err != nil { From 5abbe86943c0bda8f8b2fbf7fad28fd939236f3b Mon Sep 17 00:00:00 2001 From: Abhishek K Date: Wed, 6 Nov 2024 10:53:15 +0400 Subject: [PATCH 151/169] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 260c92376..137d66284 100644 --- a/README.md +++ b/README.md @@ -51,18 +51,20 @@ If you're looking for a managed service, you can get started with just few clicks, visit [netmaker.io](https://account.netmaker.io) to create your netmaker server. -# Self-Hosted Quick Start +# Self-Hosted Open Source Quick Start These are the instructions for deploying a Netmaker server on your own cloud VM as quickly as possible. For more detailed instructions, visit the [Install Docs](https://docs.netmaker.io/docs/server-installation/quick-install#quick-install-script). 1. Get a cloud VM with Ubuntu 22.04 and a public IP. 2. Open ports 443, 80, 3479, 8089 and 51821-51830/udp on the VM firewall and in cloud security settings. 3. (recommended) Prepare DNS - Set a wildcard subdomain in your DNS settings for Netmaker, e.g. *.netmaker.example.com, which points to your VM's public IP. -4. Run the script: +4. Run the script to setup open source version of Netmaker: + +`sudo wget -qO /root/nm-quick.sh https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh && sudo chmod +x /root/nm-quick.sh && sudo /root/nm-quick.sh` + +**

To Install Self-Hosted PRO Version - https://docs.netmaker.io/docs/server-installation/netmaker-professional-setup
** -`sudo wget -qO /root/nm-quick.sh https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh && sudo chmod +x /root/nm-quick.sh && sudo /root/nm-quick.sh` -This script by default installs PRO version with 14-day trial, check out these instructions for post trial period https://docs.netmaker.io/docs/server-installation/quick-install#after-the-trial-period-ends. It also gives you the option to use your own domain (recommended) or an auto-generated domain.

From 79136ba5e7a569485663e985c40f7e605426099c Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 6 Nov 2024 10:56:21 +0400 Subject: [PATCH 152/169] remove default pro installation from script --- scripts/nm-quick.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh index 473242520..8c11769f7 100755 --- a/scripts/nm-quick.sh +++ b/scripts/nm-quick.sh @@ -921,7 +921,7 @@ main (){ source "$CONFIG_PATH" fi - INSTALL_TYPE="pro" + INSTALL_TYPE="ce" while getopts :cudpv flag; do case "${flag}" in c) From 20fd996aae7fb296e32618ae6cc18a5280ce8ee6 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 6 Nov 2024 11:17:03 +0400 Subject: [PATCH 153/169] remove passwd prompt for mq --- scripts/nm-quick.sh | 45 ++------------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh index 8c11769f7..0cc87cf7b 100755 --- a/scripts/nm-quick.sh +++ b/scripts/nm-quick.sh @@ -593,52 +593,11 @@ set_install_vars() { done fi wait_seconds 1 - unset GET_MQ_USERNAME - unset GET_MQ_PASSWORD - unset CONFIRM_MQ_PASSWORD - echo "Enter Credentials For MQ..." - - read -p "MQ Username (click 'enter' to use 'netmaker'): " GET_MQ_USERNAME - if [ -z "$GET_MQ_USERNAME" ]; then - echo "using default username for mq" - MQ_USERNAME="netmaker" - else - MQ_USERNAME="$GET_MQ_USERNAME" - fi - - if test -z "$MQ_PASSWORD"; then - MQ_PASSWORD=$( + MQ_USERNAME="netmaker" + MQ_PASSWORD=$( tr -dc A-Za-z0-9 Date: Wed, 6 Nov 2024 11:53:37 +0400 Subject: [PATCH 154/169] set up failover only in pro --- scripts/nm-quick.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh index 0cc87cf7b..232eb3f02 100755 --- a/scripts/nm-quick.sh +++ b/scripts/nm-quick.sh @@ -167,12 +167,12 @@ configure_netclient() { nmctl host update $HOST_ID --default sleep 5 nmctl node create_remote_access_gateway netmaker $NODE_ID - #setup failOver - sleep 5 - curl --location --request POST "https://api.${NETMAKER_BASE_DOMAIN}/api/v1/node/${NODE_ID}/failover" --header "Authorization: Bearer ${MASTER_KEY}" + sleep 2 # create network for internet access vpn if [ "$INSTALL_TYPE" = "pro" ]; then + #setup failOver + curl --location --request POST "https://api.${NETMAKER_BASE_DOMAIN}/api/v1/node/${NODE_ID}/failover" --header "Authorization: Bearer ${MASTER_KEY}" INET_NODE_ID=$(sudo cat /etc/netclient/nodes.json | jq -r '."internet-access-vpn".id') nmctl node create_remote_access_gateway internet-access-vpn $INET_NODE_ID out=$(nmctl node list -o json | jq -r '.[] | select(.id=='\"$INET_NODE_ID\"') | .ingressdns = "8.8.8.8"') @@ -181,7 +181,6 @@ configure_netclient() { curl --location --request PUT "https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/internet-access-vpn/${INET_NODE_ID}" --data "$out" --header "Authorization: Bearer ${MASTER_KEY}" curl --location --request POST "https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/internet-access-vpn/${INET_NODE_ID}/inet_gw" --data '{}' --header "Authorization: Bearer ${MASTER_KEY}" fi - set -e } From f13bdada892ea30cf735293b9a2af00381034b00 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Wed, 6 Nov 2024 16:10:55 +0400 Subject: [PATCH 155/169] ignore failover requests to failover node --- pro/controllers/failover.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pro/controllers/failover.go b/pro/controllers/failover.go index 946e753e4..71a72791f 100644 --- a/pro/controllers/failover.go +++ b/pro/controllers/failover.go @@ -203,6 +203,14 @@ func failOverME(w http.ResponseWriter, r *http.Request) { ) return } + if peerNode.IsFailOver { + logic.ReturnErrorResponse( + w, + r, + logic.FormatError(errors.New("peer is acting as failover"), "badrequest"), + ) + return + } if node.IsFailOver { logic.ReturnErrorResponse( w, From 4cf6771b11afe81bbc81c371fbd6552242830eb3 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 7 Nov 2024 11:42:57 +0400 Subject: [PATCH 156/169] remove firewall requirement for ingress node --- logic/gateway.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/logic/gateway.go b/logic/gateway.go index 3c700d7b0..21dc9f315 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -150,9 +150,6 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq if host.OS != "linux" { return models.Node{}, errors.New("ingress can only be created on linux based node") } - if host.FirewallInUse == models.FIREWALL_NONE { - return models.Node{}, errors.New("firewall is not supported for ingress gateways") - } network, err := GetParentNetwork(netid) if err != nil { From bb06ddaabe8bb905d34263b19abebed5f18204e2 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 7 Nov 2024 11:44:08 +0400 Subject: [PATCH 157/169] improve egress error --- logic/gateway.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/gateway.go b/logic/gateway.go index 21dc9f315..7d0539877 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -75,7 +75,7 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro return models.Node{}, errors.New(host.OS + " is unsupported for egress gateways") } if host.FirewallInUse == models.FIREWALL_NONE { - return models.Node{}, errors.New("firewall is not supported for egress gateways. please install iptables or nftables on the device in order to use this feature") + return models.Node{}, errors.New("please install iptables or nftables on the device") } for i := len(gateway.Ranges) - 1; i >= 0; i-- { // check if internet gateway IPv4 From 16b693815f26ab68c4bb5e69a1e52226fa7a19c8 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 7 Nov 2024 18:18:08 +0400 Subject: [PATCH 158/169] add cpu profiling endpoint --- controllers/server.go | 18 ++++++++++++++++++ logic/acls.go | 1 + logic/acls/nodeacls/retrieve.go | 1 + logic/proc.go | 23 +++++++++++++++++++++++ main.go | 3 +++ 5 files changed, 46 insertions(+) create mode 100644 logic/proc.go diff --git a/controllers/server.go b/controllers/server.go index 84f732b95..bcb4495e8 100644 --- a/controllers/server.go +++ b/controllers/server.go @@ -3,6 +3,7 @@ package controller import ( "encoding/json" "net/http" + "os" "strings" "syscall" "time" @@ -17,6 +18,8 @@ import ( "github.com/gravitl/netmaker/servercfg" ) +var cpuProfileLog *os.File + func serverHandlers(r *mux.Router) { // r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(true, http.HandlerFunc(addNetwork))).Methods(http.MethodPost) r.HandleFunc( @@ -43,6 +46,21 @@ func serverHandlers(r *mux.Router) { r.HandleFunc("/api/server/status", getStatus).Methods(http.MethodGet) r.HandleFunc("/api/server/usage", logic.SecurityCheck(false, http.HandlerFunc(getUsage))). Methods(http.MethodGet) + r.HandleFunc("/api/server/cpu_profile", cpuProfile). + Methods(http.MethodPost) +} + +func cpuProfile(w http.ResponseWriter, r *http.Request) { + start := r.URL.Query().Get("action") == "start" + if start { + os.Remove("/root/data/cpu.prof") + cpuProfileLog = logic.StartCPUProfiling() + } else { + if cpuProfileLog != nil { + logic.StopCPUProfiling(cpuProfileLog) + cpuProfileLog = nil + } + } } func getUsage(w http.ResponseWriter, _ *http.Request) { diff --git a/logic/acls.go b/logic/acls.go index 81b1f0b45..43500de20 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -458,6 +458,7 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { + return true if node.IsStatic { node = node.StaticNode.ConvertToStaticNode() } diff --git a/logic/acls/nodeacls/retrieve.go b/logic/acls/nodeacls/retrieve.go index 4411c5b22..46c7c8e0b 100644 --- a/logic/acls/nodeacls/retrieve.go +++ b/logic/acls/nodeacls/retrieve.go @@ -13,6 +13,7 @@ var NodesAllowedACLMutex = &sync.Mutex{} // AreNodesAllowed - checks if nodes are allowed to communicate in their network ACL func AreNodesAllowed(networkID NetworkID, node1, node2 NodeID) bool { + return true NodesAllowedACLMutex.Lock() defer NodesAllowedACLMutex.Unlock() var currentNetworkACL, err = FetchAllACLs(networkID) diff --git a/logic/proc.go b/logic/proc.go new file mode 100644 index 000000000..c602d6a4e --- /dev/null +++ b/logic/proc.go @@ -0,0 +1,23 @@ +package logic + +import ( + "log" + "os" + "runtime/pprof" +) + +func StartCPUProfiling() *os.File { + f, err := os.OpenFile("/root/data/cpu.prof", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0755) + if err != nil { + log.Fatal("could not create CPU profile: ", err) + } + if err := pprof.StartCPUProfile(f); err != nil { + log.Fatal("could not start CPU profile: ", err) + } + return f +} + +func StopCPUProfiling(f *os.File) { + pprof.StopCPUProfile() + f.Close() +} diff --git a/main.go b/main.go index 10bb52b8b..360ab9b78 100644 --- a/main.go +++ b/main.go @@ -51,6 +51,9 @@ func main() { logic.SetAllocatedIpMap() defer logic.ClearAllocatedIpMap() setGarbageCollection() + // Start profiling + // profFile := logic.StartCPUProfiling() + // defer logic.StopCPUProfiling(profFile) setVerbosity() if servercfg.DeployedByOperator() && !servercfg.IsPro { logic.SetFreeTierLimits() From f973d3d9e1ee324e81d4bb9833300609718d0471 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 7 Nov 2024 18:25:26 +0400 Subject: [PATCH 159/169] cache acls v1 --- logic/acls.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/logic/acls.go b/logic/acls.go index 43500de20..6e58529f9 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -5,12 +5,18 @@ import ( "errors" "fmt" "sort" + "sync" "time" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" ) +var ( + aclv1CacheMutex = &sync.RWMutex{} + aclv1CacheMap = make(map[string]models.Acl) +) + // CreateDefaultAclNetworkPolicies - create default acl network policies func CreateDefaultAclNetworkPolicies(netID models.NetworkID) { if netID.String() == "" { From 163bc9e6203234788994dae37ede5c32d2e9c2ff Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 7 Nov 2024 19:32:20 +0400 Subject: [PATCH 160/169] cache new acls --- logic/acls.go | 130 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 87 insertions(+), 43 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 6e58529f9..0228d7168 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -10,11 +10,12 @@ import ( "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/servercfg" ) var ( - aclv1CacheMutex = &sync.RWMutex{} - aclv1CacheMap = make(map[string]models.Acl) + aclCacheMutex = &sync.RWMutex{} + aclCacheMap = make(map[string]models.Acl) ) // CreateDefaultAclNetworkPolicies - create default acl network policies @@ -126,18 +127,57 @@ func ValidateCreateAclReq(req models.Acl) error { return nil } +func listAclFromCache() (acls []models.Acl) { + aclCacheMutex.RLock() + defer aclCacheMutex.RUnlock() + for _, acl := range aclCacheMap { + acls = append(acls, acl) + } + return +} + +func storeAclInCache(a models.Acl) { + aclCacheMutex.Lock() + defer aclCacheMutex.Unlock() + aclCacheMap[a.ID] = a +} + +func removeAclFromCache(a models.Acl) { + aclCacheMutex.Lock() + defer aclCacheMutex.Unlock() + delete(aclCacheMap, a.ID) +} + +func getAclFromCache(aID string) (a models.Acl, ok bool) { + aclCacheMutex.RLock() + defer aclCacheMutex.RUnlock() + a, ok = aclCacheMap[aID] + return +} + // InsertAcl - creates acl policy func InsertAcl(a models.Acl) error { d, err := json.Marshal(a) if err != nil { return err } - return database.Insert(a.ID, string(d), database.ACLS_TABLE_NAME) + err = database.Insert(a.ID, string(d), database.ACLS_TABLE_NAME) + if err == nil && servercfg.CacheEnabled() { + storeAclInCache(a) + } + return err } // GetAcl - gets acl info by id func GetAcl(aID string) (models.Acl, error) { a := models.Acl{} + if servercfg.CacheEnabled() { + var ok bool + a, ok = getAclFromCache(aID) + if ok { + return a, nil + } + } d, err := database.FetchRecord(database.ACLS_TABLE_NAME, aID) if err != nil { return a, err @@ -146,6 +186,9 @@ func GetAcl(aID string) (models.Acl, error) { if err != nil { return a, err } + if servercfg.CacheEnabled() { + storeAclInCache(a) + } return a, nil } @@ -260,7 +303,11 @@ func UpdateAcl(newAcl, acl models.Acl) error { if err != nil { return err } - return database.Insert(acl.ID, string(d), database.ACLS_TABLE_NAME) + err = database.Insert(acl.ID, string(d), database.ACLS_TABLE_NAME) + if err == nil && servercfg.CacheEnabled() { + storeAclInCache(acl) + } + return err } // UpsertAcl - upserts acl @@ -269,12 +316,20 @@ func UpsertAcl(acl models.Acl) error { if err != nil { return err } - return database.Insert(acl.ID, string(d), database.ACLS_TABLE_NAME) + err = database.Insert(acl.ID, string(d), database.ACLS_TABLE_NAME) + if err == nil && servercfg.CacheEnabled() { + storeAclInCache(acl) + } + return err } // DeleteAcl - deletes acl policy func DeleteAcl(a models.Acl) error { - return database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID) + err := database.DeleteRecord(database.ACLS_TABLE_NAME, a.ID) + if err == nil && servercfg.CacheEnabled() { + removeAclFromCache(a) + } + return err } // GetDefaultPolicy - fetches default policy in the network by ruleType @@ -311,19 +366,34 @@ func GetDefaultPolicy(netID models.NetworkID, ruleType models.AclPolicyType) (mo return acl, nil } -// ListUserPolicies - lists all acl policies enforced on an user -func ListUserPolicies(u models.User) []models.Acl { +func listAcls() (acls []models.Acl) { + if servercfg.CacheEnabled() && len(aclCacheMap) > 0 { + return listAclFromCache() + } + data, err := database.FetchRecords(database.ACLS_TABLE_NAME) if err != nil && !database.IsEmptyRecord(err) { return []models.Acl{} } - acls := []models.Acl{} + for _, dataI := range data { acl := models.Acl{} err := json.Unmarshal([]byte(dataI), &acl) if err != nil { continue } + acls = append(acls, acl) + if servercfg.CacheEnabled() { + storeAclInCache(acl) + } + } + return +} + +// ListUserPolicies - lists all acl policies enforced on an user +func ListUserPolicies(u models.User) []models.Acl { + acls := listAcls() + for _, acl := range acls { if acl.RuleType == models.UserPolicy { srcMap := convAclTagToValueMap(acl.Src) @@ -346,17 +416,9 @@ func ListUserPolicies(u models.User) []models.Acl { // listPoliciesOfUser - lists all user acl policies applied to user in an network func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl { - data, err := database.FetchRecords(database.ACLS_TABLE_NAME) - if err != nil && !database.IsEmptyRecord(err) { - return []models.Acl{} - } - acls := []models.Acl{} - for _, dataI := range data { - acl := models.Acl{} - err := json.Unmarshal([]byte(dataI), &acl) - if err != nil { - continue - } + + acls := listAcls() + for _, acl := range acls { if acl.NetworkID == netID && acl.RuleType == models.UserPolicy { srcMap := convAclTagToValueMap(acl.Src) if _, ok := srcMap[user.UserName]; ok { @@ -383,17 +445,8 @@ func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl { // listDevicePolicies - lists all device policies in a network func listDevicePolicies(netID models.NetworkID) []models.Acl { - data, err := database.FetchRecords(database.ACLS_TABLE_NAME) - if err != nil && !database.IsEmptyRecord(err) { - return []models.Acl{} - } - acls := []models.Acl{} - for _, dataI := range data { - acl := models.Acl{} - err := json.Unmarshal([]byte(dataI), &acl) - if err != nil { - continue - } + acls := listAcls() + for _, acl := range acls { if acl.NetworkID == netID && acl.RuleType == models.DevicePolicy { acls = append(acls, acl) } @@ -403,17 +456,9 @@ func listDevicePolicies(netID models.NetworkID) []models.Acl { // ListAcls - lists all acl policies func ListAcls(netID models.NetworkID) ([]models.Acl, error) { - data, err := database.FetchRecords(database.ACLS_TABLE_NAME) - if err != nil && !database.IsEmptyRecord(err) { - return []models.Acl{}, err - } - acls := []models.Acl{} - for _, dataI := range data { - acl := models.Acl{} - err := json.Unmarshal([]byte(dataI), &acl) - if err != nil { - continue - } + + acls := listAcls() + for _, acl := range acls { if acl.NetworkID == netID { acls = append(acls, acl) } @@ -464,7 +509,6 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) bool { // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer func IsNodeAllowedToCommunicate(node, peer models.Node) bool { - return true if node.IsStatic { node = node.StaticNode.ConvertToStaticNode() } From 574598a2a36251abef5467e8dd5acbd7a829259f Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Thu, 7 Nov 2024 21:55:19 +0400 Subject: [PATCH 161/169] fix acls cache --- logic/acls.go | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/logic/acls.go b/logic/acls.go index 0228d7168..334e6f160 100644 --- a/logic/acls.go +++ b/logic/acls.go @@ -392,18 +392,19 @@ func listAcls() (acls []models.Acl) { // ListUserPolicies - lists all acl policies enforced on an user func ListUserPolicies(u models.User) []models.Acl { - acls := listAcls() - for _, acl := range acls { + allAcls := listAcls() + userAcls := []models.Acl{} + for _, acl := range allAcls { if acl.RuleType == models.UserPolicy { srcMap := convAclTagToValueMap(acl.Src) if _, ok := srcMap[u.UserName]; ok { - acls = append(acls, acl) + userAcls = append(userAcls, acl) } else { // check for user groups for gID := range u.UserGroups { if _, ok := srcMap[gID.String()]; ok { - acls = append(acls, acl) + userAcls = append(userAcls, acl) break } } @@ -411,59 +412,61 @@ func ListUserPolicies(u models.User) []models.Acl { } } - return acls + return userAcls } // listPoliciesOfUser - lists all user acl policies applied to user in an network func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl { - - acls := listAcls() - for _, acl := range acls { + allAcls := listAcls() + userAcls := []models.Acl{} + for _, acl := range allAcls { if acl.NetworkID == netID && acl.RuleType == models.UserPolicy { srcMap := convAclTagToValueMap(acl.Src) if _, ok := srcMap[user.UserName]; ok { - acls = append(acls, acl) + userAcls = append(userAcls, acl) continue } for netRole := range user.NetworkRoles { if _, ok := srcMap[netRole.String()]; ok { - acls = append(acls, acl) + userAcls = append(userAcls, acl) continue } } for userG := range user.UserGroups { if _, ok := srcMap[userG.String()]; ok { - acls = append(acls, acl) + userAcls = append(userAcls, acl) continue } } } } - return acls + return userAcls } // listDevicePolicies - lists all device policies in a network func listDevicePolicies(netID models.NetworkID) []models.Acl { - acls := listAcls() - for _, acl := range acls { + allAcls := listAcls() + deviceAcls := []models.Acl{} + for _, acl := range allAcls { if acl.NetworkID == netID && acl.RuleType == models.DevicePolicy { - acls = append(acls, acl) + deviceAcls = append(deviceAcls, acl) } } - return acls + return deviceAcls } // ListAcls - lists all acl policies func ListAcls(netID models.NetworkID) ([]models.Acl, error) { - acls := listAcls() - for _, acl := range acls { + allAcls := listAcls() + netAcls := []models.Acl{} + for _, acl := range allAcls { if acl.NetworkID == netID { - acls = append(acls, acl) + netAcls = append(netAcls, acl) } } - return acls, nil + return netAcls, nil } func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} { From e6656209f92bf9cafd5940d743045d9cabad418f Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 8 Nov 2024 10:33:56 +0400 Subject: [PATCH 162/169] add default global roles to admin users --- logic/auth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/logic/auth.go b/logic/auth.go index 4a1873e66..031e5fd14 100644 --- a/logic/auth.go +++ b/logic/auth.go @@ -305,6 +305,7 @@ func UpdateUser(userchange, user *models.User) (*models.User, error) { } user.UserGroups = userchange.UserGroups user.NetworkRoles = userchange.NetworkRoles + AddGlobalNetRolesToAdmins(*user) err := ValidateUser(user) if err != nil { return &models.User{}, err From 32dfcecdff1a700e02b9ac708d8ea5abc673066d Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 8 Nov 2024 10:36:25 +0400 Subject: [PATCH 163/169] add security to cpu profile --- controllers/server.go | 2 +- main.go | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/controllers/server.go b/controllers/server.go index bcb4495e8..10f548280 100644 --- a/controllers/server.go +++ b/controllers/server.go @@ -46,7 +46,7 @@ func serverHandlers(r *mux.Router) { r.HandleFunc("/api/server/status", getStatus).Methods(http.MethodGet) r.HandleFunc("/api/server/usage", logic.SecurityCheck(false, http.HandlerFunc(getUsage))). Methods(http.MethodGet) - r.HandleFunc("/api/server/cpu_profile", cpuProfile). + r.HandleFunc("/api/server/cpu_profile", logic.SecurityCheck(false, http.HandlerFunc(cpuProfile))). Methods(http.MethodPost) } diff --git a/main.go b/main.go index 360ab9b78..10bb52b8b 100644 --- a/main.go +++ b/main.go @@ -51,9 +51,6 @@ func main() { logic.SetAllocatedIpMap() defer logic.ClearAllocatedIpMap() setGarbageCollection() - // Start profiling - // profFile := logic.StartCPUProfiling() - // defer logic.StopCPUProfiling(profFile) setVerbosity() if servercfg.DeployedByOperator() && !servercfg.IsPro { logic.SetFreeTierLimits() From bfc437bc9f14b1f7236a1614a8297cbb51d7448c Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 8 Nov 2024 10:37:43 +0400 Subject: [PATCH 164/169] add security to cpu profile --- logic/proc.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/logic/proc.go b/logic/proc.go index c602d6a4e..fec258d75 100644 --- a/logic/proc.go +++ b/logic/proc.go @@ -1,18 +1,19 @@ package logic import ( - "log" "os" "runtime/pprof" + + "github.com/gravitl/netmaker/logger" ) func StartCPUProfiling() *os.File { f, err := os.OpenFile("/root/data/cpu.prof", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0755) if err != nil { - log.Fatal("could not create CPU profile: ", err) + logger.Log(0, "could not create CPU profile: ", err.Error()) } if err := pprof.StartCPUProfile(f); err != nil { - log.Fatal("could not start CPU profile: ", err) + logger.Log(0, "could not start CPU profile: ", err.Error()) } return f } From a964d2bf7d1556ffb247a9aba6ab082c1e09cb3f Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 8 Nov 2024 10:44:30 +0400 Subject: [PATCH 165/169] set managed to false by default --- scripts/netmaker.default.env | 3 ++- servercfg/serverconf.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/netmaker.default.env b/scripts/netmaker.default.env index e66c2e93c..b8a65a1fa 100644 --- a/scripts/netmaker.default.env +++ b/scripts/netmaker.default.env @@ -92,4 +92,5 @@ PEER_UPDATE_BATCH=true PEER_UPDATE_BATCH_SIZE=50 # default domain for internal DNS lookup DEFAULT_DOMAIN=netmaker.hosted - +# managed dns setting, set to true to resolve dns entries on netmaker network +MANAGE_DNS=false diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index b9955b042..2cd80e983 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -657,7 +657,7 @@ func GetMetricInterval() string { // GetManageDNS - if manage DNS enabled or not func GetManageDNS() bool { - enabled := true + enabled := false if os.Getenv("MANAGE_DNS") != "" { enabled = os.Getenv("MANAGE_DNS") == "true" } From a7ccf13cc8232de4eba78342c395fbaada27ef87 Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 8 Nov 2024 10:46:06 +0400 Subject: [PATCH 166/169] default value set on acls --- logic/acls/nodeacls/retrieve.go | 1 - 1 file changed, 1 deletion(-) diff --git a/logic/acls/nodeacls/retrieve.go b/logic/acls/nodeacls/retrieve.go index 46c7c8e0b..4411c5b22 100644 --- a/logic/acls/nodeacls/retrieve.go +++ b/logic/acls/nodeacls/retrieve.go @@ -13,7 +13,6 @@ var NodesAllowedACLMutex = &sync.Mutex{} // AreNodesAllowed - checks if nodes are allowed to communicate in their network ACL func AreNodesAllowed(networkID NetworkID, node1, node2 NodeID) bool { - return true NodesAllowedACLMutex.Lock() defer NodesAllowedACLMutex.Unlock() var currentNetworkACL, err = FetchAllACLs(networkID) From ce93c9e0c11467654b8f6c002a8e4d7256ea930d Mon Sep 17 00:00:00 2001 From: abhishek9686 Date: Fri, 8 Nov 2024 10:55:43 +0400 Subject: [PATCH 167/169] add migrate fix on tags init --- logic/gateway.go | 3 +++ migrate/migrate.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/logic/gateway.go b/logic/gateway.go index 7d0539877..a92682c5e 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -180,6 +180,9 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq if node.Metadata == "" { node.Metadata = "This host can be used for remote access" } + if node.Tags == nil { + node.Tags = make(map[models.TagID]struct{}) + } node.Tags[models.TagID(fmt.Sprintf("%s.%s", netid, models.RemoteAccessTagName))] = struct{}{} err = UpsertNode(&node) if err != nil { diff --git a/migrate/migrate.go b/migrate/migrate.go index fe151c0c1..51e74ab4c 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -198,6 +198,10 @@ func updateNodes() { } for _, node := range nodes { node := node + if node.Tags == nil { + node.Tags = make(map[models.TagID]struct{}) + logic.UpsertNode(&node) + } if node.IsIngressGateway { tagID := models.TagID(fmt.Sprintf("%s.%s", node.Network, models.RemoteAccessTagName)) From b796331f3cf523b9ae732174aaccae26268be5b6 Mon Sep 17 00:00:00 2001 From: Abhishek K Date: Fri, 8 Nov 2024 13:38:17 +0400 Subject: [PATCH 168/169] preserver platfrom user admin role (#3187) --- pro/logic/migrate.go | 21 +++++++++++++++++++-- pro/logic/user_mgmt.go | 4 +--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pro/logic/migrate.go b/pro/logic/migrate.go index f7875f846..fedef3c9b 100644 --- a/pro/logic/migrate.go +++ b/pro/logic/migrate.go @@ -9,6 +9,9 @@ import ( func MigrateUserRoleAndGroups(user models.User) { var err error + if user.PlatformRoleID == models.AdminRole || user.PlatformRoleID == models.SuperAdminRole { + return + } if len(user.RemoteGwIDs) > 0 { // define user roles for network // assign relevant network role to user @@ -31,13 +34,27 @@ func MigrateUserRoleAndGroups(user models.User) { } } if len(user.NetworkRoles) > 0 { - for netID := range user.NetworkRoles { + for netID, netRoles := range user.NetworkRoles { var g models.UserGroup + adminAccess := false + for netRoleID := range netRoles { + permTemplate, err := logic.GetRole(netRoleID) + if err == nil { + if permTemplate.FullAccess { + adminAccess = true + } + } + } + if user.PlatformRoleID == models.ServiceUser { g, err = GetUserGroup(models.UserGroupID(fmt.Sprintf("%s-%s-grp", netID, models.NetworkUser))) } else { + role := models.NetworkUser + if adminAccess { + role = models.NetworkAdmin + } g, err = GetUserGroup(models.UserGroupID(fmt.Sprintf("%s-%s-grp", - netID, models.NetworkAdmin))) + netID, role))) } if err != nil { continue diff --git a/pro/logic/user_mgmt.go b/pro/logic/user_mgmt.go index 631459247..c3a6534ff 100644 --- a/pro/logic/user_mgmt.go +++ b/pro/logic/user_mgmt.go @@ -1229,9 +1229,7 @@ func AddGlobalNetRolesToAdmins(u models.User) { if u.PlatformRoleID != models.SuperAdminRole && u.PlatformRoleID != models.AdminRole { return } - if u.UserGroups == nil { - u.UserGroups = make(map[models.UserGroupID]struct{}) - } + u.UserGroups = make(map[models.UserGroupID]struct{}) u.UserGroups[models.UserGroupID(fmt.Sprintf("global-%s-grp", models.NetworkAdmin))] = struct{}{} logic.UpsertUser(u) } From 276998b1dda3bb541c0792bcda6f2a575a185d52 Mon Sep 17 00:00:00 2001 From: Abhishek K Date: Fri, 8 Nov 2024 13:38:30 +0400 Subject: [PATCH 169/169] v0.26.0 release notes (#3188) * v0.26.0 release notes * Update release.md --- release.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/release.md b/release.md index 3aec5059c..f2a6d82aa 100644 --- a/release.md +++ b/release.md @@ -1,21 +1,21 @@ # Netmaker v0.26.0 ## Whats New ✨ -- Advanced User Management with Network Roles and Groups -- User Invitation via Email and Magic Links +- New ACLs and Tag Management System +- Managed DNS system (Linux) +- Simplified User Mgmt With Default Roles and Groups (Hidden away network roles) +- New Add a Node Flow for netclient and static wireguard files ## What's Fixed/Improved 🛠 - -- Scalability Improvements -- Optimised Traffic Flow Over MQ -- Improved Peer Updates with Batching +- Metrics Data +- FailOver Stability Fixes +- Scalability Fixes ## Known Issues 🐞 -- Erratic Traffic Data In Metrics. - Adding Custom Private/Public Key For Remote Access Gw Clients Doesn't Get Propagated To Other Peers. - IPv6 DNS Entries Are Not Working. - Stale Peer On The Interface, When Forced Removed From Multiple Networks At Once. -- Can Still Ping Domain Name Even When DNS Toggle Is Switched Off. +- Can Still Ping The Domain Name Even When The DNS Toggle Is Switched Off. - WireGuard DNS issue on most flavours of Ubuntu 24.04 and some other newer Linux distributions. The issue is affecting the Remote Access Client (RAC) and the plain WireGuard external clients. Workaround can be found here https://help.netmaker.io/en/articles/9612016-extclient-rac-dns-issue-on-ubuntu-24-04.