Add system activity tracking and event store (#636)

This PR adds system activity tracking. 
The management service records events like 
add/remove peer,  group, rule, route, etc.

The activity events are stored in the SQLite event store
and can be queried by the HTTP API.
This commit is contained in:
Misha Bragin
2023-01-02 15:11:32 +01:00
committed by GitHub
parent 50caacff69
commit 5c0b8a46f0
42 changed files with 1827 additions and 227 deletions

View File

@ -2,7 +2,9 @@ package server
import (
"github.com/google/uuid"
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/status"
log "github.com/sirupsen/logrus"
"hash/fnv"
"strconv"
"strings"
@ -107,12 +109,20 @@ func (key *SetupKey) Copy() *SetupKey {
}
}
// EventMeta returns activity event meta related to the setup key
func (key *SetupKey) EventMeta() map[string]any {
return map[string]any{"name": key.Name, "type": key.Type, "key": key.HiddenCopy(1).Key}
}
// HiddenCopy returns a copy of the key with a Key value hidden with "*" and a 5 character prefix.
// E.g., "831F6*******************************"
func (key *SetupKey) HiddenCopy() *SetupKey {
func (key *SetupKey) HiddenCopy(length int) *SetupKey {
k := key.Copy()
prefix := k.Key[0:5]
k.Key = prefix + strings.Repeat("*", utf8.RuneCountInString(key.Key)-len(prefix))
if length > utf8.RuneCountInString(key.Key) {
length = utf8.RuneCountInString(key.Key) - len(prefix)
}
k.Key = prefix + strings.Repeat("*", length)
return k
}
@ -189,7 +199,7 @@ func Hash(s string) uint32 {
// CreateSetupKey generates a new setup key with a given name, type, list of groups IDs to auto-assign to peers registered with this key,
// and adds it to the specified account. A list of autoGroups IDs can be empty.
func (am *DefaultAccountManager) CreateSetupKey(accountID string, keyName string, keyType SetupKeyType,
expiresIn time.Duration, autoGroups []string, usageLimit int) (*SetupKey, error) {
expiresIn time.Duration, autoGroups []string, usageLimit int, userID string) (*SetupKey, error) {
unlock := am.Store.AcquireAccountLock(accountID)
defer unlock()
@ -211,12 +221,44 @@ func (am *DefaultAccountManager) CreateSetupKey(accountID string, keyName string
setupKey := GenerateSetupKey(keyName, keyType, keyDuration, autoGroups, usageLimit)
account.SetupKeys[setupKey.Key] = setupKey
err = am.Store.SaveAccount(account)
if err != nil {
return nil, status.Errorf(status.Internal, "failed adding account key")
}
_, err = am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.SetupKeyCreated,
InitiatorID: userID,
TargetID: setupKey.Id,
AccountID: accountID,
Meta: setupKey.EventMeta(),
})
if err != nil {
return nil, err
}
for _, g := range setupKey.AutoGroups {
group := account.GetGroup(g)
if group != nil {
_, err := am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.GroupAddedToSetupKey,
InitiatorID: userID,
TargetID: setupKey.Id,
AccountID: accountID,
Meta: map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": setupKey.Name},
})
if err != nil {
log.Errorf("failed saving setup key activity event %s: %v",
activity.GroupAddedToSetupKey.StringCode(), err)
continue
}
} else {
log.Errorf("group %s not found while saving setup key activity event of account %s", g, account.Id)
}
}
return setupKey, nil
}
@ -224,7 +266,7 @@ func (am *DefaultAccountManager) CreateSetupKey(accountID string, keyName string
// Due to the unique nature of a SetupKey certain properties must not be overwritten
// (e.g. the key itself, creation date, ID, etc).
// These properties are overwritten: Name, AutoGroups, Revoked. The rest is copied from the existing key.
func (am *DefaultAccountManager) SaveSetupKey(accountID string, keyToSave *SetupKey) (*SetupKey, error) {
func (am *DefaultAccountManager) SaveSetupKey(accountID string, keyToSave *SetupKey, userID string) (*SetupKey, error) {
unlock := am.Store.AcquireAccountLock(accountID)
defer unlock()
@ -261,6 +303,67 @@ func (am *DefaultAccountManager) SaveSetupKey(accountID string, keyToSave *Setup
return nil, err
}
if !oldKey.Revoked && newKey.Revoked {
_, err = am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.SetupKeyRevoked,
InitiatorID: userID,
TargetID: newKey.Id,
AccountID: accountID,
Meta: newKey.EventMeta(),
})
if err != nil {
return nil, err
}
}
defer func() {
addedGroups := difference(newKey.AutoGroups, oldKey.AutoGroups)
removedGroups := difference(oldKey.AutoGroups, newKey.AutoGroups)
for _, g := range removedGroups {
group := account.GetGroup(g)
if group != nil {
_, err := am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.GroupRemovedFromSetupKey,
InitiatorID: userID,
TargetID: oldKey.Id,
AccountID: accountID,
Meta: map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": newKey.Name},
})
if err != nil {
log.Errorf("failed saving setup key activity event %s: %v",
activity.GroupRemovedFromSetupKey.StringCode(), err)
continue
}
} else {
log.Errorf("group %s not found while saving setup key activity event of account %s", g, account.Id)
}
}
for _, g := range addedGroups {
group := account.GetGroup(g)
if group != nil {
_, err := am.eventStore.Save(&activity.Event{
Timestamp: time.Now(),
Activity: activity.GroupAddedToSetupKey,
InitiatorID: userID,
TargetID: oldKey.Id,
AccountID: accountID,
Meta: map[string]any{"group": group.Name, "group_id": group.ID, "setupkey": newKey.Name},
})
if err != nil {
log.Errorf("failed saving setup key activity event %s: %v",
activity.GroupAddedToSetupKey.StringCode(), err)
continue
}
} else {
log.Errorf("group %s not found while saving setup key activity event of account %s", g, account.Id)
}
}
}()
return newKey, am.updateAccountPeers(account)
}
@ -282,7 +385,7 @@ func (am *DefaultAccountManager) ListSetupKeys(accountID, userID string) ([]*Set
for _, key := range account.SetupKeys {
var k *SetupKey
if !user.IsAdmin() {
k = key.HiddenCopy()
k = key.HiddenCopy(999)
} else {
k = key.Copy()
}
@ -324,7 +427,7 @@ func (am *DefaultAccountManager) GetSetupKey(accountID, userID, keyID string) (*
}
if !user.IsAdmin() {
foundKey = foundKey.HiddenCopy()
foundKey = foundKey.HiddenCopy(999)
}
return foundKey, nil