add signatures and frame for peer approval

This commit is contained in:
Pascal Fischer 2023-11-28 11:44:08 +01:00
parent b7c0eba1e5
commit a7e55cc5e3
9 changed files with 140 additions and 16 deletions

2
go.mod
View File

@ -51,7 +51,7 @@ require (
github.com/miekg/dns v1.1.43
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/nadoo/ipset v0.5.0
github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88
github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818
github.com/okta/okta-sdk-golang/v2 v2.18.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pion/logging v0.2.2

14
go.sum
View File

@ -495,8 +495,18 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nadoo/ipset v0.5.0 h1:5GJUAuZ7ITQQQGne5J96AmFjRtI8Avlbk6CabzYWVUc=
github.com/nadoo/ipset v0.5.0/go.mod h1:rYF5DQLRGGoQ8ZSWeK+6eX5amAuPqwFkWjhQlEITGJQ=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88 h1:zhe8qseauBuYOS910jpl5sv8Tb+36zxQPXrwYXqll0g=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231027143200-a966bce7db88/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944 h1:n7o2/NCZzn0+73LGdl/VMh7DOTdWZ98le2woeZ4HlB0=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231124150713-21460cd61944/go.mod h1:KSqjzHcqlodTWiuap5lRXxt5KT3vtYRoksL0KIrTK40=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a h1:6aipBr80s0GPKO9Wl+f5TUOSwebQ91uX2thk9tElyqc=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127164900-a09d11271e0a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683 h1:jJMO8KL2u3ok5VtGgZtFpuVK0GBEXXIb84idlmqGe68=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127165733-0d0650c84683/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a h1:DIe9xdl6RcxeZFu5Pr3OPC8SHM6yadF212W3LJlzfhQ=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127170523-a11fee39970a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a h1:iMEPP7MC3/7DTs/BNMshsBoviG3yWSTRbIzXKdrUwHw=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231127171411-ffb4ff80f85a/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818 h1:PTQ2SSijkoN8Qkctq9oLzEdzCLLv7WoD2dqScmpb15o=
github.com/netbirdio/management-integrations/integrations v0.0.0-20231128103220-a3b41e63c818/go.mod h1:aRyvEvLzMX9+eDgW+cMRh0CkxR8sYIszmEITaWFZ5Vc=
github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0 h1:hirFRfx3grVA/9eEyjME5/z3nxdJlN9kfQpvWWPk32g=
github.com/netbirdio/service v0.0.0-20230215170314-b923b89432b0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949 h1:xbWM9BU6mwZZLHxEjxIX/V8Hv3HurQt4mReIE4mY4DM=

View File

@ -17,6 +17,7 @@ import (
"github.com/eko/gocache/v3/cache"
cacheStore "github.com/eko/gocache/v3/store"
"github.com/netbirdio/management-integrations/integrations"
gocache "github.com/patrickmn/go-cache"
"github.com/rs/xid"
log "github.com/sirupsen/logrus"
@ -159,12 +160,12 @@ type Settings struct {
// JWTGroupsClaimName from which we extract groups name to add it to account groups
JWTGroupsClaimName string
// Extra contains additional settings that are not supported in the open-source version
// Extra is a dictionary of Account settings
Extra *ExtraSettings
}
type ExtraSettings struct {
// PeerApprovalEnabled enables or disables the need for peers to be approved by an administrator
// PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator
PeerApprovalEnabled bool
}
@ -352,7 +353,20 @@ func (a *Account) GetGroup(groupID string) *Group {
// GetPeerNetworkMap returns a group by ID if exists, nil otherwise
func (a *Account) GetPeerNetworkMap(peerID, dnsDomain string) *NetworkMap {
peer := a.Peers[peerID]
if peer == nil {
return &NetworkMap{
Network: a.Network.Copy(),
}
}
validatedPeers := integrations.ValidatePeers([]*Peer{peer}, a)
if len(validatedPeers) == 0 {
return &NetworkMap{
Network: a.Network.Copy(),
}
}
aclPeers, firewallRules := a.getPeerConnectionResources(peerID)
aclPeers = integrations.ValidatePeers(aclPeers, a)
// exclude expired peers
var peersToConnect []*Peer
var expiredPeers []*Peer
@ -879,6 +893,11 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string,
return nil, err
}
err = integrations.ValidateExtraSettings(newSettings.Extra, account, am)
if err != nil {
return nil, err
}
user, err := account.FindUser(userID)
if err != nil {
return nil, err
@ -905,6 +924,18 @@ func (am *DefaultAccountManager) UpdateAccountSettings(accountID, userID string,
am.checkAndSchedulePeerLoginExpiration(account)
}
// if oldSettings.PeerApprovalEnabled != newSettings.PeerApprovalEnabled {
// event := activity.AccountPeerApprovalEnabled
// if !newSettings.PeerApprovalEnabled {
// event = activity.AccountPeerApprovalDisabled
// }
// am.StoreEvent(userID, accountID, accountID, event, nil)
//
// for _, peer := range account.Peers {
// peer.Status.RequiresApproval = false
// }
// }
updatedAccount := account.UpdateSettings(newSettings)
err = am.Store.SaveAccount(account)

View File

@ -120,6 +120,14 @@ const (
IntegrationUpdated
// IntegrationDeleted indicates that the user deleted an integration
IntegrationDeleted
// AccountPeerApprovalEnabled indicates that the user enabled peer approval for the account
AccountPeerApprovalEnabled
// AccountPeerApprovalDisabled indicates that the user disabled peer approval for the account
AccountPeerApprovalDisabled
// PeerApproved indicates that the peer has been approved
PeerApproved
// PeerApprovalRevoked indicates that the peer approval has been revoked
PeerApprovalRevoked
)
var activityMap = map[Activity]Code{
@ -178,6 +186,10 @@ var activityMap = map[Activity]Code{
IntegrationCreated: {"Integration created", "integration.create"},
IntegrationUpdated: {"Integration updated", "integration.update"},
IntegrationDeleted: {"Integration deleted", "integration.delete"},
AccountPeerApprovalEnabled: {"Account peer approval enabled", "account.setting.peer.approval.enable"},
AccountPeerApprovalDisabled: {"Account peer approval disabled", "account.setting.peer.approval.disable"},
PeerApproved: {"Peer approved", "peer.approve"},
PeerApprovalRevoked: {"Peer approval revoked", "peer.approval.revoke"},
}
// StringCode returns a string code of the activity

View File

@ -77,6 +77,10 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request)
PeerLoginExpiration: time.Duration(float64(time.Second.Nanoseconds()) * float64(req.Settings.PeerLoginExpiration)),
}
if req.Settings.Extra != nil {
settings.Extra = &server.ExtraSettings{PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled}
}
if req.Settings.JwtGroupsEnabled != nil {
settings.JWTGroupsEnabled = *req.Settings.JwtGroupsEnabled
}
@ -99,14 +103,20 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request)
}
func toAccountResponse(account *server.Account) *api.Account {
return &api.Account{
Id: account.Id,
Settings: api.AccountSettings{
settings := api.AccountSettings{
PeerLoginExpiration: int(account.Settings.PeerLoginExpiration.Seconds()),
PeerLoginExpirationEnabled: account.Settings.PeerLoginExpirationEnabled,
GroupsPropagationEnabled: &account.Settings.GroupsPropagationEnabled,
JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled,
JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName,
},
}
if account.Settings.Extra != nil {
settings.Extra = &api.AccountExtraSettings{PeerApprovalEnabled: &account.Settings.Extra.PeerApprovalEnabled}
}
return &api.Account{
Id: account.Id,
Settings: settings,
}
}

View File

@ -66,9 +66,18 @@ components:
description: Name of the claim from which we extract groups names to add it to account groups.
type: string
example: "roles"
extra:
$ref: '#/components/schemas/AccountExtraSettings'
required:
- peer_login_expiration_enabled
- peer_login_expiration
AccountExtraSettings:
type: object
properties:
peer_approval_enabled:
description: Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin.
type: boolean
example: true
AccountRequest:
type: object
properties:
@ -213,6 +222,10 @@ components:
login_expiration_enabled:
type: boolean
example: false
approval_required:
description: (Cloud only) Indicates whether peer needs approval
type: boolean
example: true
required:
- name
- ssh_enabled
@ -281,6 +294,10 @@ components:
type: string
format: date-time
example: 2023-05-05T09:00:35.477782Z
approval_required:
description: (Cloud only) Indicates whether peer needs approval
type: boolean
example: true
required:
- ip
- connected

View File

@ -142,6 +142,12 @@ type Account struct {
Settings AccountSettings `json:"settings"`
}
// AccountExtraSettings defines model for AccountExtraSettings.
type AccountExtraSettings struct {
// PeerApprovalEnabled Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin.
PeerApprovalEnabled *bool `json:"peer_approval_enabled,omitempty"`
}
// AccountRequest defines model for AccountRequest.
type AccountRequest struct {
Settings AccountSettings `json:"settings"`
@ -149,6 +155,8 @@ type AccountRequest struct {
// AccountSettings defines model for AccountSettings.
type AccountSettings struct {
Extra *AccountExtraSettings `json:"extra,omitempty"`
// GroupsPropagationEnabled Allows propagate the new user auto groups to peers that belongs to the user
GroupsPropagationEnabled *bool `json:"groups_propagation_enabled,omitempty"`
@ -323,6 +331,9 @@ type Peer struct {
// AccessiblePeers List of accessible peers
AccessiblePeers []AccessiblePeer `json:"accessible_peers"`
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
ApprovalRequired *bool `json:"approval_required,omitempty"`
// Connected Peer to Management connection status
Connected bool `json:"connected"`
@ -374,6 +385,9 @@ type Peer struct {
// PeerBase defines model for PeerBase.
type PeerBase struct {
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
ApprovalRequired *bool `json:"approval_required,omitempty"`
// Connected Peer to Management connection status
Connected bool `json:"connected"`
@ -428,6 +442,9 @@ type PeerBatch struct {
// AccessiblePeersCount Number of accessible peers
AccessiblePeersCount int `json:"accessible_peers_count"`
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
ApprovalRequired *bool `json:"approval_required,omitempty"`
// Connected Peer to Management connection status
Connected bool `json:"connected"`
@ -488,6 +505,8 @@ type PeerMinimum struct {
// PeerRequest defines model for PeerRequest.
type PeerRequest struct {
// ApprovalRequired (Cloud only) Indicates whether peer needs approval
ApprovalRequired *bool `json:"approval_required,omitempty"`
LoginExpirationEnabled bool `json:"login_expiration_enabled"`
Name string `json:"name"`
SshEnabled bool `json:"ssh_enabled"`

View File

@ -81,6 +81,11 @@ func (h *PeersHandler) updatePeer(account *server.Account, user *server.User, pe
update := &server.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name,
LoginExpirationEnabled: req.LoginExpirationEnabled}
if req.ApprovalRequired != nil {
update.Status = &server.PeerStatus{RequiresApproval: *req.ApprovalRequired}
}
peer, err := h.accountManager.UpdatePeer(account.Id, user.Id, update)
if err != nil {
util.WriteError(err, w)
@ -248,6 +253,7 @@ func toSinglePeerResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dnsD
LastLogin: peer.LastLogin,
LoginExpired: peer.Status.LoginExpired,
AccessiblePeers: accessiblePeer,
Approved: &peer.Status.Approved,
}
}
@ -270,6 +276,7 @@ func toPeerListItemResponse(peer *server.Peer, groupsInfo []api.GroupMinimum, dn
LastLogin: peer.LastLogin,
LoginExpired: peer.Status.LoginExpired,
AccessiblePeersCount: accessiblePeersCount,
Approved: peer.Status.Approved,
}
}

View File

@ -6,6 +6,7 @@ import (
"strings"
"time"
"github.com/netbirdio/management-integrations/integrations"
"github.com/rs/xid"
"github.com/netbirdio/netbird/management/server/activity"
@ -46,6 +47,8 @@ type PeerStatus struct {
Connected bool
// LoginExpired
LoginExpired bool
// RequiresApproval indicates whether peer requires approval or not
RequiresApproval bool
}
// PeerSync used as a data object between the gRPC API and AccountManager on Sync request.
@ -195,6 +198,7 @@ func (p *PeerStatus) Copy() *PeerStatus {
LastSeen: p.LastSeen,
Connected: p.Connected,
LoginExpired: p.LoginExpired,
RequiresApproval: p.RequiresApproval,
}
}
@ -304,6 +308,11 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Pe
return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID)
}
update, err = integrations.ValidatePeersUpdateRequest(update, peer, am)
if err != nil {
return nil, err
}
if peer.SSHEnabled != update.SSHEnabled {
peer.SSHEnabled = update.SSHEnabled
event := activity.PeerSSHEnabled
@ -562,6 +571,10 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*
Ephemeral: ephemeral,
}
if account.Settings.Extra.PeerApprovalEnabled {
newPeer.Status.RequiresApproval = true
}
// add peer to 'All' group
group, err := account.GetGroupAll()
if err != nil {
@ -632,6 +645,11 @@ func (am *DefaultAccountManager) SyncPeer(sync PeerSync) (*Peer, *NetworkMap, er
return nil, nil, status.Errorf(status.Unauthenticated, "peer is not registered")
}
validatedPeers := integrations.ValidatePeers([]*Peer{peer}, account)
if len(validatedPeers) == 0 {
return nil, nil, status.Errorf(status.PermissionDenied, "peer validation failed")
}
err = checkIfPeerOwnerIsBlocked(peer, account)
if err != nil {
return nil, nil, err