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 }