fix(podman): create managed workspace volumes owned by the workload identity - #3981
matthewgrossman wants to merge 4 commits into
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
e10d66f to
71f24e5
Compare
71f24e5 to
5920b8d
Compare
|
Label |
|
/ok to test 5920b8d |
…dentity Podman now creates the managed /sandbox volume with uid/gid options for the resolved workload identity, so the workload starts directly as that identity. This fixes rootful sandboxes whose image USER or policy run_as_user could not write to a root-owned /sandbox, and removes the root-then-drop workspace chown start path. Resource admission accepts the managed workspace volume when its options match the workload container's final identity, or are empty for volumes created by older gateways. The channel volume still requires empty options. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
5920b8d to
53e7b71
Compare
|
/ok to test 53e7b71 |
elezar
left a comment
There was a problem hiding this comment.
No blocking correctness issues found. Three nonblocking suggestions below to clarify the helper's contract and strengthen regression coverage.
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Signed-off-by: Evan Lezar <elezar@nvidia.com>
Signed-off-by: Evan Lezar <elezar@nvidia.com>
elezar
left a comment
There was a problem hiding this comment.
Approved. The ownership fix looks sound, and the independent review found no blocking correctness issues.
@matthewgrossman, please feel free to push back on any of the test or readability changes we added. They are nonblocking suggestions, and I am happy to adjust or drop them if you prefer a different approach.
Summary
Fix Podman sandboxes that cannot start when their image or policy selects a non-root user. Podman now creates the managed
/sandboxvolume for that user, so the workload can start and write there without first running as root.This is the second of four stacked PRs split out of #3801: #3979 (remove unreachable sandbox code) ← this PR ← #3982 (Podman OCI
WORKDIR) ← #3931 (shared OCI image tests). Review after #3979.What breaks today, and why this fix
For example, build an image with
USER 2345:2346and no/sandbox, or use a USER-less image with policyrun_as_user: "2345"andrun_as_group: "2346". On a rootful Podman gateway, OpenShell gives the workload a managed/sandboxvolume, but Podman creates its root asroot:rootwith mode0700. User 2345 cannot enter it, so sandbox provisioning fails before the agent command can run (locally,ContainerExited ... code 1; the entrypoint can reportPermission denied). The user cannot fix this from inside the sandbox because the process has no authority to change the directory's ownership.Docker already prepares its managed
/sandboxdirectory owned by the workload UID/GID before starting the capability-free process: it stages a directory in the container archive with those ownership and permission settings. Podman uses a named volume instead of that Docker archive directory. We could start Podman's workload as root, adjust/sandboxownership/permissions, then drop to the requested user—as the old root-then-drop path did for some launches—but that adds a privileged setup step to every affected start. Instead, this PR passes the final UID/GID directly to Podman when creating the volume. Podman makes the volume root owned by that user, and the workload starts as that user from the outset with no added capabilities. The channel volume remains unchanged.Why the startup code no longer needs
rootlessThis does not remove Podman's rootful/rootless distinction. Rootless describes how the Podman service runs on the host; it does not mean the workload must run as container root or as a particular non-root user. Host privileges, UID/GID mappings, networking, and storage still differ between the two modes, and both still need testing.
Previously, the startup code used
rootlessto decide whether to start as container root, fix/sandboxownership, and then drop to the workload user. Creating the volume with the correct ownership beforehand removes the need for that startup workaround: both modes can start directly as the selected workload user. We remove only the now-unused stored driver field and builder argument in this context; Podman's rootless status is still read and logged, and existing checks and user-namespace configuration remain.Related Issue
Replaces #3932, which GitHub automatically marked merged during stack reordering.
Fixes #3937. This bug was found while working on #3801 / #2526: the shared
oci-imagesuite'sdefault_workdir_uses_managed_workspacescenario exposed it on rootful Podman. Docker already gives the image user a writable/sandbox.Changes
client.rs:create_owned_volume(..., owner: Option<(u32, u32)>)sendsOptions: {"o": "uid=…,gid=…"}and verifies the created or existing volume against a sharedvolume_options_match_ownerpredicate. Podman records the parsedUID/GIDnext too. AddContainerConfig.userfor admission.driver.rs: create the workspace volume owned by(identity.uid, identity.gid)and the channel volume with no options. Resource admission accepts a workspace volume whose options match the container's numericConfig.User, or have no options (created by older gateways). The channel volume still requires empty options. Remove the now-unusedrootlessdriver field.container.rs: remove thelaunch-capability-freeroot-then-drop branch andIsolationSpecInput.rootless. The workload always runs--bootstrapas the final identity withcap_drop: ALLand no added capabilities.launch-capability-freestays inopenshell-sandboxbecause the VM driver still uses it.e2e/rust/tests/podman_oci_identity.rs: the workload container user is now{OCI_UID}:{OCI_GID}instead of0:0.Testing
All checks ran against a local rootful Podman machine (macOS, libkrun).
mise run pre-commitpassescargo test -p openshell-driver-podman --lib(228 passed), with newcreate_owned_volume_verifies_requested_ownerandadmission_accepts_workspace_volume_owned_by_workload_identity, and updated isolation-spec tests.cargo clippy -p openshell-driver-podman --all-targets -- -D warningsis clean.podman_oci_identitypasses.e2e/with-podman-gateway.sh. Each case runsid; stat /sandbox; touch /sandbox/probe:ubuntu:24.04with policyrun_as_user: "2345",run_as_group: "2346": onmain, provisioning fails withContainerExited ... code 1. With this PR it runs as2345:2346,/sandboxis2345:2346 700, and the write succeeds.USER 2345:2346and no/sandbox: same results onmainand with this PR.resource_admission.enabled = truetemporarily set ine2e/support/podman-gateway-config.sh(not committed),oci-image'sdefault_workdir_uses_managed_workspacepasses. With the owner-match branch of the admission check disabled, it fails withsandbox lacks attachment provenance.Checklist