Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
136 changes: 136 additions & 0 deletions client/cmd/kubeconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package cmd

import (
"context"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"
"google.golang.org/grpc/status"

"github.com/netbirdio/netbird/client/proto"
)

var (
kubeconfigOutput string
kubeconfigCluster string
kubeconfigContext string
kubeconfigUser string
kubeconfigServer string
kubeconfigNamespace string
)

var kubeconfigCmd = &cobra.Command{
Use: "kubeconfig",
Short: "Generate kubeconfig for accessing Kubernetes via NetBird",
Long: `Generate a kubeconfig file that points to a Kubernetes cluster accessible via NetBird.

The generated kubeconfig uses a dummy bearer token for authentication when the
cluster's auth proxy is running in 'auth' mode. The actual authentication is
handled by the NetBird network - the auth proxy identifies users by their
NetBird peer IP and impersonates them in the Kubernetes API.

Example:
netbird kubeconfig --server https://k8s.example.netbird.cloud:6443 --cluster my-cluster
netbird kubeconfig --server https://10.100.0.1:6443 -o ~/.kube/netbird-config`,
RunE: kubeconfigFunc,
}

// init configures command-line flags for the kubeconfig command.
// It registers flags for output path, cluster, context, user, server, and namespace
// and marks the server flag as required.
func init() {
kubeconfigCmd.Flags().StringVarP(&kubeconfigOutput, "output", "o", "", "Output file path (default: stdout)")
kubeconfigCmd.Flags().StringVar(&kubeconfigCluster, "cluster", "netbird-cluster", "Cluster name in kubeconfig")
kubeconfigCmd.Flags().StringVar(&kubeconfigContext, "context", "netbird", "Context name in kubeconfig")
kubeconfigCmd.Flags().StringVar(&kubeconfigUser, "user", "netbird-user", "User name in kubeconfig")
kubeconfigCmd.Flags().StringVar(&kubeconfigServer, "server", "", "Kubernetes API server URL (required)")
kubeconfigCmd.Flags().StringVar(&kubeconfigNamespace, "namespace", "default", "Default namespace")
_ = kubeconfigCmd.MarkFlagRequired("server")
}

// kubeconfigFunc generates a kubeconfig file for accessing Kubernetes via the NetBird auth proxy.
// KUBECONFIG and running kubectl.
func kubeconfigFunc(cmd *cobra.Command, args []string) error {
ctx := context.Background()

// Get current NetBird status to verify connection
conn, err := DialClientGRPCServer(ctx, daemonAddr)
if err != nil {
cmd.PrintErrf("Warning: Could not connect to NetBird daemon: %v\n", err)
cmd.PrintErrln("Generating kubeconfig anyway, but make sure NetBird is running before using it.")
} else {
defer conn.Close()

resp, err := proto.NewDaemonServiceClient(conn).Status(ctx, &proto.StatusRequest{})
if err != nil {
cmd.PrintErrf("Warning: Could not get NetBird status: %v\n", status.Convert(err).Message())
} else if resp.Status != "Connected" {
cmd.PrintErrf("Warning: NetBird is not connected (status: %s)\n", resp.Status)
cmd.PrintErrln("Make sure to run 'netbird up' before using the generated kubeconfig.")
}
}

kubeconfig := generateKubeconfig(kubeconfigServer, kubeconfigCluster, kubeconfigContext, kubeconfigUser, kubeconfigNamespace)

if kubeconfigOutput == "" {
fmt.Println(kubeconfig)
return nil
}

// Expand ~ in path
if strings.HasPrefix(kubeconfigOutput, "~/") {
home, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get home directory: %w", err)
}
kubeconfigOutput = filepath.Join(home, kubeconfigOutput[2:])
}

// Create directory if needed
dir := filepath.Dir(kubeconfigOutput)
if err := os.MkdirAll(dir, 0700); err != nil {
return fmt.Errorf("failed to create directory %s: %w", dir, err)
}

if err := os.WriteFile(kubeconfigOutput, []byte(kubeconfig), 0600); err != nil {
return fmt.Errorf("failed to write kubeconfig: %w", err)
}

cmd.Printf("Kubeconfig written to %s\n", kubeconfigOutput)
cmd.PrintErrln("\nWarning: TLS verification is disabled (insecure-skip-tls-verify: true).")
cmd.PrintErrln("This is safe when traffic is encrypted via NetBird's WireGuard tunnel.")
cmd.Printf("\nTo use this kubeconfig:\n")
cmd.Printf(" export KUBECONFIG=%s\n", kubeconfigOutput)
cmd.Printf(" kubectl get nodes\n")

return nil
}

// generateKubeconfig creates a kubeconfig YAML string with the given parameters.
// generateKubeconfig generates a kubeconfig YAML for accessing the specified Kubernetes API server via NetBird.
// The returned config sets the current context to the provided context, includes the given cluster, user, and namespace,
// enables `insecure-skip-tls-verify: true`, and embeds the static token `netbird-auth-proxy`.
func generateKubeconfig(server, cluster, context, user, namespace string) string {
return fmt.Sprintf(`apiVersion: v1
kind: Config
clusters:
- cluster:
insecure-skip-tls-verify: true
server: %s
name: %s
contexts:
- context:
cluster: %s
namespace: %s
user: %s
name: %s
current-context: %s
users:
- name: %s
user:
token: netbird-auth-proxy
`, server, cluster, cluster, namespace, user, context, context, user)
}
13 changes: 9 additions & 4 deletions client/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,16 @@ var (

// Execute executes the root command.
func Execute() error {
if isUpdateBinary() {
return updateCmd.Execute()
}
return rootCmd.Execute()
}

// init initializes package-level defaults and configures the root CLI command.
// It sets OS-specific default paths for configuration and logs, determines the default
// daemon address, registers persistent CLI flags (daemon address, management/admin URLs,
// logging, setup key options, pre-shared key, hostname, anonymization, and config path),
// and wires up all top-level and nested subcommands. It also defines upCmd-specific
// flags for external IP mapping, custom DNS resolver address, Rosenpass options,
// auto-connect control, and lazy connection.
func init() {
defaultConfigPathDir = "/etc/netbird/"
defaultLogFileDir = "/var/log/netbird/"
Expand Down Expand Up @@ -144,6 +148,7 @@ func init() {
rootCmd.AddCommand(forwardingRulesCmd)
rootCmd.AddCommand(debugCmd)
rootCmd.AddCommand(profileCmd)
rootCmd.AddCommand(kubeconfigCmd)

networksCMD.AddCommand(routesListCmd)
networksCMD.AddCommand(routesSelectCmd, routesDeselectCmd)
Expand Down Expand Up @@ -396,4 +401,4 @@ func getClient(cmd *cobra.Command) (*grpc.ClientConn, error) {
}

return conn, nil
}
}
78 changes: 65 additions & 13 deletions management/internals/shared/grpc/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"strings"

integrationsConfig "github.com/netbirdio/management-integrations/integrations/config"

nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller/cache"
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
Expand Down Expand Up @@ -84,6 +83,10 @@
return nbConfig
}

// toPeerConfig builds a proto.PeerConfig from internal peer, network, DNS name, and settings.
//
// The returned PeerConfig includes the peer's IP with network mask, FQDN, SSH configuration
// (including JWT config when SSH is enabled), and flags for routing DNS resolution and lazy connections.
func toPeerConfig(peer *nbpeer.Peer, network *types.Network, dnsName string, settings *types.Settings, httpConfig *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow) *proto.PeerConfig {
netmask, _ := network.Net.Mask.Size()
fqdn := peer.FQDN(dnsName)
Expand All @@ -102,20 +105,25 @@
Fqdn: fqdn,
RoutingPeerDnsResolutionEnabled: settings.RoutingPeerDNSResolutionEnabled,
LazyConnectionEnabled: settings.LazyConnectionEnabled,
AutoUpdate: &proto.AutoUpdateSettings{
Version: settings.AutoUpdateVersion,
},
}
}

func ToSyncResponse(ctx context.Context, config *nbconfig.Config, httpConfig *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow, peer *nbpeer.Peer, turnCredentials *Token, relayCredentials *Token, networkMap *types.NetworkMap, dnsName string, checks []*posture.Checks, dnsCache *cache.DNSConfigCache, settings *types.Settings, extraSettings *types.ExtraSettings, peerGroups []string, dnsFwdPort int64) *proto.SyncResponse {
// ToSyncResponse constructs a proto.SyncResponse that bundles the peer's runtime configuration,
// network map (routes, DNS, peer lists, firewall and forwarding rules), Netbird configuration,
// and posture checks for a sync operation.
//
// The response includes PeerConfig, NetworkMap (with Serial, Routes, DNSConfig, PeerConfig,
// RemotePeers, OfflinePeers, FirewallRules, RoutesFirewallRules, and ForwardingRules when present),
// NetbirdConfig (extended with integrations), and Checks. Remote peer lists' "IsEmpty" flags are
// set based on their lengths. If remotePeerGroupsLookup is non-nil, each remote peer's Groups and
// UserId fields are populated using GetPeerGroupNames for that peer.
func ToSyncResponse(ctx context.Context, config *nbconfig.Config, httpConfig *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow, peer *nbpeer.Peer, turnCredentials *Token, relayCredentials *Token, networkMap *types.NetworkMap, dnsName string, checks []*posture.Checks, dnsCache *cache.DNSConfigCache, settings *types.Settings, extraSettings *types.ExtraSettings, peerGroups []string, dnsFwdPort int64, remotePeerGroupsLookup PeerGroupsLookup) *proto.SyncResponse {
response := &proto.SyncResponse{
PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, settings, httpConfig, deviceFlowConfig),
NetworkMap: &proto.NetworkMap{
Serial: networkMap.Network.CurrentSerial(),
Routes: toProtocolRoutes(networkMap.Routes),
DNSConfig: toProtocolDNSConfig(networkMap.DNSConfig, dnsCache, dnsFwdPort),
PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, settings, httpConfig, deviceFlowConfig),
Serial: networkMap.Network.CurrentSerial(),
Routes: toProtocolRoutes(networkMap.Routes),
DNSConfig: toProtocolDNSConfig(networkMap.DNSConfig, dnsCache, dnsFwdPort),
},
Checks: toProtocolChecks(ctx, checks),
}
Expand All @@ -127,13 +135,13 @@
response.NetworkMap.PeerConfig = response.PeerConfig

remotePeers := make([]*proto.RemotePeerConfig, 0, len(networkMap.Peers)+len(networkMap.OfflinePeers))
remotePeers = appendRemotePeerConfig(remotePeers, networkMap.Peers, dnsName)
remotePeers = appendRemotePeerConfig(remotePeers, networkMap.Peers, dnsName, remotePeerGroupsLookup)
response.RemotePeers = remotePeers
response.NetworkMap.RemotePeers = remotePeers
response.RemotePeersIsEmpty = len(remotePeers) == 0
response.NetworkMap.RemotePeersIsEmpty = response.RemotePeersIsEmpty

response.NetworkMap.OfflinePeers = appendRemotePeerConfig(nil, networkMap.OfflinePeers, dnsName)
response.NetworkMap.OfflinePeers = appendRemotePeerConfig(nil, networkMap.OfflinePeers, dnsName, remotePeerGroupsLookup)

firewallRules := toProtocolFirewallRules(networkMap.FirewallRules)
response.NetworkMap.FirewallRules = firewallRules
Expand All @@ -154,14 +162,58 @@
return response
}

func appendRemotePeerConfig(dst []*proto.RemotePeerConfig, peers []*nbpeer.Peer, dnsName string) []*proto.RemotePeerConfig {
// PeerGroupsLookup provides group names for a peer ID
type PeerGroupsLookup interface {
GetPeerGroupNames(peerID string) []string
}

// AccountPeerGroupsLookup implements PeerGroupsLookup using a pre-built reverse index
// for O(1) lookup performance instead of O(N*M) iteration.
type AccountPeerGroupsLookup struct {
peerToGroups map[string][]string
}

// NewAccountPeerGroupsLookup creates a new AccountPeerGroupsLookup from an Account.
// NewAccountPeerGroupsLookup builds an AccountPeerGroupsLookup containing a reverse index
// from peer ID to the names of groups that include that peer. If account is nil, it returns nil.
func NewAccountPeerGroupsLookup(account *types.Account) *AccountPeerGroupsLookup {
if account == nil {
return nil
}
peerToGroups := make(map[string][]string)
for _, group := range account.Groups {
for _, peerID := range group.Peers {
peerToGroups[peerID] = append(peerToGroups[peerID], group.Name)
}
}
return &AccountPeerGroupsLookup{peerToGroups: peerToGroups}
}

// GetPeerGroupNames returns the group names for a given peer ID.
// Returns nil if the peer is not found in any group.
func (a *AccountPeerGroupsLookup) GetPeerGroupNames(peerID string) []string {
if a == nil || a.peerToGroups == nil {
return nil
}
return a.peerToGroups[peerID]
}

// appendRemotePeerConfig appends a RemotePeerConfig for each peer in peers to dst.
// For each peer it adds a RemotePeerConfig populated with the WireGuard public key, an /32 allowed IP derived from the peer IP, SSH public key, FQDN (computed using dnsName), agent version, group names retrieved from groupsLookup when provided, and the user ID, and returns the extended slice.
func appendRemotePeerConfig(dst []*proto.RemotePeerConfig, peers []*nbpeer.Peer, dnsName string, groupsLookup PeerGroupsLookup) []*proto.RemotePeerConfig {
for _, rPeer := range peers {
var groups []string
if groupsLookup != nil {
groups = groupsLookup.GetPeerGroupNames(rPeer.ID)
}
dst = append(dst, &proto.RemotePeerConfig{
WgPubKey: rPeer.Key,
AllowedIps: []string{rPeer.IP.String() + "/32"},
SshConfig: &proto.SSHConfig{SshPubKey: []byte(rPeer.SSHKey)},
Fqdn: rPeer.FQDN(dnsName),
AgentVersion: rPeer.Meta.WtVersion,
Groups: groups,

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Integration (amd64, postgres)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Integration (amd64, sqlite)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (API) (amd64, postgres)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (API) (amd64, sqlite)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Unit (amd64, sqlite)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Unit (amd64, mysql)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Unit (amd64, postgres)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Darwin

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Darwin

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Darwin

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (amd64, postgres)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / JS / Lint

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / JS / Lint

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / JS / Lint

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (amd64, sqlite)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Linux

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Linux

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Linux

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit (386)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit (amd64)

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client (Docker) / Unit

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 215 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit

unknown field Groups in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig
UserId: rPeer.UserID,

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Integration (amd64, postgres)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Integration (amd64, sqlite)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (API) (amd64, postgres)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (API) (amd64, sqlite)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Unit (amd64, sqlite)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Unit (amd64, mysql)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Unit (amd64, postgres)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Darwin

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Darwin

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (amd64, postgres)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / JS / Lint

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / JS / Lint

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Management / Benchmark (amd64, sqlite)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Linux

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Linux

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit (386)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit (amd64)

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client (Docker) / Unit

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig

Check failure on line 216 in management/internals/shared/grpc/conversion.go

View workflow job for this annotation

GitHub Actions / Client / Unit

unknown field UserId in struct literal of type "github.com/netbirdio/netbird/shared/management/proto".RemotePeerConfig
})
}
return dst
Expand Down Expand Up @@ -407,4 +459,4 @@
}

return fmt.Sprintf("%s://%s/", u.Scheme, u.Host)
}
}
Loading