mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-19 03:16:58 +02:00
Feat rego default policy (#700)
Converts rules to Rego policies and allow users to write raw policies to set up connectivity and firewall on the clients.
This commit is contained in:
committed by
GitHub
parent
221934447e
commit
3bfa26b13b
@@ -1,10 +1,6 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/netbirdio/netbird/management/server/activity"
|
||||
"github.com/netbirdio/netbird/management/server/status"
|
||||
"strings"
|
||||
)
|
||||
import "fmt"
|
||||
|
||||
// TrafficFlowType defines allowed direction of the traffic in the rule
|
||||
type TrafficFlowType int
|
||||
@@ -18,6 +14,10 @@ const (
|
||||
DefaultRuleName = "Default"
|
||||
// DefaultRuleDescription is a description for the Default rule that is created for every account
|
||||
DefaultRuleDescription = "This is a default rule that allows connections between all the resources"
|
||||
// DefaultPolicyName is a name for the Default policy that is created for every account
|
||||
DefaultPolicyName = "Default"
|
||||
// DefaultPolicyDescription is a description for the Default policy that is created for every account
|
||||
DefaultPolicyDescription = "This is a default policy that allows connections between all the resources"
|
||||
)
|
||||
|
||||
// Rule of ACL for groups
|
||||
@@ -44,38 +44,6 @@ type Rule struct {
|
||||
Flow TrafficFlowType
|
||||
}
|
||||
|
||||
const (
|
||||
// UpdateRuleName indicates a rule name update operation
|
||||
UpdateRuleName RuleUpdateOperationType = iota
|
||||
// UpdateRuleDescription indicates a rule description update operation
|
||||
UpdateRuleDescription
|
||||
// UpdateRuleStatus indicates a rule status update operation
|
||||
UpdateRuleStatus
|
||||
// UpdateRuleFlow indicates a rule flow update operation
|
||||
UpdateRuleFlow
|
||||
// InsertGroupsToSource indicates an insert groups to source rule operation
|
||||
InsertGroupsToSource
|
||||
// RemoveGroupsFromSource indicates an remove groups from source rule operation
|
||||
RemoveGroupsFromSource
|
||||
// UpdateSourceGroups indicates a replacement of source group list of a rule operation
|
||||
UpdateSourceGroups
|
||||
// InsertGroupsToDestination indicates an insert groups to destination rule operation
|
||||
InsertGroupsToDestination
|
||||
// RemoveGroupsFromDestination indicates an remove groups from destination rule operation
|
||||
RemoveGroupsFromDestination
|
||||
// UpdateDestinationGroups indicates a replacement of destination group list of a rule operation
|
||||
UpdateDestinationGroups
|
||||
)
|
||||
|
||||
// RuleUpdateOperationType operation type
|
||||
type RuleUpdateOperationType int
|
||||
|
||||
// RuleUpdateOperation operation object with type and values to be applied
|
||||
type RuleUpdateOperation struct {
|
||||
Type RuleUpdateOperationType
|
||||
Values []string
|
||||
}
|
||||
|
||||
func (r *Rule) Copy() *Rule {
|
||||
return &Rule{
|
||||
ID: r.ID,
|
||||
@@ -93,185 +61,36 @@ func (r *Rule) EventMeta() map[string]any {
|
||||
return map[string]any{"name": r.Name}
|
||||
}
|
||||
|
||||
// GetRule of ACL from the store
|
||||
func (am *DefaultAccountManager) GetRule(accountID, ruleID, userID string) (*Rule, error) {
|
||||
unlock := am.Store.AcquireAccountLock(accountID)
|
||||
defer unlock()
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// ToPolicyRule converts a Rule to a PolicyRule object
|
||||
func (r *Rule) ToPolicyRule() *PolicyRule {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
user, err := account.FindUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return &PolicyRule{
|
||||
ID: r.ID,
|
||||
Name: r.Name,
|
||||
Enabled: !r.Disabled,
|
||||
Description: r.Description,
|
||||
Action: PolicyTrafficActionAccept,
|
||||
Destinations: r.Destination,
|
||||
Sources: r.Source,
|
||||
}
|
||||
|
||||
if !user.IsAdmin() {
|
||||
return nil, status.Errorf(status.PermissionDenied, "only admins are allowed to view rules")
|
||||
}
|
||||
|
||||
rule, ok := account.Rules[ruleID]
|
||||
if ok {
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
return nil, status.Errorf(status.NotFound, "rule with ID %s not found", ruleID)
|
||||
}
|
||||
|
||||
// SaveRule of ACL in the store
|
||||
func (am *DefaultAccountManager) SaveRule(accountID, userID string, rule *Rule) error {
|
||||
unlock := am.Store.AcquireAccountLock(accountID)
|
||||
defer unlock()
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, exists := account.Rules[rule.ID]
|
||||
|
||||
account.Rules[rule.ID] = rule
|
||||
|
||||
account.Network.IncSerial()
|
||||
if err = am.Store.SaveAccount(account); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
action := activity.RuleAdded
|
||||
if exists {
|
||||
action = activity.RuleUpdated
|
||||
}
|
||||
am.storeEvent(userID, rule.ID, accountID, action, rule.EventMeta())
|
||||
|
||||
return am.updateAccountPeers(account)
|
||||
}
|
||||
|
||||
// UpdateRule updates a rule using a list of operations
|
||||
func (am *DefaultAccountManager) UpdateRule(accountID string, ruleID string,
|
||||
operations []RuleUpdateOperation) (*Rule, error) {
|
||||
unlock := am.Store.AcquireAccountLock(accountID)
|
||||
defer unlock()
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ruleToUpdate, ok := account.Rules[ruleID]
|
||||
if !ok {
|
||||
return nil, status.Errorf(status.NotFound, "rule %s no longer exists", ruleID)
|
||||
}
|
||||
|
||||
rule := ruleToUpdate.Copy()
|
||||
|
||||
for _, operation := range operations {
|
||||
switch operation.Type {
|
||||
case UpdateRuleName:
|
||||
rule.Name = operation.Values[0]
|
||||
case UpdateRuleDescription:
|
||||
rule.Description = operation.Values[0]
|
||||
case UpdateRuleFlow:
|
||||
if operation.Values[0] != TrafficFlowBidirectString {
|
||||
return nil, status.Errorf(status.InvalidArgument, "failed to parse flow")
|
||||
}
|
||||
rule.Flow = TrafficFlowBidirect
|
||||
case UpdateRuleStatus:
|
||||
if strings.ToLower(operation.Values[0]) == "true" {
|
||||
rule.Disabled = true
|
||||
} else if strings.ToLower(operation.Values[0]) == "false" {
|
||||
rule.Disabled = false
|
||||
} else {
|
||||
return nil, status.Errorf(status.InvalidArgument, "failed to parse status")
|
||||
}
|
||||
case UpdateSourceGroups:
|
||||
rule.Source = operation.Values
|
||||
case InsertGroupsToSource:
|
||||
sourceList := rule.Source
|
||||
resultList := removeFromList(sourceList, operation.Values)
|
||||
rule.Source = append(resultList, operation.Values...)
|
||||
case RemoveGroupsFromSource:
|
||||
sourceList := rule.Source
|
||||
resultList := removeFromList(sourceList, operation.Values)
|
||||
rule.Source = resultList
|
||||
case UpdateDestinationGroups:
|
||||
rule.Destination = operation.Values
|
||||
case InsertGroupsToDestination:
|
||||
sourceList := rule.Destination
|
||||
resultList := removeFromList(sourceList, operation.Values)
|
||||
rule.Destination = append(resultList, operation.Values...)
|
||||
case RemoveGroupsFromDestination:
|
||||
sourceList := rule.Destination
|
||||
resultList := removeFromList(sourceList, operation.Values)
|
||||
rule.Destination = resultList
|
||||
}
|
||||
}
|
||||
|
||||
account.Rules[ruleID] = rule
|
||||
|
||||
account.Network.IncSerial()
|
||||
if err = am.Store.SaveAccount(account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = am.updateAccountPeers(account)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(status.Internal, "failed to update account peers")
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
// DeleteRule of ACL from the store
|
||||
func (am *DefaultAccountManager) DeleteRule(accountID, ruleID, userID string) error {
|
||||
unlock := am.Store.AcquireAccountLock(accountID)
|
||||
defer unlock()
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rule := account.Rules[ruleID]
|
||||
// RuleToPolicy converts a Rule to a Policy query object
|
||||
func RuleToPolicy(rule *Rule) (*Policy, error) {
|
||||
if rule == nil {
|
||||
return status.Errorf(status.NotFound, "rule with ID %s doesn't exist", ruleID)
|
||||
return nil, fmt.Errorf("rule is empty")
|
||||
}
|
||||
delete(account.Rules, ruleID)
|
||||
|
||||
account.Network.IncSerial()
|
||||
if err = am.Store.SaveAccount(account); err != nil {
|
||||
return err
|
||||
policy := &Policy{
|
||||
ID: rule.ID,
|
||||
Name: rule.Name,
|
||||
Description: rule.Description,
|
||||
Enabled: !rule.Disabled,
|
||||
Rules: []*PolicyRule{rule.ToPolicyRule()},
|
||||
}
|
||||
|
||||
am.storeEvent(userID, rule.ID, accountID, activity.RuleRemoved, rule.EventMeta())
|
||||
|
||||
return am.updateAccountPeers(account)
|
||||
}
|
||||
|
||||
// ListRules of ACL from the store
|
||||
func (am *DefaultAccountManager) ListRules(accountID, userID string) ([]*Rule, error) {
|
||||
unlock := am.Store.AcquireAccountLock(accountID)
|
||||
defer unlock()
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
if err := policy.UpdateQueryFromRules(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err := account.FindUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !user.IsAdmin() {
|
||||
return nil, status.Errorf(status.PermissionDenied, "Only Administrators can view Access Rules")
|
||||
}
|
||||
|
||||
rules := make([]*Rule, 0, len(account.Rules))
|
||||
for _, item := range account.Rules {
|
||||
rules = append(rules, item)
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
return policy, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user