From 8ac627d8452c1ea767d496da871b68cdd017155d Mon Sep 17 00:00:00 2001 From: Yury Gargay Date: Wed, 31 Jan 2024 16:02:24 +0100 Subject: [PATCH] Extract peer real IP from Load Balancer when possible (#1510) --- go.mod | 3 ++- go.sum | 5 ++++- management/cmd/management.go | 18 +++++++++++++++++- management/server/config.go | 3 +++ management/server/grpcserver.go | 24 +++++++++++++----------- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 1bdf78a3a73..31db5dbe7d2 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 golang.zx2c4.com/wireguard/windows v0.5.3 google.golang.org/grpc v1.56.3 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) @@ -47,6 +47,7 @@ require ( github.com/google/go-cmp v0.5.9 github.com/google/gopacket v1.1.19 github.com/google/nftables v0.0.0-20220808154552-2eca00135732 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240129190346-220740bc30b1 github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 github.com/hashicorp/go-version v1.6.0 github.com/libp2p/go-netroute v0.2.0 diff --git a/go.sum b/go.sum index 3f5ff7511d4..66dd07bcc4f 100644 --- a/go.sum +++ b/go.sum @@ -286,6 +286,8 @@ github.com/gopherjs/gopherjs v0.0.0-20220410123724-9e86199038b0 h1:fWY+zXdWhvWnd github.com/gopherjs/gopherjs v0.0.0-20220410123724-9e86199038b0/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240129190346-220740bc30b1 h1:AKSzml3dShaejT9YPRSjPmtx9i1FsevIxUll3vyitDo= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240129190346-220740bc30b1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= @@ -940,8 +942,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/management/cmd/management.go b/management/cmd/management.go index 3801c5d09bc..9afddc0f796 100644 --- a/management/cmd/management.go +++ b/management/cmd/management.go @@ -11,6 +11,7 @@ import ( "io/fs" "net" "net/http" + "net/netip" "net/url" "os" "path" @@ -30,6 +31,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" + "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/realip" "github.com/netbirdio/netbird/encryption" mgmtProto "github.com/netbirdio/netbird/management/proto" "github.com/netbirdio/netbird/management/server" @@ -168,7 +170,21 @@ var ( turnManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig) - gRPCOpts := []grpc.ServerOption{grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp)} + trustedPeers := config.TrustedHTTPProxies + if len(trustedPeers) == 0 { + trustedPeers = []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0")} + } + headers := []string{realip.XForwardedFor, realip.XRealIp} + gRPCOpts := []grpc.ServerOption{ + grpc.KeepaliveEnforcementPolicy(kaep), + grpc.KeepaliveParams(kasp), + grpc.ChainUnaryInterceptor( + realip.UnaryServerInterceptor(trustedPeers, headers), + ), + grpc.ChainStreamInterceptor( + realip.StreamServerInterceptor(trustedPeers, headers), + ), + } var certManager *autocert.Manager var tlsConfig *tls.Config tlsEnabled := false diff --git a/management/server/config.go b/management/server/config.go index 4fed93bba48..c8b6606ea23 100644 --- a/management/server/config.go +++ b/management/server/config.go @@ -1,6 +1,7 @@ package server import ( + "net/netip" "net/url" "github.com/netbirdio/netbird/management/server/idp" @@ -40,6 +41,8 @@ type Config struct { HttpConfig *HttpServerConfig + TrustedHTTPProxies []netip.Prefix + IdpManagerConfig *idp.Config DeviceAuthorizationFlow *DeviceAuthorizationFlow diff --git a/management/server/grpcserver.go b/management/server/grpcserver.go index d6463edd9b6..d21c9027dbb 100644 --- a/management/server/grpcserver.go +++ b/management/server/grpcserver.go @@ -8,10 +8,10 @@ import ( pb "github.com/golang/protobuf/proto" // nolint "github.com/golang/protobuf/ptypes/timestamp" + "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/realip" log "github.com/sirupsen/logrus" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "google.golang.org/grpc/codes" - gRPCPeer "google.golang.org/grpc/peer" "google.golang.org/grpc/status" "github.com/netbirdio/netbird/encryption" @@ -109,6 +109,13 @@ func (s *GRPCServer) GetServerKey(ctx context.Context, req *proto.Empty) (*proto }, nil } +func getRealIP(ctx context.Context) string { + if ip, ok := realip.FromContext(ctx); ok { + return ip.String() + } + return "" +} + // Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and // notifies the connected peer of any updates (e.g. new peers under the same account) func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_SyncServer) error { @@ -116,10 +123,8 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi if s.appMetrics != nil { s.appMetrics.GRPCMetrics().CountSyncRequest() } - p, ok := gRPCPeer.FromContext(srv.Context()) - if ok { - log.Debugf("Sync request from peer [%s] [%s]", req.WgPubKey, p.Addr.String()) - } + realIP := getRealIP(srv.Context()) + log.Debugf("Sync request from peer [%s] [%s]", req.WgPubKey, realIP) syncReq := &proto.SyncRequest{} peerKey, err := s.parseRequest(req, syncReq) @@ -290,10 +295,8 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p if s.appMetrics != nil { s.appMetrics.GRPCMetrics().CountLoginRequest() } - p, ok := gRPCPeer.FromContext(ctx) - if ok { - log.Debugf("Login request from peer [%s] [%s]", req.WgPubKey, p.Addr.String()) - } + realIP := getRealIP(ctx) + log.Debugf("Login request from peer [%s] [%s]", req.WgPubKey, realIP) loginReq := &proto.LoginRequest{} peerKey, err := s.parseRequest(req, loginReq) @@ -303,8 +306,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p if loginReq.GetMeta() == nil { msg := status.Errorf(codes.FailedPrecondition, - "peer system meta has to be provided to log in. Peer %s, remote addr %s", peerKey.String(), - p.Addr.String()) + "peer system meta has to be provided to log in. Peer %s, remote addr %s", peerKey.String(), realIP) log.Warn(msg) return nil, msg }