@@ -241,10 +241,13 @@ pub struct KubernetesComputeConfig {
241241 deserialize_with = "deserialize_provider_spiffe_workload_api_socket_path"
242242 ) ]
243243 pub provider_spiffe_workload_api_socket_path : String ,
244- /// UID used for the supervisor container `securityContext.runAsUser` and
245- /// PVC init container ownership operations. When empty, the driver
246- /// auto-detects from OpenShift SCC annotations on the target namespace;
247- /// if those are also absent, falls back to `1000`.
244+ /// UID used for privilege-drop operations and workspace init container
245+ /// ownership. The supervisor container always runs as UID 0 (root) to
246+ /// create network namespaces and configure Landlock/seccomp; the
247+ /// `sandbox_uid` is injected as the `SANDBOX_UID` environment variable so
248+ /// the supervisor knows which UID to drop to for child processes.
249+ /// When empty, the driver auto-detects from `OpenShift` SCC annotations on
250+ /// the target namespace; if those are also absent, falls back to `1000`.
248251 #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
249252 pub sandbox_uid : Option < u32 > ,
250253 /// GID used alongside `sandbox_uid` for PVC init container operations.
@@ -261,15 +264,15 @@ pub const MIN_SA_TOKEN_TTL_SECS: i64 = 600;
261264/// pod start).
262265pub const MAX_SA_TOKEN_TTL_SECS : i64 = 86_400 ;
263266
264- /// Default sandbox UID used when neither config nor OpenShift SCC annotations
267+ /// Default sandbox UID used when neither config nor ` OpenShift` SCC annotations
265268/// provide a resolved value.
266269pub ( crate ) const DEFAULT_SANDBOX_UID : u32 = 1000 ;
267270
268- /// The annotation key for the OpenShift ServiceAccount UID range.
271+ /// The annotation key for the ` OpenShift` ` ServiceAccount` UID range.
269272/// Format: `<start>/<size>` (e.g. `1000000000/10000`).
270273pub const ANNOTATION_SCC_UID_RANGE : & str = "openshift.io/sa.scc.uid-range" ;
271274
272- /// The annotation key for the OpenShift ServiceAccount supplemental groups.
275+ /// The annotation key for the ` OpenShift` ` ServiceAccount` supplemental groups.
273276/// Format: `<start>/<size>` (e.g. `1000000000/10000`).
274277pub const ANNOTATION_SCC_SUPPLEMENTAL_GROUPS : & str = "openshift.io/sa.scc.supplemental-groups" ;
275278
@@ -337,7 +340,7 @@ impl KubernetesComputeConfig {
337340 ///
338341 /// Resolution order:
339342 /// 1. Configured `sandbox_uid` / `sandbox_gid` (explicit override)
340- /// 2. OpenShift SCC namespace annotations (`sa.scc.uid-range`,
343+ /// 2. ` OpenShift` SCC namespace annotations (`sa.scc.uid-range`,
341344 /// `sa.scc.supplemental-groups`) — passed in as the optional
342345 /// `namespace_annotations` map
343346 /// 3. Fallback defaults: UID=`1000`, GID=UID
@@ -348,13 +351,11 @@ impl KubernetesComputeConfig {
348351 if let Some ( uid) = self . sandbox_uid {
349352 return uid;
350353 }
351- // Try OpenShift SCC annotation.
352- if let Some ( anns) = namespace_annotations {
353- if let Some ( range) = anns. get ( ANNOTATION_SCC_UID_RANGE ) {
354- if let Some ( uid) = Self :: from_open_shift_uid_range ( range) {
355- return uid;
356- }
357- }
354+ if let Some ( anns) = namespace_annotations
355+ && let Some ( range) = anns. get ( ANNOTATION_SCC_UID_RANGE )
356+ && let Some ( uid) = Self :: from_open_shift_uid_range ( range)
357+ {
358+ return uid;
358359 }
359360 DEFAULT_SANDBOX_UID
360361 }
@@ -365,30 +366,52 @@ impl KubernetesComputeConfig {
365366 _namespace_annotations : Option < & std:: collections:: BTreeMap < String , String > > ,
366367 ) -> u32 {
367368 self . sandbox_gid
368- . or_else ( || self . sandbox_uid )
369+ . or ( self . sandbox_uid )
369370 . unwrap_or ( resolved_uid)
370371 }
371372
372- /// Parse OpenShift SCC `sa.scc.uid-range` annotation.
373+ /// Parse ` OpenShift` SCC `sa.scc.uid-range` annotation.
373374 ///
374375 /// Format: `<start>/<size>` (e.g. `1000000000/10000`).
375376 pub fn from_open_shift_uid_range ( annotation : & str ) -> Option < u32 > {
376377 let ( start, _) = annotation. split_once ( '/' ) ?;
377- start
378- . trim ( )
379- . parse :: < u32 > ( )
380- . ok ( )
381- . filter ( |& uid| uid >= openshell_policy:: MIN_SANDBOX_UID )
378+ start. trim ( ) . parse :: < u32 > ( ) . ok ( ) . filter ( |& uid| {
379+ ( openshell_policy:: MIN_SANDBOX_UID ..=openshell_policy:: MAX_SANDBOX_UID ) . contains ( & uid)
380+ } )
382381 }
383382
384- /// Parse OpenShift SCC `sa.scc.supplemental-groups` annotation.
383+ /// Parse ` OpenShift` SCC `sa.scc.supplemental-groups` annotation.
385384 pub fn from_open_shift_supplemental_groups ( annotation : & str ) -> Option < u32 > {
386385 let ( start, _) = annotation. split_once ( '/' ) ?;
387- start
388- . trim ( )
389- . parse :: < u32 > ( )
390- . ok ( )
391- . filter ( |& gid| gid >= openshell_policy:: MIN_SANDBOX_UID )
386+ start. trim ( ) . parse :: < u32 > ( ) . ok ( ) . filter ( |& gid| {
387+ ( openshell_policy:: MIN_SANDBOX_UID ..=openshell_policy:: MAX_SANDBOX_UID ) . contains ( & gid)
388+ } )
389+ }
390+
391+ /// Validate that configured `sandbox_uid` and `sandbox_gid` fall within
392+ /// the policy-enforced UID/GID range. Called during driver initialization
393+ /// before any pod parameters are rendered.
394+ pub fn validate_sandbox_identity_config ( & self ) -> Result < ( ) , String > {
395+ let range = openshell_policy:: MIN_SANDBOX_UID ..=openshell_policy:: MAX_SANDBOX_UID ;
396+ if let Some ( uid) = self . sandbox_uid
397+ && !range. contains ( & uid)
398+ {
399+ return Err ( format ! (
400+ "sandbox_uid {uid} is outside the allowed range [{}, {}]" ,
401+ openshell_policy:: MIN_SANDBOX_UID ,
402+ openshell_policy:: MAX_SANDBOX_UID ,
403+ ) ) ;
404+ }
405+ if let Some ( gid) = self . sandbox_gid
406+ && !range. contains ( & gid)
407+ {
408+ return Err ( format ! (
409+ "sandbox_gid {gid} is outside the allowed range [{}, {}]" ,
410+ openshell_policy:: MIN_SANDBOX_UID ,
411+ openshell_policy:: MAX_SANDBOX_UID ,
412+ ) ) ;
413+ }
414+ Ok ( ( ) )
392415 }
393416}
394417
@@ -628,7 +651,7 @@ mod tests {
628651 fn parse_openshift_uid_range ( ) {
629652 assert_eq ! (
630653 KubernetesComputeConfig :: from_open_shift_uid_range( "1000000000/10000" ) ,
631- Some ( 1000000000 )
654+ Some ( 1_000_000_000 )
632655 ) ;
633656 assert_eq ! (
634657 KubernetesComputeConfig :: from_open_shift_uid_range( "1000/50000" ) ,
@@ -645,6 +668,51 @@ mod tests {
645668 ) ;
646669 }
647670
671+ #[ test]
672+ fn parse_openshift_uid_range_rejects_above_max ( ) {
673+ // u32::MAX is well above MAX_SANDBOX_UID — should be rejected.
674+ assert_eq ! (
675+ KubernetesComputeConfig :: from_open_shift_uid_range( "4294967295/10000" ) ,
676+ None
677+ ) ;
678+ }
679+
680+ #[ test]
681+ fn validate_sandbox_identity_config_accepts_valid_range ( ) {
682+ let cfg = KubernetesComputeConfig {
683+ sandbox_uid : Some ( 1000 ) ,
684+ sandbox_gid : Some ( 1000 ) ,
685+ ..KubernetesComputeConfig :: default ( )
686+ } ;
687+ assert ! ( cfg. validate_sandbox_identity_config( ) . is_ok( ) ) ;
688+ }
689+
690+ #[ test]
691+ fn validate_sandbox_identity_config_rejects_uid_zero ( ) {
692+ let cfg = KubernetesComputeConfig {
693+ sandbox_uid : Some ( 0 ) ,
694+ ..KubernetesComputeConfig :: default ( )
695+ } ;
696+ let err = cfg. validate_sandbox_identity_config ( ) . unwrap_err ( ) ;
697+ assert ! ( err. contains( "sandbox_uid" ) ) ;
698+ }
699+
700+ #[ test]
701+ fn validate_sandbox_identity_config_rejects_gid_above_max ( ) {
702+ let cfg = KubernetesComputeConfig {
703+ sandbox_gid : Some ( openshell_policy:: MAX_SANDBOX_UID + 1 ) ,
704+ ..KubernetesComputeConfig :: default ( )
705+ } ;
706+ let err = cfg. validate_sandbox_identity_config ( ) . unwrap_err ( ) ;
707+ assert ! ( err. contains( "sandbox_gid" ) ) ;
708+ }
709+
710+ #[ test]
711+ fn validate_sandbox_identity_config_accepts_none_fields ( ) {
712+ let cfg = KubernetesComputeConfig :: default ( ) ;
713+ assert ! ( cfg. validate_sandbox_identity_config( ) . is_ok( ) ) ;
714+ }
715+
648716 #[ test]
649717 fn parse_openshift_supplemental_groups ( ) {
650718 assert_eq ! (
@@ -676,7 +744,7 @@ mod tests {
676744 ANNOTATION_SCC_UID_RANGE . to_string ( ) ,
677745 "1000000000/10000" . to_string ( ) ,
678746 ) ;
679- assert_eq ! ( cfg. resolve_sandbox_uid( Some ( & anns) ) , 1000000000 ) ;
747+ assert_eq ! ( cfg. resolve_sandbox_uid( Some ( & anns) ) , 1_000_000_000 ) ;
680748 }
681749
682750 #[ test]
0 commit comments