Skip to content

Commit be05115

Browse files
committed
code review changes
1 parent 0aa1927 commit be05115

13 files changed

Lines changed: 710 additions & 87 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/openshell-driver-kubernetes/src/config.rs

Lines changed: 98 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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).
262265
pub 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.
266269
pub(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`).
270273
pub 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`).
274277
pub 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

Comments
 (0)