mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
NetBird SSH (#361)
This PR adds support for SSH access through the NetBird network without managing SSH skeys. NetBird client app has an embedded SSH server (Linux/Mac only) and a netbird ssh command.
This commit is contained in:
@@ -51,6 +51,7 @@ type AccountManager interface {
|
||||
GetNetworkMap(peerKey string) (*NetworkMap, error)
|
||||
AddPeer(setupKey string, userId string, peer *Peer) (*Peer, error)
|
||||
UpdatePeerMeta(peerKey string, meta PeerSystemMeta) error
|
||||
UpdatePeerSSHKey(peerKey string, sshKey string) error
|
||||
GetUsersFromAccount(accountId string) ([]*UserInfo, error)
|
||||
GetGroup(accountId, groupID string) (*Group, error)
|
||||
SaveGroup(accountId string, group *Group) error
|
||||
@@ -65,6 +66,7 @@ type AccountManager interface {
|
||||
UpdateRule(accountID string, ruleID string, operations []RuleUpdateOperation) (*Rule, error)
|
||||
DeleteRule(accountId, ruleID string) error
|
||||
ListRules(accountId string) ([]*Rule, error)
|
||||
UpdatePeer(accountID string, peer *Peer) (*Peer, error)
|
||||
}
|
||||
|
||||
type DefaultAccountManager struct {
|
||||
|
||||
@@ -185,9 +185,15 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
|
||||
return nil, status.Errorf(codes.InvalidArgument, "peer meta data was not provided")
|
||||
}
|
||||
|
||||
var sshKey []byte
|
||||
if req.GetPeerKeys() != nil {
|
||||
sshKey = req.GetPeerKeys().GetSshPubKey()
|
||||
}
|
||||
|
||||
peer, err := s.accountManager.AddPeer(reqSetupKey, userId, &Peer{
|
||||
Key: peerKey.String(),
|
||||
Name: meta.GetHostname(),
|
||||
Key: peerKey.String(),
|
||||
Name: meta.GetHostname(),
|
||||
SSHKey: string(sshKey),
|
||||
Meta: PeerSystemMeta{
|
||||
Hostname: meta.GetHostname(),
|
||||
GoOS: meta.GetGoOS(),
|
||||
@@ -290,6 +296,19 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
|
||||
return nil, status.Error(codes.Internal, "internal server error")
|
||||
}
|
||||
}
|
||||
|
||||
var sshKey []byte
|
||||
if loginReq.GetPeerKeys() != nil {
|
||||
sshKey = loginReq.GetPeerKeys().GetSshPubKey()
|
||||
}
|
||||
|
||||
if len(sshKey) > 0 {
|
||||
err = s.accountManager.UpdatePeerSSHKey(peerKey.String(), string(sshKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// if peer has reached this point then it has logged in
|
||||
loginResp := &proto.LoginResponse{
|
||||
WiretrusteeConfig: toWiretrusteeConfig(s.config, nil),
|
||||
@@ -365,7 +384,8 @@ func toWiretrusteeConfig(config *Config, turnCredentials *TURNCredentials) *prot
|
||||
|
||||
func toPeerConfig(peer *Peer) *proto.PeerConfig {
|
||||
return &proto.PeerConfig{
|
||||
Address: fmt.Sprintf("%s/%d", peer.IP.String(), SubnetSize), // take it from the network
|
||||
Address: fmt.Sprintf("%s/%d", peer.IP.String(), SubnetSize), // take it from the network
|
||||
SshConfig: &proto.SSHConfig{SshEnabled: peer.SSHEnabled},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,9 +395,9 @@ func toRemotePeerConfig(peers []*Peer) []*proto.RemotePeerConfig {
|
||||
remotePeers = append(remotePeers, &proto.RemotePeerConfig{
|
||||
WgPubKey: rPeer.Key,
|
||||
AllowedIps: []string{fmt.Sprintf(AllowedIPsFormat, rPeer.IP)},
|
||||
SshConfig: &proto.SSHConfig{SshPubKey: []byte(rPeer.SSHKey)},
|
||||
})
|
||||
}
|
||||
|
||||
return remotePeers
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,9 @@ components:
|
||||
required:
|
||||
- type
|
||||
- value
|
||||
ssh_enabled:
|
||||
description: Indicates whether SSH server is enabled on this peer
|
||||
type: boolean
|
||||
required:
|
||||
- ip
|
||||
- connected
|
||||
@@ -93,6 +96,7 @@ components:
|
||||
- version
|
||||
- groups
|
||||
- activated_by
|
||||
- ssh_enabled
|
||||
SetupKey:
|
||||
type: object
|
||||
properties:
|
||||
@@ -397,8 +401,11 @@ paths:
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
ssh_enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- name
|
||||
- ssh_enabled
|
||||
responses:
|
||||
'200':
|
||||
description: A Peer object
|
||||
|
||||
@@ -115,6 +115,9 @@ type Peer struct {
|
||||
// Peer's operating system and version
|
||||
Os string `json:"os"`
|
||||
|
||||
// Indicates whether SSH server is enabled on this peer
|
||||
SshEnabled bool `json:"ssh_enabled"`
|
||||
|
||||
// Peer's daemon or cli version
|
||||
Version string `json:"version"`
|
||||
}
|
||||
@@ -265,7 +268,8 @@ type PutApiGroupsIdJSONBody struct {
|
||||
|
||||
// PutApiPeersIdJSONBody defines parameters for PutApiPeersId.
|
||||
type PutApiPeersIdJSONBody struct {
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name"`
|
||||
SshEnabled bool `json:"ssh_enabled"`
|
||||
}
|
||||
|
||||
// PostApiRulesJSONBody defines parameters for PostApiRules.
|
||||
|
||||
@@ -34,7 +34,9 @@ func (h *Peers) updatePeer(account *server.Account, peer *server.Peer, w http.Re
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
peer, err = h.accountManager.RenamePeer(account.Id, peer.Key, req.Name)
|
||||
|
||||
update := &server.Peer{Key: peer.Key, SSHEnabled: req.SshEnabled, Name: req.Name}
|
||||
peer, err = h.accountManager.UpdatePeer(account.Id, update)
|
||||
if err != nil {
|
||||
log.Errorf("failed updating peer %s under account %s %v", peerIp, account.Id, err)
|
||||
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||
@@ -133,13 +135,14 @@ func toPeerResponse(peer *server.Peer, account *server.Account) *api.Peer {
|
||||
}
|
||||
}
|
||||
return &api.Peer{
|
||||
Id: peer.IP.String(),
|
||||
Name: peer.Name,
|
||||
Ip: peer.IP.String(),
|
||||
Connected: peer.Status.Connected,
|
||||
LastSeen: peer.Status.LastSeen,
|
||||
Os: fmt.Sprintf("%s %s", peer.Meta.OS, peer.Meta.Core),
|
||||
Version: peer.Meta.WtVersion,
|
||||
Groups: groupsInfo,
|
||||
Id: peer.IP.String(),
|
||||
Name: peer.Name,
|
||||
Ip: peer.IP.String(),
|
||||
Connected: peer.Status.Connected,
|
||||
LastSeen: peer.Status.LastSeen,
|
||||
Os: fmt.Sprintf("%s %s", peer.Meta.OS, peer.Meta.Core),
|
||||
Version: peer.Meta.WtVersion,
|
||||
Groups: groupsInfo,
|
||||
SshEnabled: peer.SSHEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ type MockAccountManager struct {
|
||||
ListRulesFunc func(accountID string) ([]*server.Rule, error)
|
||||
GetUsersFromAccountFunc func(accountID string) ([]*server.UserInfo, error)
|
||||
UpdatePeerMetaFunc func(peerKey string, meta server.PeerSystemMeta) error
|
||||
UpdatePeerSSHKeyFunc func(peerKey string, sshKey string) error
|
||||
UpdatePeerFunc func(accountID string, peer *server.Peer) (*server.Peer, error)
|
||||
}
|
||||
|
||||
// GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface
|
||||
@@ -48,7 +50,7 @@ func (am *MockAccountManager) GetUsersFromAccount(accountID string) ([]*server.U
|
||||
if am.GetUsersFromAccountFunc != nil {
|
||||
return am.GetUsersFromAccountFunc(accountID)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUsersFromAccount not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetUsersFromAccount is not implemented")
|
||||
}
|
||||
|
||||
// GetOrCreateAccountByUser mock implementation of GetOrCreateAccountByUser from server.AccountManager interface
|
||||
@@ -60,7 +62,7 @@ func (am *MockAccountManager) GetOrCreateAccountByUser(
|
||||
}
|
||||
return nil, status.Errorf(
|
||||
codes.Unimplemented,
|
||||
"method GetOrCreateAccountByUser not implemented",
|
||||
"method GetOrCreateAccountByUser is not implemented",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ func (am *MockAccountManager) GetAccountByUser(userId string) (*server.Account,
|
||||
if am.GetAccountByUserFunc != nil {
|
||||
return am.GetAccountByUserFunc(userId)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAccountByUser not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAccountByUser is not implemented")
|
||||
}
|
||||
|
||||
// AddSetupKey mock implementation of AddSetupKey from server.AccountManager interface
|
||||
@@ -82,7 +84,7 @@ func (am *MockAccountManager) AddSetupKey(
|
||||
if am.AddSetupKeyFunc != nil {
|
||||
return am.AddSetupKeyFunc(accountId, keyName, keyType, expiresIn)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddSetupKey not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddSetupKey is not implemented")
|
||||
}
|
||||
|
||||
// RevokeSetupKey mock implementation of RevokeSetupKey from server.AccountManager interface
|
||||
@@ -93,7 +95,7 @@ func (am *MockAccountManager) RevokeSetupKey(
|
||||
if am.RevokeSetupKeyFunc != nil {
|
||||
return am.RevokeSetupKeyFunc(accountId, keyId)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RevokeSetupKey not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RevokeSetupKey is not implemented")
|
||||
}
|
||||
|
||||
// RenameSetupKey mock implementation of RenameSetupKey from server.AccountManager interface
|
||||
@@ -105,7 +107,7 @@ func (am *MockAccountManager) RenameSetupKey(
|
||||
if am.RenameSetupKeyFunc != nil {
|
||||
return am.RenameSetupKeyFunc(accountId, keyId, newName)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RenameSetupKey not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RenameSetupKey is not implemented")
|
||||
}
|
||||
|
||||
// GetAccountById mock implementation of GetAccountById from server.AccountManager interface
|
||||
@@ -113,7 +115,7 @@ func (am *MockAccountManager) GetAccountById(accountId string) (*server.Account,
|
||||
if am.GetAccountByIdFunc != nil {
|
||||
return am.GetAccountByIdFunc(accountId)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAccountById not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetAccountById is not implemented")
|
||||
}
|
||||
|
||||
// GetAccountByUserOrAccountId mock implementation of GetAccountByUserOrAccountId from server.AccountManager interface
|
||||
@@ -125,7 +127,7 @@ func (am *MockAccountManager) GetAccountByUserOrAccountId(
|
||||
}
|
||||
return nil, status.Errorf(
|
||||
codes.Unimplemented,
|
||||
"method GetAccountByUserOrAccountId not implemented",
|
||||
"method GetAccountByUserOrAccountId is not implemented",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -138,7 +140,7 @@ func (am *MockAccountManager) GetAccountWithAuthorizationClaims(
|
||||
}
|
||||
return nil, status.Errorf(
|
||||
codes.Unimplemented,
|
||||
"method GetAccountWithAuthorizationClaims not implemented",
|
||||
"method GetAccountWithAuthorizationClaims is not implemented",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -147,7 +149,7 @@ func (am *MockAccountManager) AccountExists(accountId string) (*bool, error) {
|
||||
if am.AccountExistsFunc != nil {
|
||||
return am.AccountExistsFunc(accountId)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AccountExists not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AccountExists is not implemented")
|
||||
}
|
||||
|
||||
// GetPeer mock implementation of GetPeer from server.AccountManager interface
|
||||
@@ -155,7 +157,7 @@ func (am *MockAccountManager) GetPeer(peerKey string) (*server.Peer, error) {
|
||||
if am.GetPeerFunc != nil {
|
||||
return am.GetPeerFunc(peerKey)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPeer not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPeer is not implemented")
|
||||
}
|
||||
|
||||
// MarkPeerConnected mock implementation of MarkPeerConnected from server.AccountManager interface
|
||||
@@ -163,7 +165,7 @@ func (am *MockAccountManager) MarkPeerConnected(peerKey string, connected bool)
|
||||
if am.MarkPeerConnectedFunc != nil {
|
||||
return am.MarkPeerConnectedFunc(peerKey, connected)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method MarkPeerConnected not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method MarkPeerConnected is not implemented")
|
||||
}
|
||||
|
||||
// RenamePeer mock implementation of RenamePeer from server.AccountManager interface
|
||||
@@ -175,7 +177,7 @@ func (am *MockAccountManager) RenamePeer(
|
||||
if am.RenamePeerFunc != nil {
|
||||
return am.RenamePeerFunc(accountId, peerKey, newName)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RenamePeer not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RenamePeer is not implemented")
|
||||
}
|
||||
|
||||
// DeletePeer mock implementation of DeletePeer from server.AccountManager interface
|
||||
@@ -183,7 +185,7 @@ func (am *MockAccountManager) DeletePeer(accountId string, peerKey string) (*ser
|
||||
if am.DeletePeerFunc != nil {
|
||||
return am.DeletePeerFunc(accountId, peerKey)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeletePeer not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeletePeer is not implemented")
|
||||
}
|
||||
|
||||
// GetPeerByIP mock implementation of GetPeerByIP from server.AccountManager interface
|
||||
@@ -191,7 +193,7 @@ func (am *MockAccountManager) GetPeerByIP(accountId string, peerIP string) (*ser
|
||||
if am.GetPeerByIPFunc != nil {
|
||||
return am.GetPeerByIPFunc(accountId, peerIP)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPeerByIP not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPeerByIP is not implemented")
|
||||
}
|
||||
|
||||
// GetNetworkMap mock implementation of GetNetworkMap from server.AccountManager interface
|
||||
@@ -199,7 +201,7 @@ func (am *MockAccountManager) GetNetworkMap(peerKey string) (*server.NetworkMap,
|
||||
if am.GetNetworkMapFunc != nil {
|
||||
return am.GetNetworkMapFunc(peerKey)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetNetworkMap not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetNetworkMap is not implemented")
|
||||
}
|
||||
|
||||
// AddPeer mock implementation of AddPeer from server.AccountManager interface
|
||||
@@ -211,7 +213,7 @@ func (am *MockAccountManager) AddPeer(
|
||||
if am.AddPeerFunc != nil {
|
||||
return am.AddPeerFunc(setupKey, userId, peer)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddPeer not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AddPeer is not implemented")
|
||||
}
|
||||
|
||||
// GetGroup mock implementation of GetGroup from server.AccountManager interface
|
||||
@@ -219,7 +221,7 @@ func (am *MockAccountManager) GetGroup(accountID, groupID string) (*server.Group
|
||||
if am.GetGroupFunc != nil {
|
||||
return am.GetGroupFunc(accountID, groupID)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetGroup not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetGroup is not implemented")
|
||||
}
|
||||
|
||||
// SaveGroup mock implementation of SaveGroup from server.AccountManager interface
|
||||
@@ -227,7 +229,7 @@ func (am *MockAccountManager) SaveGroup(accountID string, group *server.Group) e
|
||||
if am.SaveGroupFunc != nil {
|
||||
return am.SaveGroupFunc(accountID, group)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method SaveGroup not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method SaveGroup is not implemented")
|
||||
}
|
||||
|
||||
// UpdateGroup mock implementation of UpdateGroup from server.AccountManager interface
|
||||
@@ -243,7 +245,7 @@ func (am *MockAccountManager) DeleteGroup(accountID, groupID string) error {
|
||||
if am.DeleteGroupFunc != nil {
|
||||
return am.DeleteGroupFunc(accountID, groupID)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method DeleteGroup not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method DeleteGroup is not implemented")
|
||||
}
|
||||
|
||||
// ListGroups mock implementation of ListGroups from server.AccountManager interface
|
||||
@@ -251,7 +253,7 @@ func (am *MockAccountManager) ListGroups(accountID string) ([]*server.Group, err
|
||||
if am.ListGroupsFunc != nil {
|
||||
return am.ListGroupsFunc(accountID)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListGroups not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListGroups is not implemented")
|
||||
}
|
||||
|
||||
// GroupAddPeer mock implementation of GroupAddPeer from server.AccountManager interface
|
||||
@@ -259,7 +261,7 @@ func (am *MockAccountManager) GroupAddPeer(accountID, groupID, peerKey string) e
|
||||
if am.GroupAddPeerFunc != nil {
|
||||
return am.GroupAddPeerFunc(accountID, groupID, peerKey)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method GroupAddPeer not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method GroupAddPeer is not implemented")
|
||||
}
|
||||
|
||||
// GroupDeletePeer mock implementation of GroupDeletePeer from server.AccountManager interface
|
||||
@@ -267,7 +269,7 @@ func (am *MockAccountManager) GroupDeletePeer(accountID, groupID, peerKey string
|
||||
if am.GroupDeletePeerFunc != nil {
|
||||
return am.GroupDeletePeerFunc(accountID, groupID, peerKey)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method GroupDeletePeer not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method GroupDeletePeer is not implemented")
|
||||
}
|
||||
|
||||
// GroupListPeers mock implementation of GroupListPeers from server.AccountManager interface
|
||||
@@ -275,7 +277,7 @@ func (am *MockAccountManager) GroupListPeers(accountID, groupID string) ([]*serv
|
||||
if am.GroupListPeersFunc != nil {
|
||||
return am.GroupListPeersFunc(accountID, groupID)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GroupListPeers not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GroupListPeers is not implemented")
|
||||
}
|
||||
|
||||
// GetRule mock implementation of GetRule from server.AccountManager interface
|
||||
@@ -283,7 +285,7 @@ func (am *MockAccountManager) GetRule(accountID, ruleID string) (*server.Rule, e
|
||||
if am.GetRuleFunc != nil {
|
||||
return am.GetRuleFunc(accountID, ruleID)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRule not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRule is not implemented")
|
||||
}
|
||||
|
||||
// SaveRule mock implementation of SaveRule from server.AccountManager interface
|
||||
@@ -291,7 +293,7 @@ func (am *MockAccountManager) SaveRule(accountID string, rule *server.Rule) erro
|
||||
if am.SaveRuleFunc != nil {
|
||||
return am.SaveRuleFunc(accountID, rule)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method SaveRule not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method SaveRule is not implemented")
|
||||
}
|
||||
|
||||
// UpdateRule mock implementation of UpdateRule from server.AccountManager interface
|
||||
@@ -307,7 +309,7 @@ func (am *MockAccountManager) DeleteRule(accountID, ruleID string) error {
|
||||
if am.DeleteRuleFunc != nil {
|
||||
return am.DeleteRuleFunc(accountID, ruleID)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method DeleteRule not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method DeleteRule is not implemented")
|
||||
}
|
||||
|
||||
// ListRules mock implementation of ListRules from server.AccountManager interface
|
||||
@@ -315,7 +317,7 @@ func (am *MockAccountManager) ListRules(accountID string) ([]*server.Rule, error
|
||||
if am.ListRulesFunc != nil {
|
||||
return am.ListRulesFunc(accountID)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRules not implemented")
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListRules is not implemented")
|
||||
}
|
||||
|
||||
// UpdatePeerMeta mock implementation of UpdatePeerMeta from server.AccountManager interface
|
||||
@@ -323,7 +325,7 @@ func (am *MockAccountManager) UpdatePeerMeta(peerKey string, meta server.PeerSys
|
||||
if am.UpdatePeerMetaFunc != nil {
|
||||
return am.UpdatePeerMetaFunc(peerKey, meta)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method UpdatePeerMetaFunc not implemented")
|
||||
return status.Errorf(codes.Unimplemented, "method UpdatePeerMetaFunc is not implemented")
|
||||
}
|
||||
|
||||
// IsUserAdmin mock implementation of IsUserAdmin from server.AccountManager interface
|
||||
@@ -331,5 +333,21 @@ func (am *MockAccountManager) IsUserAdmin(claims jwtclaims.AuthorizationClaims)
|
||||
if am.IsUserAdminFunc != nil {
|
||||
return am.IsUserAdminFunc(claims)
|
||||
}
|
||||
return false, status.Errorf(codes.Unimplemented, "method IsUserAdmin not implemented")
|
||||
return false, status.Errorf(codes.Unimplemented, "method IsUserAdmin is not implemented")
|
||||
}
|
||||
|
||||
// UpdatePeerSSHKey mocks UpdatePeerSSHKey function of the account manager
|
||||
func (am *MockAccountManager) UpdatePeerSSHKey(peerKey string, sshKey string) error {
|
||||
if am.UpdatePeerSSHKeyFunc != nil {
|
||||
return am.UpdatePeerSSHKeyFunc(peerKey, sshKey)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method UpdatePeerSSHKey is is not implemented")
|
||||
}
|
||||
|
||||
// UpdatePeer mocks UpdatePeerFunc function of the account manager
|
||||
func (am *MockAccountManager) UpdatePeer(accountID string, peer *server.Peer) (*server.Peer, error) {
|
||||
if am.UpdatePeerFunc != nil {
|
||||
return am.UpdatePeerFunc(accountID, peer)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdatePeerFunc is is not implemented")
|
||||
}
|
||||
|
||||
@@ -47,18 +47,24 @@ type Peer struct {
|
||||
Status *PeerStatus
|
||||
// The user ID that registered the peer
|
||||
UserID string
|
||||
// SSHKey is a public SSH key of the peer
|
||||
SSHKey string
|
||||
// SSHEnabled indicated whether SSH server is enabled on the peer
|
||||
SSHEnabled bool
|
||||
}
|
||||
|
||||
// Copy copies Peer object
|
||||
func (p *Peer) Copy() *Peer {
|
||||
return &Peer{
|
||||
Key: p.Key,
|
||||
SetupKey: p.SetupKey,
|
||||
IP: p.IP,
|
||||
Meta: p.Meta,
|
||||
Name: p.Name,
|
||||
Status: p.Status,
|
||||
UserID: p.UserID,
|
||||
Key: p.Key,
|
||||
SetupKey: p.SetupKey,
|
||||
IP: p.IP,
|
||||
Meta: p.Meta,
|
||||
Name: p.Name,
|
||||
Status: p.Status,
|
||||
UserID: p.UserID,
|
||||
SSHKey: p.SSHKey,
|
||||
SSHEnabled: p.SSHEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +106,41 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerKey string, connected boo
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePeer updates peer. Only Peer.Name and Peer.SSHEnabled can be updated.
|
||||
func (am *DefaultAccountManager) UpdatePeer(accountID string, update *Peer) (*Peer, error) {
|
||||
am.mux.Lock()
|
||||
defer am.mux.Unlock()
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.NotFound, "account not found")
|
||||
}
|
||||
|
||||
peer, err := am.Store.GetPeer(update.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
peerCopy := peer.Copy()
|
||||
if peer.Name != "" {
|
||||
peerCopy.Name = update.Name
|
||||
}
|
||||
peerCopy.SSHEnabled = update.SSHEnabled
|
||||
|
||||
err = am.Store.SavePeer(accountID, peerCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = am.updateAccountPeers(account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return peerCopy, nil
|
||||
|
||||
}
|
||||
|
||||
// RenamePeer changes peer's name
|
||||
func (am *DefaultAccountManager) RenamePeer(
|
||||
accountId string,
|
||||
@@ -285,13 +326,15 @@ func (am *DefaultAccountManager) AddPeer(
|
||||
}
|
||||
|
||||
newPeer := &Peer{
|
||||
Key: peer.Key,
|
||||
SetupKey: upperKey,
|
||||
IP: nextIp,
|
||||
Meta: peer.Meta,
|
||||
Name: peer.Name,
|
||||
UserID: userID,
|
||||
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
|
||||
Key: peer.Key,
|
||||
SetupKey: upperKey,
|
||||
IP: nextIp,
|
||||
Meta: peer.Meta,
|
||||
Name: peer.Name,
|
||||
UserID: userID,
|
||||
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
|
||||
SSHEnabled: false,
|
||||
SSHKey: peer.SSHKey,
|
||||
}
|
||||
|
||||
// add peer to 'All' group
|
||||
@@ -315,6 +358,38 @@ func (am *DefaultAccountManager) AddPeer(
|
||||
return newPeer, nil
|
||||
}
|
||||
|
||||
// UpdatePeerSSHKey updates peer's public SSH key
|
||||
func (am *DefaultAccountManager) UpdatePeerSSHKey(peerKey string, sshKey string) error {
|
||||
am.mux.Lock()
|
||||
defer am.mux.Unlock()
|
||||
|
||||
if sshKey == "" {
|
||||
log.Debugf("empty SSH key provided for peer %s, skipping update", peerKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
peer, err := am.Store.GetPeer(peerKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
account, err := am.Store.GetPeerAccount(peerKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
peerCopy := peer.Copy()
|
||||
peerCopy.SSHKey = sshKey
|
||||
|
||||
err = am.Store.SavePeer(account.Id, peerCopy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// trigger network map update
|
||||
return am.updateAccountPeers(account)
|
||||
}
|
||||
|
||||
// UpdatePeerMeta updates peer's system metadata
|
||||
func (am *DefaultAccountManager) UpdatePeerMeta(peerKey string, meta PeerSystemMeta) error {
|
||||
am.mux.Lock()
|
||||
@@ -345,7 +420,7 @@ func (am *DefaultAccountManager) UpdatePeerMeta(peerKey string, meta PeerSystemM
|
||||
return nil
|
||||
}
|
||||
|
||||
// getPeersByACL allowed for given peer by ACL
|
||||
// getPeersByACL returns all peers that given peer has access to.
|
||||
func (am *DefaultAccountManager) getPeersByACL(account *Account, peerKey string) []*Peer {
|
||||
var peers []*Peer
|
||||
srcRules, err := am.Store.GetPeerSrcRules(account.Id, peerKey)
|
||||
@@ -409,7 +484,8 @@ func (am *DefaultAccountManager) getPeersByACL(account *Account, peerKey string)
|
||||
return peers
|
||||
}
|
||||
|
||||
// updateAccountPeers network map constructed by ACL
|
||||
// updateAccountPeers updates all peers that belong to an account.
|
||||
// Should be called when changes have to be synced to peers.
|
||||
func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
|
||||
// notify other peers of the change
|
||||
peers, err := am.Store.GetAccountPeers(account.Id)
|
||||
@@ -422,7 +498,7 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
|
||||
err = am.peersUpdateManager.SendUpdate(p.Key,
|
||||
&UpdateMessage{
|
||||
Update: &proto.SyncResponse{
|
||||
// fill those field for backward compatibility
|
||||
// fill deprecated fields for backward compatibility
|
||||
RemotePeers: update,
|
||||
RemotePeersIsEmpty: len(update) == 0,
|
||||
// new field
|
||||
@@ -430,6 +506,7 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
|
||||
Serial: account.Network.CurrentSerial(),
|
||||
RemotePeers: update,
|
||||
RemotePeersIsEmpty: len(update) == 0,
|
||||
PeerConfig: toPeerConfig(p),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
type UpdateMessage struct {
|
||||
Update *proto.SyncResponse
|
||||
}
|
||||
|
||||
type PeersUpdateManager struct {
|
||||
peerChannels map[string]chan *UpdateMessage
|
||||
channelsMux *sync.Mutex
|
||||
|
||||
Reference in New Issue
Block a user