Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5acf1c9
wip(go): set tenant id header when calling netmaker apis;
VishalDalwadi Jul 15, 2026
c9f46ee
wip(go): add tenant id for flow logs;
VishalDalwadi Jul 15, 2026
a76c633
wip(go): remove tenant header on register; always user tenant id from…
VishalDalwadi Jul 15, 2026
272c551
Merge branch 'develop' of https://github.com/gravitl/netclient into N…
VishalDalwadi Jul 28, 2026
4064894
wip(go): update netmaker dep;
VishalDalwadi Jul 28, 2026
ab55ea4
wip(go): store each host id corresponding to each tenant id;
VishalDalwadi Jul 30, 2026
2e5bf99
wip(go): pass empty tenant id for sso;
VishalDalwadi Jul 30, 2026
dcf3d61
wip(go): set mqid from host id;
VishalDalwadi Aug 3, 2026
984b229
wip(go): generate new host id for new server;
VishalDalwadi Aug 3, 2026
caa8d19
wip(go): use host ids map instead of mqid;
VishalDalwadi Aug 3, 2026
3485f09
wip(go): add tenant id flag to netclient server leave and switch;
VishalDalwadi Aug 3, 2026
cb83a7e
wip(go): remove tenant id arg from switch;
VishalDalwadi Aug 4, 2026
3aee6cb
wip(go): backfill host id for older clients;
VishalDalwadi Aug 4, 2026
3dcb513
wip(go): switch tenants on leave if leaving active tenant;
VishalDalwadi Aug 4, 2026
c723f6f
wip(go): get server by api host;
VishalDalwadi Aug 4, 2026
50d5b7d
wip(go): ignore igw egress;
VishalDalwadi Aug 4, 2026
8b1f855
wip(go): use tenant id from host object;
VishalDalwadi Aug 5, 2026
5b5f3cb
wip(go): copy server with tenant id changed to leave inactive tenant;
VishalDalwadi Aug 5, 2026
fb6bf79
wip(go): log on leave;
VishalDalwadi Aug 5, 2026
42ca640
wip(go): verify active/inactive; check if other hosts exist on same t…
VishalDalwadi Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/gravitl/netclient/wireguard"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/scope"
)

var (
Expand Down Expand Up @@ -55,12 +56,13 @@ func Authenticate(server *config.Server, host *config.Config) (string, error) {
url := fmt.Sprintf("https://%s/api/hosts/adm/authenticate", server.API)
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set(scope.HeaderTenantID, host.TenantID)
respBytes, err := ncutils.SendRequest(http.MethodPost, url, headers, data)
if err != nil {
var notOkErr ncutils.ErrStatusNotOk
if errors.As(err, &notOkErr) {
if notOkErr.Status == http.StatusUnauthorized {
if err := cleanUpByServer(server); err != nil {
if err := cleanUpByServer(server, host); err != nil {
return "", err
}

Expand All @@ -85,7 +87,7 @@ func Authenticate(server *config.Server, host *config.Config) (string, error) {
return token.(string), nil
}

func cleanUpByServer(server *config.Server) error {
func cleanUpByServer(server *config.Server, host *config.Config) error {
if err := config.ReadNodeConfig(); err != nil {
return err
}
Expand All @@ -111,7 +113,19 @@ func cleanUpByServer(server *config.Server) error {
if err := config.WriteNetclientConfig(); err != nil {
return err
}
config.DeleteServer(server.Name)

freshServer := config.GetServer(server.Name)
if freshServer != nil && host != nil && host.TenantID != "" {
logger.Log(0, "removing unauthorized tenant", host.TenantID, "from", server.Name)
delete(freshServer.HostIDs, host.TenantID)
if len(freshServer.HostIDs) == 0 {
config.DeleteServer(server.Name)
} else {
config.UpdateServer(server.Name, *freshServer)
}
} else {
config.DeleteServer(server.Name)
}
if err := config.WriteServerConfig(); err != nil {
return err
}
Expand Down
14 changes: 12 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,19 @@ func checkConfig() {
fail = true
logger.Log(0, "configuration for", config.CurrServer, "is missing")
} else {
if server.MQID != netclient.ID {
if len(server.HostIDs) == 0 && netclient.ID != uuid.Nil {
// pre-multi-tenancy configs predate the HostIDs map; backfill it
// from the existing single host id instead of failing
logger.Log(0, "backfilling host id for", server.Name)
server.HostIDs = map[string]uuid.UUID{netclient.TenantID: netclient.ID}
config.UpdateServer(server.Name, *server)
if err := config.WriteServerConfig(); err != nil {
logger.Log(0, "failed to save server", server.Name, err.Error())
}
}
if server.HostIDs[netclient.TenantID] != netclient.ID {
fail = true
logger.Log(0, server.Name, "is misconfigured: MQID/Password does not match hostid/password")
logger.Log(0, server.Name, "is misconfigured: registered host ID does not match hostid/password")
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ func init() {
serverCmd.AddCommand(listServersCmd)
serverCmd.AddCommand(switchServerCmd)

leaveServerCmd.Flags().String("tenant-id", "", "leave only the specified tenant on the server")

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
Expand All @@ -53,10 +55,11 @@ func init() {
var leaveServerCmd = &cobra.Command{
Use: "leave [servername]",
Short: "leave a server",
Long: `leave the specified server`,
Long: `leave the specified server. Use --tenant-id to leave only that tenant; omit it to leave every tenant registered on the server.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
if err := functions.LeaveServer(args[0]); err != nil {
tenantID, _ := cmd.Flags().GetString("tenant-id")
if err := functions.LeaveServer(args[0], tenantID); err != nil {
fmt.Println(err.Error())
}
},
Expand Down
31 changes: 23 additions & 8 deletions config/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/google/uuid"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/schema"
)

var serverMutex sync.RWMutex
Expand All @@ -27,12 +28,12 @@ const ServerLockfile = "netclient-servers.lck"
// Server represents a server configuration
type Server struct {
models.ServerConfig
Name string `json:"name" yaml:"name"`
MQID uuid.UUID `json:"mqid" yaml:"mqid"`
Nodes map[string]bool `json:"nodes" yaml:"nodes"`
AccessKey string `json:"accesskey" yaml:"accesskey"`
NameServers []string `json:"name_servers"`
DnsNameservers []models.Nameserver `json:"dns_nameservers"`
HostIDs map[string]uuid.UUID `json:"host_ids"`
Name string `json:"name" yaml:"name"`
Nodes map[string]bool `json:"nodes" yaml:"nodes"`
AccessKey string `json:"accesskey" yaml:"accesskey"`
NameServers []string `json:"name_servers"`
DnsNameservers []models.Nameserver `json:"dns_nameservers"`
}

// TurnConfig - struct to hold turn server config
Expand Down Expand Up @@ -108,6 +109,17 @@ func GetServer(name string) *Server {
return nil
}

func GetServerByAPIHost(apiHost string) *Server {
serverMutex.RLock()
defer serverMutex.RUnlock()
for _, server := range Servers {
if server.APIHost == apiHost {
return &server
}
}
return nil
}

// GetServers - gets all the server names host has registered to.
func GetServers() (servers []string) {
serverMutex.RLock()
Expand Down Expand Up @@ -164,7 +176,7 @@ func DeleteServer(k string) {
}

// UpdateServerConfig updates the in memory server map with values provided from netmaker server
func UpdateServerConfig(cfg *models.ServerConfig) {
func UpdateServerConfig(cfg *models.ServerConfig, host *schema.Host) {
serverMutex.Lock()
defer serverMutex.Unlock()
if cfg == nil {
Expand All @@ -175,8 +187,11 @@ func UpdateServerConfig(cfg *models.ServerConfig) {
server = Server{}
server.Nodes = make(map[string]bool)
}
if server.HostIDs == nil {
server.HostIDs = make(map[string]uuid.UUID)
}
server.HostIDs[host.TenantID] = host.ID
server.Name = cfg.Server
server.MQID = netclient.ID
server.ServerConfig = *cfg
Servers[cfg.Server] = server
}
5 changes: 5 additions & 0 deletions flow/manager_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,15 @@ func (m *Manager) Start(participantIdentifiers map[string]models.PeerIdentity) e
identity, found := m.participantIdentifiers[ipCidr]
if !found {
for addr := range m.participantIdentifiers {
if addr == "0.0.0.0/0" || addr == "::/0" {
continue
}

_, cidr, err := net.ParseCIDR(addr)
if err != nil {
continue
}

if cidr.Contains(net.ParseIP(ip)) {
identity, found = m.participantIdentifiers[addr]
break
Expand Down
1 change: 1 addition & 0 deletions flow/tracker/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ func (c *FlowTracker) handleEvent(event ct.Event) error {

return c.flowExporter.Export(&pbflow.FlowEvent{
Type: eventType,
TenantId: config.Netclient().TenantID,
FlowId: flowID,
HostId: c.hostIDStr,
HostName: config.Netclient().Name,
Expand Down
2 changes: 2 additions & 0 deletions functions/auto_relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/schema"
"github.com/gravitl/netmaker/scope"

"golang.org/x/exp/slog"
)
Expand Down Expand Up @@ -560,6 +561,7 @@ func autoRelayME(method, serverName, nodeID, peernodeID, relayID string) error {
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set("Authorization", "Bearer "+token)
headers.Set(scope.HeaderTenantID, host.TenantID)
_, err = ncutils.SendRequest(method, url, headers, models.AutoRelayMeReq{NodeID: peernodeID, AutoRelayGwID: relayID})
if err != nil {
return err
Expand Down
7 changes: 5 additions & 2 deletions functions/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

mqtt "github.com/eclipse/paho.mqtt.golang"
externalip "github.com/glendc/go-external-ip"
"github.com/google/uuid"
"github.com/gravitl/netclient/auth"
"github.com/gravitl/netclient/cache"
"github.com/gravitl/netclient/config"
Expand Down Expand Up @@ -595,8 +596,10 @@ func unsubscribeNode(client mqtt.Client, node *config.Node) {
}

// unsubscribe client broker communications for host topics
func unsubscribeHost(client mqtt.Client, server string) {
hostID := config.Netclient().ID
func unsubscribeHost(client mqtt.Client, server string, hostID uuid.UUID) {
if hostID != config.Netclient().ID {
return
}
slog.Info("removing subscription for host peer updates", "host", hostID, "server", server)
if token := client.Unsubscribe(fmt.Sprintf("peers/host/%s/%s", hostID.String(), server)); token.WaitTimeout(MQ_TIMEOUT*time.Second) && token.Error() != nil {
slog.Error("unable to unsubscribe from host peer updates", "host", hostID, "server", server, "error", token.Error())
Expand Down
2 changes: 2 additions & 0 deletions functions/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/gravitl/netclient/ncutils"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/scope"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

Expand Down Expand Up @@ -103,6 +104,7 @@ func GetNodePeers(node config.Node) ([]wgtypes.PeerConfig, error) {
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set("Authorization", "Bearer "+token)
headers.Set(scope.HeaderTenantID, host.TenantID)
respBytes, err := ncutils.SendRequest(http.MethodGet, url, headers, nil)
if err != nil {
return nil, err
Expand Down
21 changes: 17 additions & 4 deletions functions/mqhandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/schema"
"github.com/gravitl/netmaker/scope"
"golang.org/x/exp/slog"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
Expand Down Expand Up @@ -492,8 +493,8 @@ func HostUpdate(client mqtt.Client, msg mqtt.Message) {
resetInterface = true
case models.DeleteHost:
clearRetainedMsg(client, msg.Topic())
unsubscribeHost(client, serverName)
deleteHostCfg(client, serverName)
unsubscribeHost(client, serverName, hostUpdate.Host.ID)
deleteHostCfg(client, serverName, hostUpdate.Host.TenantID)
config.WriteNodeConfig()
config.WriteServerConfig()
config.DeleteClientNodes()
Expand Down Expand Up @@ -648,7 +649,7 @@ func handleEndpointDetection(peers []wgtypes.PeerConfig, peerInfo models.HostInf
}
}

func deleteHostCfg(client mqtt.Client, server string) {
func deleteHostCfg(client mqtt.Client, server, tenantID string) {
config.DeleteServerHostPeerCfg()
nodes := config.GetNodes()
for k, node := range nodes {
Expand All @@ -658,7 +659,18 @@ func deleteHostCfg(client mqtt.Client, server string) {
config.DeleteNode(k)
}
}
config.DeleteServer(server)

srvCfg := config.GetServer(server)
if srvCfg != nil && tenantID != "" {
delete(srvCfg.HostIDs, tenantID)
if len(srvCfg.HostIDs) == 0 {
config.DeleteServer(server)
} else {
config.UpdateServer(server, *srvCfg)
}
} else {
config.DeleteServer(server)
}
}

func parseNetworkFromTopic(topic string) string {
Expand Down Expand Up @@ -719,6 +731,7 @@ func getServerBrokerStatus() (bool, error) {
url := fmt.Sprintf("https://%s/api/server/status", server.API)
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set(scope.HeaderTenantID, config.Netclient().TenantID)
respBytes, err := ncutils.SendRequest(http.MethodGet, url, headers, nil)
if err != nil {
logger.Log(1, "failed to read from server during metrics publish", err.Error())
Expand Down
2 changes: 2 additions & 0 deletions functions/mqpublish.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/schema"
"github.com/gravitl/netmaker/scope"
"github.com/gravitl/netmaker/utils"
"golang.org/x/exp/slog"
)
Expand Down Expand Up @@ -194,6 +195,7 @@ func hostUpdateWithServer(server *config.Server, hu models.HostUpdate) error {
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set("Authorization", "Bearer "+token)
headers.Set(scope.HeaderTenantID, host.TenantID)
_, err = ncutils.SendRequest(http.MethodPut, url, headers, buildHostUpdatePayload(hu))
if err != nil {
if denyErr := auth.AsMDMDenied(err); errors.Is(denyErr, auth.ErrMDMDenied) {
Expand Down
4 changes: 3 additions & 1 deletion functions/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/gravitl/netclient/wireguard"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/scope"
)

var pMutex = sync.Mutex{} // used to mutex functions for pull
Expand All @@ -39,6 +40,7 @@ func Pull(restart bool, resetIfFailedOvered bool) (models.HostPull, bool, bool,
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set("Authorization", "Bearer "+token)
headers.Set(scope.HeaderTenantID, config.Netclient().TenantID)
respBytes, err := ncutils.SendRequest(http.MethodGet, url, headers, nil)
if err != nil {
if denyErr := auth.AsMDMDenied(err); errors.Is(denyErr, auth.ErrMDMDenied) {
Expand Down Expand Up @@ -82,7 +84,7 @@ func Pull(restart bool, resetIfFailedOvered bool) (models.HostPull, bool, bool,
}
replacePeers = wireguard.ShouldReplace(pullResponse.Peers)
config.UpdateHostPeers(pullResponse.Peers)
config.UpdateServerConfig(&pullResponse.ServerConfig)
config.UpdateServerConfig(&pullResponse.ServerConfig, &pullResponse.Host)
config.SetNodes(pullResponse.Nodes)
UpdateHostFromServer(&pullResponse.Host)
server = config.GetServer(serverName)
Expand Down
18 changes: 15 additions & 3 deletions functions/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/gravitl/netclient/posture"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/scope"
)

// Register - should be simple to register with a token
Expand Down Expand Up @@ -44,7 +45,7 @@ func Register(token string) error {
} else if defaultInterface != ncutils.GetInterfaceName() {
host.DefaultInterface = defaultInterface
}
shouldUpdateHost, err := doubleCheck(host)
shouldUpdateHost, err := doubleCheck(serverData.Server, serverData.TenantID, host)
if err != nil {
logger.FatalLog(fmt.Sprintf("error when checking host values - %v", err.Error()))
}
Expand All @@ -55,6 +56,7 @@ func Register(token string) error {
url := fmt.Sprintf("https://%s/api/v1/host/register/%s", serverData.Server, token)
headers := make(http.Header)
headers.Set("Content-Type", "application/json")
headers.Set(scope.HeaderTenantID, serverData.TenantID)
posture.ApplyIdentity(&host.Host)
respBytes, err := ncutils.SendRequest(http.MethodPost, url, headers, host)
if err != nil {
Expand All @@ -81,7 +83,7 @@ func Register(token string) error {
return nil
}

func doubleCheck(host *config.Config) (shouldUpdate bool, err error) {
func doubleCheck(server, tenantID string, host *config.Config) (shouldUpdate bool, err error) {
var shouldUpdateHost bool

if len(config.CurrServer) == 0 { // should indicate a first join
Expand All @@ -107,6 +109,16 @@ func doubleCheck(host *config.Config) (shouldUpdate bool, err error) {
host.HostPass = ncutils.RandomString(32)
shouldUpdateHost = true
}
} else if tenantID != "" {
var hostIDs map[string]uuid.UUID
if server := config.GetServerByAPIHost(server); server != nil {
hostIDs = server.HostIDs
}
if existingID, ok := hostIDs[tenantID]; ok {
host.ID = existingID
} else if host.ID, err = uuid.NewUUID(); err != nil {
return false, err
}
}

if shouldUpdateHost {
Expand All @@ -118,7 +130,7 @@ func doubleCheck(host *config.Config) (shouldUpdate bool, err error) {
}

func handleRegisterResponse(registerResponse *models.RegisterResponse) {
config.UpdateServerConfig(&registerResponse.ServerConf)
config.UpdateServerConfig(&registerResponse.ServerConf, &registerResponse.RequestedHost)
server := config.GetServer(registerResponse.ServerConf.Server)
if err := config.SaveServer(registerResponse.ServerConf.Server, *server); err != nil {
logger.Log(0, "failed to save server", err.Error())
Expand Down
Loading