github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/rules/policy_loader.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the Apache License Version 2.0.
     3  // This product includes software developed at Datadog (https://www.datadoghq.com/).
     4  // Copyright 2016-present Datadog, Inc.
     5  
     6  // Package rules holds rules related files
     7  package rules
     8  
     9  import (
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/hashicorp/go-multierror"
    14  	"github.com/skydive-project/go-debouncer"
    15  )
    16  
    17  const (
    18  	PolicyProviderTypeDir     = "file"          // PolicyProviderTypeDir defines directory policy provider
    19  	PolicyProviderTypeRC      = "remote-config" // PolicyProviderTypeRC defines RC policy provider
    20  	PolicyProviderTypeBundled = "bundled"       // PolicyProviderTypeBundled defines the bundled policy provider
    21  )
    22  
    23  var (
    24  	debounceDelay = 5 * time.Second
    25  )
    26  
    27  // PolicyLoaderOpts options used during the loading
    28  type PolicyLoaderOpts struct {
    29  	MacroFilters       []MacroFilter
    30  	RuleFilters        []RuleFilter
    31  	DisableEnforcement bool
    32  }
    33  
    34  // PolicyLoader defines a policy loader
    35  type PolicyLoader struct {
    36  	sync.RWMutex
    37  
    38  	Providers []PolicyProvider
    39  
    40  	listeners []chan struct{}
    41  	debouncer *debouncer.Debouncer
    42  }
    43  
    44  // LoadPolicies gathers the policies in the correct precedence order and ensuring there's only 1 default policy.
    45  // RC Default replaces Local Default and takes precedence above any other policies, and RC Custom takes precedence over Local Custom.
    46  func (p *PolicyLoader) LoadPolicies(opts PolicyLoaderOpts) ([]*Policy, *multierror.Error) {
    47  	p.RLock()
    48  	defer p.RUnlock()
    49  
    50  	var (
    51  		errs          *multierror.Error
    52  		allPolicies   []*Policy
    53  		defaultPolicy *Policy
    54  	)
    55  
    56  	p.remoteConfigProvidersFirst()
    57  	for _, provider := range p.Providers {
    58  		policies, err := provider.LoadPolicies(opts.MacroFilters, opts.RuleFilters)
    59  		if err.ErrorOrNil() != nil {
    60  			errs = multierror.Append(errs, err)
    61  		}
    62  
    63  		if policies == nil {
    64  			continue
    65  		}
    66  
    67  		for _, policy := range policies {
    68  			if policy.Name == DefaultPolicyName {
    69  				if defaultPolicy == nil {
    70  					defaultPolicy = policy // only load the first seen default policy
    71  				}
    72  			} else {
    73  				allPolicies = append(allPolicies, policy)
    74  			}
    75  		}
    76  	}
    77  
    78  	if defaultPolicy != nil {
    79  		allPolicies = append([]*Policy{defaultPolicy}, allPolicies...)
    80  	}
    81  
    82  	return allPolicies, errs
    83  }
    84  
    85  // NewPolicyReady returns chan to listen new policy ready event
    86  func (p *PolicyLoader) NewPolicyReady() <-chan struct{} {
    87  	p.Lock()
    88  	defer p.Unlock()
    89  
    90  	ch := make(chan struct{})
    91  	p.listeners = append(p.listeners, ch)
    92  	return ch
    93  }
    94  
    95  func (p *PolicyLoader) onNewPoliciesReady() {
    96  	p.debouncer.Call()
    97  }
    98  
    99  func (p *PolicyLoader) notifyListeners() {
   100  	p.RLock()
   101  	defer p.RUnlock()
   102  
   103  	// TODO(safchain) debounce
   104  	for _, ch := range p.listeners {
   105  		select {
   106  		case ch <- struct{}{}:
   107  		default:
   108  		}
   109  	}
   110  }
   111  
   112  // Close stops the loader
   113  func (p *PolicyLoader) Close() {
   114  	p.RLock()
   115  	defer p.RUnlock()
   116  
   117  	for _, ch := range p.listeners {
   118  		close(ch)
   119  	}
   120  
   121  	p.debouncer.Stop()
   122  }
   123  
   124  // SetProviders set providers
   125  func (p *PolicyLoader) SetProviders(providers []PolicyProvider) {
   126  	p.Lock()
   127  	defer p.Unlock()
   128  
   129  	p.Providers = providers
   130  	for _, provider := range providers {
   131  		provider.SetOnNewPoliciesReadyCb(p.onNewPoliciesReady)
   132  	}
   133  }
   134  
   135  // NewPolicyLoader returns a new loader
   136  func NewPolicyLoader(providers ...PolicyProvider) *PolicyLoader {
   137  	p := &PolicyLoader{}
   138  
   139  	p.debouncer = debouncer.New(debounceDelay, p.notifyListeners)
   140  	p.debouncer.Start()
   141  
   142  	p.SetProviders(providers)
   143  
   144  	return p
   145  }
   146  
   147  // Rules from RC override local rules if they share the same ID, so the RC policy provider has to be first
   148  func (p *PolicyLoader) remoteConfigProvidersFirst() {
   149  	var remoteConfigProviders []PolicyProvider
   150  	var otherProviders []PolicyProvider
   151  
   152  	for _, provider := range p.Providers {
   153  		if provider.Type() == PolicyProviderTypeRC {
   154  			remoteConfigProviders = append(remoteConfigProviders, provider)
   155  		} else {
   156  			otherProviders = append(otherProviders, provider)
   157  		}
   158  	}
   159  
   160  	p.Providers = append(remoteConfigProviders, otherProviders...)
   161  }