mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-17 04:09:07 +02:00
Peer management login (#83)
* feature: replace RegisterPeer with Login method that does both - registration and login * test: add management login test * feature: add WiretrusteeConfig to the Login response to configure peer global config * feature: add client peer login support * fix: missing parts * chore: update go deps * feature: support Management Service gRPC endpoints [CLIENT] * feature: finalize client sync with management * fix: management store peer key lower case restore * fix: management returns peer ip without a mask * refactor: remove cmd pkg * fix: invalid tun interface name on mac * fix: timeout when calling management client * fix: tests and lint errors * fix: golang-test workflow * fix: client service tests * fix: iface build * feature: detect management scheme on startup * chore: better logs for management * fix: goreleaser * fix: lint errors * fix: signal TLS * fix: direct Wireguard connection * chore: verbose logging on direct connection
This commit is contained in:
@@ -55,7 +55,7 @@ func (manager *AccountManager) GetPeer(peerKey string) (*Peer, error) {
|
||||
|
||||
peer, err := manager.Store.GetPeer(peerKey)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.NotFound, "provided peer key doesn't exists %s", peerKey)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return peer, nil
|
||||
|
||||
@@ -70,7 +70,7 @@ func restore(file string) (*FileStore, error) {
|
||||
store.SetupKeyId2AccountId[strings.ToLower(setupKeyId)] = accountId
|
||||
}
|
||||
for _, peer := range account.Peers {
|
||||
store.PeerKeyId2AccountId[strings.ToLower(peer.Key)] = accountId
|
||||
store.PeerKeyId2AccountId[peer.Key] = accountId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func (s *FileStore) GetPeer(peerKey string) (*Peer, error) {
|
||||
|
||||
accountId, accountIdFound := s.PeerKeyId2AccountId[peerKey]
|
||||
if !accountIdFound {
|
||||
return nil, status.Errorf(codes.Internal, "account not found")
|
||||
return nil, status.Errorf(codes.NotFound, "peer not found")
|
||||
}
|
||||
|
||||
account, err := s.GetAccount(accountId)
|
||||
|
||||
@@ -77,7 +77,7 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
|
||||
|
||||
peer, err := s.accountManager.GetPeer(peerKey.String())
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Unauthenticated, "provided peer with the key wgPubKey %s is not registered", peerKey.String())
|
||||
return status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered", peerKey.String())
|
||||
}
|
||||
|
||||
syncReq := &proto.SyncRequest{}
|
||||
@@ -126,23 +126,18 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterPeer adds a peer to the Store. Returns 404 in case the provided setup key doesn't exist
|
||||
func (s *Server) RegisterPeer(ctx context.Context, req *proto.RegisterPeerRequest) (*proto.RegisterPeerResponse, error) {
|
||||
|
||||
log.Debugf("RegisterPeer request from peer %s", req.Key)
|
||||
|
||||
func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*server.Peer, error) {
|
||||
s.channelsMux.Lock()
|
||||
defer s.channelsMux.Unlock()
|
||||
|
||||
peer, err := s.accountManager.AddPeer(req.SetupKey, req.Key)
|
||||
peer, err := s.accountManager.AddPeer(setupKey, peerKey.String())
|
||||
if err != nil {
|
||||
return &proto.RegisterPeerResponse{}, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
|
||||
return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
|
||||
}
|
||||
|
||||
peers, err := s.accountManager.GetPeersForAPeer(peer.Key)
|
||||
if err != nil {
|
||||
//todo return a proper error
|
||||
return nil, err
|
||||
return nil, status.Error(codes.Internal, "internal server error")
|
||||
}
|
||||
|
||||
// notify other peers of our registration
|
||||
@@ -160,7 +155,63 @@ func (s *Server) RegisterPeer(ctx context.Context, req *proto.RegisterPeerReques
|
||||
}
|
||||
}
|
||||
|
||||
return &proto.RegisterPeerResponse{}, nil
|
||||
return peer, nil
|
||||
}
|
||||
|
||||
// Login endpoint first checks whether peer is registered under any account
|
||||
// In case it is, the login is successful
|
||||
// In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer.
|
||||
// In case of the successful registration login is also successful
|
||||
func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
|
||||
log.Debugf("Login request from peer %s", req.WgPubKey)
|
||||
|
||||
peerKey, err := wgtypes.ParseKey(req.GetWgPubKey())
|
||||
if err != nil {
|
||||
log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", req.WgPubKey)
|
||||
return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", req.WgPubKey)
|
||||
}
|
||||
|
||||
peer, err := s.accountManager.GetPeer(peerKey.String())
|
||||
if err != nil {
|
||||
if errStatus, ok := status.FromError(err); ok && errStatus.Code() == codes.NotFound {
|
||||
//peer doesn't exist -> check if setup key was provided
|
||||
loginReq := &proto.LoginRequest{}
|
||||
err = encryption.DecryptMessage(peerKey, s.wgKey, req.Body, loginReq)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid request message")
|
||||
}
|
||||
|
||||
if loginReq.GetSetupKey() == "" {
|
||||
//absent setup key -> permission denied
|
||||
return nil, status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered", peerKey.String())
|
||||
}
|
||||
|
||||
//setup key is present -> try normal registration flow
|
||||
peer, err = s.registerPeer(peerKey, loginReq.GetSetupKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
return nil, status.Error(codes.Internal, "internal server error")
|
||||
}
|
||||
}
|
||||
|
||||
// if peer has reached this point then it has logged in
|
||||
loginResp := &proto.LoginResponse{
|
||||
WiretrusteeConfig: toWiretrusteeConfig(s.config),
|
||||
PeerConfig: toPeerConfig(peer),
|
||||
}
|
||||
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, loginResp)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed logging in peer")
|
||||
}
|
||||
|
||||
return &proto.EncryptedMessage{
|
||||
WgPubKey: s.wgKey.PublicKey().String(),
|
||||
Body: encryptedResp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol {
|
||||
@@ -181,7 +232,7 @@ func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol {
|
||||
}
|
||||
}
|
||||
|
||||
func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Peer) *proto.SyncResponse {
|
||||
func toWiretrusteeConfig(config *server.Config) *proto.WiretrusteeConfig {
|
||||
|
||||
var stuns []*proto.HostConfig
|
||||
for _, stun := range config.Stuns {
|
||||
@@ -202,7 +253,7 @@ func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Pe
|
||||
})
|
||||
}
|
||||
|
||||
wtConfig := &proto.WiretrusteeConfig{
|
||||
return &proto.WiretrusteeConfig{
|
||||
Stuns: stuns,
|
||||
Turns: turns,
|
||||
Signal: &proto.HostConfig{
|
||||
@@ -210,10 +261,19 @@ func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Pe
|
||||
Protocol: toResponseProto(config.Signal.Proto),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pConfig := &proto.PeerConfig{
|
||||
Address: peer.IP.String(),
|
||||
func toPeerConfig(peer *server.Peer) *proto.PeerConfig {
|
||||
return &proto.PeerConfig{
|
||||
Address: peer.IP.String() + "/24", //todo make it explicit
|
||||
}
|
||||
}
|
||||
|
||||
func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Peer) *proto.SyncResponse {
|
||||
|
||||
wtConfig := toWiretrusteeConfig(config)
|
||||
|
||||
pConfig := toPeerConfig(peer)
|
||||
|
||||
remotePeers := make([]*proto.RemotePeerConfig, 0, len(peers))
|
||||
for _, rPeer := range peers {
|
||||
|
||||
@@ -92,7 +92,7 @@ var _ = Describe("Management service", func() {
|
||||
Context("when there is a new peer registered", func() {
|
||||
Specify("a proper configuration is returned", func() {
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
|
||||
encryptedBytes, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.SyncRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -111,7 +111,7 @@ var _ = Describe("Management service", func() {
|
||||
err = encryption.DecryptMessage(serverPubKey, key, encryptedResponse.Body, resp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(resp.PeerConfig.Address).To(BeEquivalentTo("100.64.0.1"))
|
||||
Expect(resp.PeerConfig.Address).To(BeEquivalentTo("100.64.0.1/24"))
|
||||
|
||||
expectedSignalConfig := &mgmtProto.HostConfig{
|
||||
Uri: "signal.wiretrustee.com:10000",
|
||||
@@ -142,9 +142,9 @@ var _ = Describe("Management service", func() {
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
key1, _ := wgtypes.GenerateKey()
|
||||
key2, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key, client)
|
||||
registerPeerWithValidSetupKey(key1, client)
|
||||
registerPeerWithValidSetupKey(key2, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key1, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key2, client)
|
||||
|
||||
messageBytes, err := pb.Marshal(&mgmtProto.SyncRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -178,7 +178,7 @@ var _ = Describe("Management service", func() {
|
||||
Specify("an update is returned", func() {
|
||||
// register only a single peer
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
|
||||
messageBytes, err := pb.Marshal(&mgmtProto.SyncRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -218,7 +218,7 @@ var _ = Describe("Management service", func() {
|
||||
|
||||
// register a new peer
|
||||
key1, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key1, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key1, client)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
@@ -247,15 +247,18 @@ var _ = Describe("Management service", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("when calling RegisterPeer endpoint", func() {
|
||||
Context("when calling Login endpoint", func() {
|
||||
|
||||
Context("with an invalid setup key", func() {
|
||||
Specify("an error is returned", func() {
|
||||
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
resp, err := client.RegisterPeer(context.TODO(), &mgmtProto.RegisterPeerRequest{
|
||||
Key: key.PublicKey().String(),
|
||||
SetupKey: InvalidSetupKey,
|
||||
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: "invalid setup key"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
resp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{
|
||||
WgPubKey: key.PublicKey().String(),
|
||||
Body: message,
|
||||
})
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
@@ -268,12 +271,56 @@ var _ = Describe("Management service", func() {
|
||||
It("a non error result is returned", func() {
|
||||
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
resp := registerPeerWithValidSetupKey(key, client)
|
||||
resp := loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
|
||||
Expect(resp).ToNot(BeNil())
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("with a registered peer", func() {
|
||||
It("a non error result is returned", func() {
|
||||
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
regResp := loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
Expect(regResp).NotTo(BeNil())
|
||||
|
||||
// just login without registration
|
||||
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
loginResp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{
|
||||
WgPubKey: key.PublicKey().String(),
|
||||
Body: message,
|
||||
})
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
decryptedResp := &mgmtProto.LoginResponse{}
|
||||
err = encryption.DecryptMessage(serverPubKey, key, loginResp.Body, decryptedResp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
expectedSignalConfig := &mgmtProto.HostConfig{
|
||||
Uri: "signal.wiretrustee.com:10000",
|
||||
Protocol: mgmtProto.HostConfig_HTTP,
|
||||
}
|
||||
expectedStunsConfig := &mgmtProto.HostConfig{
|
||||
Uri: "stun:stun.wiretrustee.com:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
}
|
||||
expectedTurnsConfig := &mgmtProto.ProtectedHostConfig{
|
||||
HostConfig: &mgmtProto.HostConfig{
|
||||
Uri: "turn:stun.wiretrustee.com:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
},
|
||||
User: "some_user",
|
||||
Password: "some_password",
|
||||
}
|
||||
|
||||
Expect(decryptedResp.GetWiretrusteeConfig().Signal).To(BeEquivalentTo(expectedSignalConfig))
|
||||
Expect(decryptedResp.GetWiretrusteeConfig().Stuns).To(ConsistOf(expectedStunsConfig))
|
||||
Expect(decryptedResp.GetWiretrusteeConfig().Turns).To(ConsistOf(expectedTurnsConfig))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("when there are 50 peers registered under one account", func() {
|
||||
@@ -286,7 +333,7 @@ var _ = Describe("Management service", func() {
|
||||
var peers []wgtypes.Key
|
||||
for i := 0; i < initialPeers; i++ {
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
peers = append(peers, key)
|
||||
}
|
||||
|
||||
@@ -331,7 +378,7 @@ var _ = Describe("Management service", func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
for i := 0; i < additionalPeers; i++ {
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
n := rand.Intn(500)
|
||||
time.Sleep(time.Duration(n) * time.Millisecond)
|
||||
@@ -357,7 +404,7 @@ var _ = Describe("Management service", func() {
|
||||
for i := 0; i < initialPeers; i++ {
|
||||
go func() {
|
||||
key, _ := wgtypes.GenerateKey()
|
||||
registerPeerWithValidSetupKey(key, client)
|
||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||
encryptedBytes, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.SyncRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@@ -395,16 +442,22 @@ var _ = Describe("Management service", func() {
|
||||
})
|
||||
})
|
||||
|
||||
func registerPeerWithValidSetupKey(key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.RegisterPeerResponse {
|
||||
func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.LoginResponse {
|
||||
|
||||
resp, err := client.RegisterPeer(context.TODO(), &mgmtProto.RegisterPeerRequest{
|
||||
Key: key.PublicKey().String(),
|
||||
SetupKey: ValidSetupKey,
|
||||
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: ValidSetupKey})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
resp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{
|
||||
WgPubKey: key.PublicKey().String(),
|
||||
Body: message,
|
||||
})
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return resp
|
||||
loginResp := &mgmtProto.LoginResponse{}
|
||||
err = encryption.DecryptMessage(serverPubKey, key, resp.Body, loginResp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return loginResp
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user