Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion crates/openshell-driver-docker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2355,7 +2355,6 @@ fn build_container_create_body_with_gpu_devices(
"SYS_ADMIN".to_string(),
"NET_ADMIN".to_string(),
"SYS_PTRACE".to_string(),
"SYSLOG".to_string(),
]),
// The sandbox supervisor needs to bind-mount `/run/netns`,
// mark it shared, and create per-process network namespaces.
Expand Down
18 changes: 12 additions & 6 deletions crates/openshell-driver-kubernetes/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2534,7 +2534,10 @@ fn sandbox_template_to_k8s_with_validated_config(

container.insert("env".to_string(), serde_json::Value::Array(env));

let mut capabilities: Vec<&str> = vec!["SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE", "SYSLOG"];
// Bypass-detection log entries arrive over an NFLOG socket (covered by
// NET_ADMIN), so CAP_SYSLOG is not needed. With user namespaces every
// remaining capability is scoped to the pod's user namespace.
let mut capabilities: Vec<&str> = vec!["SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE"];
if use_user_namespaces {
// In a user namespace the bounding set is reset. SETUID/SETGID are
// needed for the supervisor to drop privileges to the sandbox user.
Expand Down Expand Up @@ -3874,7 +3877,7 @@ mod tests {
"image": "custom-image:latest",
"securityContext": {
"capabilities": {
"add": ["SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE", "SYSLOG"]
"add": ["SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE"]
}
}
}]
Expand Down Expand Up @@ -5179,8 +5182,12 @@ mod tests {
let caps = pod_template["spec"]["containers"][0]["securityContext"]["capabilities"]["add"]
.as_array()
.unwrap();
assert_eq!(caps.len(), 4);
assert_eq!(caps.len(), 3);
assert!(!caps.contains(&serde_json::json!("SETUID")));
assert!(
!caps.contains(&serde_json::json!("SYSLOG")),
"CAP_SYSLOG must not be requested; bypass detection uses NFLOG"
);
}

#[test]
Expand All @@ -5202,11 +5209,10 @@ mod tests {
assert!(caps.contains(&serde_json::json!("SYS_ADMIN")));
assert!(caps.contains(&serde_json::json!("NET_ADMIN")));
assert!(caps.contains(&serde_json::json!("SYS_PTRACE")));
assert!(caps.contains(&serde_json::json!("SYSLOG")));
assert!(caps.contains(&serde_json::json!("SETUID")));
assert!(caps.contains(&serde_json::json!("SETGID")));
assert!(caps.contains(&serde_json::json!("DAC_READ_SEARCH")));
assert_eq!(caps.len(), 7);
assert_eq!(caps.len(), 6);
}

#[test]
Expand Down Expand Up @@ -5280,7 +5286,7 @@ mod tests {
.unwrap();
assert_eq!(
caps.len(),
4,
3,
"extra capabilities must not be added when user namespaces are disabled"
);
}
Expand Down
5 changes: 2 additions & 3 deletions crates/openshell-driver-podman/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The container spec in `container.rs` sets these security-critical fields:
|---|---|---|
| `user` | `0:0` | The supervisor needs root inside the container for namespace creation, proxy setup, Landlock, seccomp, and filesystem preparation. |
| `cap_drop` | Selected unneeded defaults | Podman's default capability set is already restricted. The driver drops capabilities the supervisor does not need. |
| `cap_add` | `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYSLOG`, `DAC_READ_SEARCH`, `SETPCAP` | Grants supervisor-only capabilities required for namespace setup, process identity, bypass diagnostics, and child bounding-set cleanup. |
| `cap_add` | `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `DAC_READ_SEARCH`, `SETPCAP` | Grants supervisor-only capabilities required for namespace setup, process identity, bypass diagnostics, and child bounding-set cleanup. |
| `no_new_privileges` | `true` | Prevents privilege escalation after exec. |
| `seccomp_profile_path` | `unconfined` | The supervisor installs its own policy-aware BPF filter. A container-level profile can block Landlock/seccomp syscalls during setup. |
| `mounts` | Private tmpfs at `/run/netns` | Lets the supervisor create named network namespaces in rootless Podman. |
Expand Down Expand Up @@ -96,9 +96,8 @@ openshell sandbox create \
| Capability | Purpose |
|---|---|
| `SYS_ADMIN` | seccomp filter installation, namespace creation, and Landlock setup. |
| `NET_ADMIN` | Network namespace veth setup, IP address assignment, routes, and nftables. |
| `NET_ADMIN` | Network namespace veth setup, IP address assignment, routes, nftables, and the NFLOG socket that receives bypass-detection log entries. |
| `SYS_PTRACE` | Reading `/proc/<pid>/exe` and walking process ancestry for binary identity. |
| `SYSLOG` | Reading `/dev/kmsg` for bypass-detection diagnostics. |
| `DAC_READ_SEARCH` | Reading `/proc/<pid>/fd/` across UIDs so the proxy can resolve the binary responsible for a connection. |
| `SETPCAP` | Clearing the restricted child process capability bounding set before exec. |

Expand Down
11 changes: 7 additions & 4 deletions crates/openshell-driver-podman/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,12 +932,12 @@ pub fn build_container_spec_with_token_and_gpu_devices(
cap_add: vec![
// seccomp filter installation, namespace creation, Landlock setup.
"SYS_ADMIN".into(),
// Network namespace veth setup, IP/route configuration.
// Network namespace veth setup, IP/route configuration. Also
// covers the NFLOG socket that delivers bypass-detection log
// entries, so CAP_SYSLOG is not needed.
"NET_ADMIN".into(),
// Reading /proc/<pid>/exe and ancestor walk for process identity in policy.
"SYS_PTRACE".into(),
// Reading /dev/kmsg for bypass-detection diagnostics.
"SYSLOG".into(),
// Reading /proc/<pid>/fd/ across UIDs for process identity resolution.
// In rootless Podman the supervisor runs as UID 0 inside a user namespace
// while sandbox processes run as the sandbox user. The kernel's
Expand Down Expand Up @@ -1469,7 +1469,10 @@ mod tests {
assert!(added.contains(&"SYS_ADMIN"), "missing SYS_ADMIN");
assert!(added.contains(&"NET_ADMIN"), "missing NET_ADMIN");
assert!(added.contains(&"SYS_PTRACE"), "missing SYS_PTRACE");
assert!(added.contains(&"SYSLOG"), "missing SYSLOG");
assert!(
!added.contains(&"SYSLOG"),
"CAP_SYSLOG must not be requested; bypass detection uses NFLOG"
);
assert!(
added.contains(&"DAC_READ_SEARCH"),
"missing DAC_READ_SEARCH"
Expand Down
Loading
Loading