@@ -30,20 +30,12 @@ import (
3030	yaml "gopkg.in/yaml.v3" 
3131)
3232
33- type  DefaultValidatorConfig  struct  {
33+ type  DefaultConfig  struct  {
3434	// Enable the default validator plugin. 
3535	Enable  bool  `yaml:"enable" toml:"enable"` 
36- 	// RejectOCIHookAdjustment fails validation if OCI hooks are adjusted. 
37- 	RejectOCIHookAdjustment  bool  `yaml:"rejectOCIHookAdjustment" toml:"reject_oci_hook_adjustment"` 
38- 	// RejectRuntimeDefaultSeccompAdjustment fails validation if a runtime default seccomp 
39- 	// policy is adjusted. 
40- 	RejectRuntimeDefaultSeccompAdjustment  bool  `yaml:"rejectRuntimeDefaultSeccompAdjustment" toml:"reject_runtime_default_seccomp_adjustment"` 
41- 	// RejectUnconfinedSeccompAdjustment fails validation if an unconfined seccomp policy is 
42- 	// adjusted. 
43- 	RejectUnconfinedSeccompAdjustment  bool  `yaml:"rejectUnconfinedSeccompAdjustment" toml:"reject_unconfined_seccomp_adjustment"` 
44- 	// RejectCustomSeccompAdjustment fails validation if a custom seccomp policy (aka LOCALHOST) 
45- 	// is adjusted. 
46- 	RejectCustomSeccompAdjustment  bool  `yaml:"rejectCustomSeccompAdjustment" toml:"reject_custom_seccomp_adjustment"` 
36+ 	* Config 
37+ 	// Overrides provide per-role overrides to the default configuration. 
38+ 	Overrides  map [string ]* Config  `yaml:"overrides" toml:"overrides"` 
4739	// RequiredPlugins list globally required plugins. These must be present 
4840	// or otherwise validation will fail. 
4941	// WARNING: This is a global setting and will affect all containers. In 
@@ -59,9 +51,24 @@ type DefaultValidatorConfig struct {
5951	TolerateMissingAnnotation  string  `yaml:"tolerateMissingPluginsAnnotation" toml:"tolerate_missing_plugins_annotation"` 
6052}
6153
54+ // Config provides validation defaults or per role overrides. 
55+ type  Config  struct  {
56+ 	// RejectOCIHookAdjustment fails validation if OCI hooks are adjusted. 
57+ 	RejectOCIHookAdjustment  * bool  `yaml:"rejectOCIHookAdjustment" toml:"reject_oci_hook_adjustment"` 
58+ 	// RejectRuntimeDefaultSeccompAdjustment fails validation if a runtime default seccomp 
59+ 	// policy is adjusted. 
60+ 	RejectRuntimeDefaultSeccompAdjustment  * bool  `yaml:"rejectRuntimeDefaultSeccompAdjustment" toml:"reject_runtime_default_seccomp_adjustment"` 
61+ 	// RejectUnconfinedSeccompAdjustment fails validation if an unconfined seccomp policy is 
62+ 	// adjusted. 
63+ 	RejectUnconfinedSeccompAdjustment  * bool  `yaml:"rejectUnconfinedSeccompAdjustment" toml:"reject_unconfined_seccomp_adjustment"` 
64+ 	// RejectCustomSeccompAdjustment fails validation if a custom seccomp policy (aka LOCALHOST) 
65+ 	// is adjusted. 
66+ 	RejectCustomSeccompAdjustment  * bool  `yaml:"rejectCustomSeccompAdjustment" toml:"reject_custom_seccomp_adjustment"` 
67+ }
68+ 
6269// DefaultValidator implements default validation. 
6370type  DefaultValidator  struct  {
64- 	cfg  DefaultValidatorConfig 
71+ 	cfg  DefaultConfig 
6572}
6673
6774const  (
@@ -75,12 +82,12 @@ var (
7582)
7683
7784// NewDefaultValidator creates a new instance of the validator. 
78- func  NewDefaultValidator (cfg  * DefaultValidatorConfig ) * DefaultValidator  {
85+ func  NewDefaultValidator (cfg  * DefaultConfig ) * DefaultValidator  {
7986	return  & DefaultValidator {cfg : * cfg }
8087}
8188
8289// SetConfig sets new configuration for the validator. 
83- func  (v  * DefaultValidator ) SetConfig (cfg  * DefaultValidatorConfig ) {
90+ func  (v  * DefaultValidator ) SetConfig (cfg  * DefaultConfig ) {
8491	if  cfg  ==  nil  {
8592		return 
8693	}
@@ -92,50 +99,64 @@ func (v *DefaultValidator) ValidateContainerAdjustment(ctx context.Context, req
9299	log .Debugf (ctx , "Validating adjustment of container %s/%s/%s" ,
93100		req .GetPod ().GetNamespace (), req .GetPod ().GetName (), req .GetContainer ().GetName ())
94101
95- 	if  err  :=  v .validateOCIHooks (req ); err  !=  nil  {
102+ 	plugins  :=  req .GetPluginMap ()
103+ 
104+ 	if  err  :=  v .validateOCIHooks (req , plugins ); err  !=  nil  {
96105		log .Errorf (ctx , "rejecting adjustment: %v" , err )
97106		return  err 
98107	}
99108
100- 	if  err  :=  v .validateSeccompPolicy (req ); err  !=  nil  {
109+ 	if  err  :=  v .validateSeccompPolicy (req ,  plugins ); err  !=  nil  {
101110		log .Errorf (ctx , "rejecting adjustment: %v" , err )
102111		return  err 
103112	}
104113
105- 	if  err  :=  v .validateRequiredPlugins (req ); err  !=  nil  {
114+ 	if  err  :=  v .validateRequiredPlugins (req ,  plugins ); err  !=  nil  {
106115		log .Errorf (ctx , "rejecting adjustment: %v" , err )
107116		return  err 
108117	}
109118
110119	return  nil 
111120}
112121
113- func  (v  * DefaultValidator ) validateOCIHooks (req  * api.ValidateContainerAdjustmentRequest ) error  {
122+ func  (v  * DefaultValidator ) validateOCIHooks (req  * api.ValidateContainerAdjustmentRequest ,  plugins   map [ string ] * api. PluginInstance ) error  {
114123	if  req .Adjust  ==  nil  {
115124		return  nil 
116125	}
117126
118- 	if  ! v .cfg .RejectOCIHookAdjustment  {
127+ 	owners , claimed  :=  req .Owners .HooksOwner (req .Container .Id )
128+ 	if  ! claimed  {
119129		return  nil 
120130	}
121131
122- 	owners , claimed  :=  req .Owners .HooksOwner (req .Container .Id )
123- 	if  ! claimed  {
132+ 	defaults  :=  v .cfg .Config 
133+ 	rejected  :=  []string {}
134+ 
135+ 	for  _ , p  :=  range  strings .Split (owners , "," ) {
136+ 		if  instance , ok  :=  plugins [p ]; ok  {
137+ 			cfg  :=  v .cfg .GetConfig (instance .GetRole ())
138+ 			if  cfg .DenyOCIHookInjection (defaults ) {
139+ 				rejected  =  append (rejected , p )
140+ 			}
141+ 		}
142+ 	}
143+ 
144+ 	if  len (rejected ) ==  0  {
124145		return  nil 
125146	}
126147
127148	offender  :=  "" 
128149
129- 	if  ! strings . Contains ( owners ,  "," )  {
130- 		offender  =  fmt .Sprintf ("plugin %q" , owners )
150+ 	if  len ( rejected )  ==   1  {
151+ 		offender  =  fmt .Sprintf ("plugin %q" , rejected [ 0 ] )
131152	} else  {
132- 		offender  =  fmt .Sprintf ("plugins %q" , owners )
153+ 		offender  =  fmt .Sprintf ("plugins %q" , strings . Join ( rejected ,  "," ) )
133154	}
134155
135156	return  fmt .Errorf ("%w: %s attempted restricted OCI hook injection" , ErrValidation , offender )
136157}
137158
138- func  (v  * DefaultValidator ) validateSeccompPolicy (req  * api.ValidateContainerAdjustmentRequest ) error  {
159+ func  (v  * DefaultValidator ) validateSeccompPolicy (req  * api.ValidateContainerAdjustmentRequest ,  plugins   map [ string ] * api. PluginInstance ) error  {
139160	if  req .Adjust  ==  nil  {
140161		return  nil 
141162	}
@@ -145,22 +166,31 @@ func (v *DefaultValidator) validateSeccompPolicy(req *api.ValidateContainerAdjus
145166		return  nil 
146167	}
147168
169+ 	var  (
170+ 		cfg       * Config 
171+ 		defaults  =  v .cfg .Config 
172+ 	)
173+ 
174+ 	if  instance , ok  :=  plugins [owner ]; ok  {
175+ 		cfg  =  v .cfg .GetConfig (instance .GetRole ())
176+ 	}
177+ 
148178	profile  :=  req .Container .GetLinux ().GetSeccompProfile ()
149179	switch  {
150180	case  profile  ==  nil  ||  profile .GetProfileType () ==  api .SecurityProfile_UNCONFINED :
151- 		if  v . cfg .RejectUnconfinedSeccompAdjustment  {
181+ 		if  cfg .DenyUnconfinedSeccompAdjustment ( defaults )  {
152182			return  fmt .Errorf ("%w: plugin %s attempted restricted " + 
153183				" unconfined seccomp policy adjustment" , ErrValidation , owner )
154184		}
155185
156186	case  profile .GetProfileType () ==  api .SecurityProfile_RUNTIME_DEFAULT :
157- 		if  v . cfg .RejectRuntimeDefaultSeccompAdjustment  {
187+ 		if  cfg .DenyRuntimeDefaultSeccompAdjustment ( defaults )  {
158188			return  fmt .Errorf ("%w: plugin %s attempted restricted " + 
159189				"runtime default seccomp policy adjustment" , ErrValidation , owner )
160190		}
161191
162192	case  profile .GetProfileType () ==  api .SecurityProfile_LOCALHOST :
163- 		if  v . cfg .RejectCustomSeccompAdjustment  {
193+ 		if  cfg .DenyCustomSeccompAdjustment ( defaults )  {
164194			return  fmt .Errorf ("%w: plugin %s attempted restricted " + 
165195				" custom seccomp policy adjustment" , ErrValidation , owner )
166196		}
@@ -169,7 +199,7 @@ func (v *DefaultValidator) validateSeccompPolicy(req *api.ValidateContainerAdjus
169199	return  nil 
170200}
171201
172- func  (v  * DefaultValidator ) validateRequiredPlugins (req  * api.ValidateContainerAdjustmentRequest ) error  {
202+ func  (v  * DefaultValidator ) validateRequiredPlugins (req  * api.ValidateContainerAdjustmentRequest ,  plugins   map [ string ] * api. PluginInstance ) error  {
173203	var  (
174204		container  =  req .GetContainer ().GetName ()
175205		required   =  slices .Clone (v .cfg .RequiredPlugins )
@@ -200,7 +230,6 @@ func (v *DefaultValidator) validateRequiredPlugins(req *api.ValidateContainerAdj
200230		return  nil 
201231	}
202232
203- 	plugins  :=  req .GetPluginMap ()
204233	missing  :=  []string {}
205234
206235	for  _ , r  :=  range  required  {
@@ -223,3 +252,56 @@ func (v *DefaultValidator) validateRequiredPlugins(req *api.ValidateContainerAdj
223252
224253	return  fmt .Errorf ("%w: %s not present" , ErrValidation , offender )
225254}
255+ 
256+ // GetConfig returns overrides for the named role if it exists in the 
257+ // configuration. 
258+ func  (cfg  * DefaultConfig ) GetConfig (role  string ) * Config  {
259+ 	if  cfg  ==  nil  ||  cfg .Overrides  ==  nil  {
260+ 		return  nil 
261+ 	}
262+ 	return  cfg .Overrides [role ]
263+ }
264+ 
265+ // DenyOCIHookInjection checks whether OCI hook injection should be denied 
266+ // based on the configuration, using an optional fallbak configuration if 
267+ // this one is nil or omits configuration. 
268+ func  (cfg  * Config ) DenyOCIHookInjection (fallback  * Config ) bool  {
269+ 	if  cfg  !=  nil  &&  cfg .RejectOCIHookAdjustment  !=  nil  {
270+ 		return  * cfg .RejectOCIHookAdjustment 
271+ 	}
272+ 
273+ 	return  fallback  !=  nil  &&  fallback .DenyOCIHookInjection (nil )
274+ }
275+ 
276+ // DenyUnconfinedSeccompAdjustment checks whether adjustment of an unconfined 
277+ // seccomp policy should be denied based on the configuration, using an optional 
278+ // fallback configuration if this one is nil or omits configuration. 
279+ func  (cfg  * Config ) DenyUnconfinedSeccompAdjustment (fallback  * Config ) bool  {
280+ 	if  cfg  !=  nil  &&  cfg .RejectUnconfinedSeccompAdjustment  !=  nil  {
281+ 		return  * cfg .RejectUnconfinedSeccompAdjustment 
282+ 	}
283+ 
284+ 	return  fallback  !=  nil  &&  fallback .DenyUnconfinedSeccompAdjustment (nil )
285+ }
286+ 
287+ // DenyRuntimeDefaultSeccompAdjustment checks whether adjustment of a runtime 
288+ // default seccomp policy should be denied based on the configuration, using an 
289+ // optional fallback configuration if this one is nil or omits configuration. 
290+ func  (cfg  * Config ) DenyRuntimeDefaultSeccompAdjustment (fallback  * Config ) bool  {
291+ 	if  cfg  !=  nil  &&  cfg .RejectRuntimeDefaultSeccompAdjustment  !=  nil  {
292+ 		return  * cfg .RejectRuntimeDefaultSeccompAdjustment 
293+ 	}
294+ 
295+ 	return  fallback  !=  nil  &&  fallback .DenyRuntimeDefaultSeccompAdjustment (nil )
296+ }
297+ 
298+ // DenyCustomSeccompAdjustment checks whether adjustment of a custom (localhost) 
299+ // seccomp policy should be denied based on the configuration, using an optional 
300+ // fallback configuration if this one is nil or omits configuration. 
301+ func  (cfg  * Config ) DenyCustomSeccompAdjustment (fallback  * Config ) bool  {
302+ 	if  cfg  !=  nil  &&  cfg .RejectCustomSeccompAdjustment  !=  nil  {
303+ 		return  * cfg .RejectCustomSeccompAdjustment 
304+ 	}
305+ 
306+ 	return  fallback  !=  nil  &&  fallback .DenyCustomSeccompAdjustment (nil )
307+ }
0 commit comments