Repository navigation
Honor a container image's USER and WORKDIR - #1918
Davanum Srinivas (dims) wants to merge 5 commits into
Conversation
7321a72 to
4ab3b53
Compare
4ab3b53 to
58e3ad2
Compare
58e3ad2 to
9ed0a39
Compare
… note the rootfs root dependency of kagent-upstream#125 (agent-substrate#1918)
Maya Wang (mayawang)
left a comment
There was a problem hiding this comment.
The USER and WORKDIR resolution looks right to me, and moving to moby/sys/user covers Ben's gid point. My main ask is a live run before this merges, since it changes who real images run as. It also needs a rebase: internal/ocispec/parity_test.go conflicts with main.
… root dependency of kagent-upstream#125 (#94) docs(fork): the egress default's upstream exit is agent-substrate#1558; note the rootfs root dependency of kagent-upstream#125 (agent-substrate#1918)
9ed0a39 to
0ca0710
Compare
0ca0710 to
d41a2fc
Compare
|
Two gVisor issues from Preston Holmes (@ptone) that every image this change moves to non-root will hit: #2035 (the actor rootfs |
|
I agree that we should fix #2036 and probably need to fix it first. |
d41a2fc to
9ac6eae
Compare
|
Maya Wang (@mayawang) Plan is roughly spreadh between #1906 / #2392 (fixes #2036) and this PR. #2035 is fixed in this PR's first commit (merged root 0755, layerless case included); #2430 fixes the upper only. Whichever lands first, I drop the other. Ran the three together on kind, both classes: USER images start, write their own files and resume after suspend. Details in the live-run thread above. Privileged ports on microVM need #1904. |
…nt-substrate#1906) Durable-dir volumes were created `0700`, so a container running as a non-root user could not write its own volume. Now `0777`, as Kubernetes creates an emptyDir: one actor's containers can run as different users, and the `0700` actor directory above keeps other actors out. A restore keeps the mode the snapshot recorded, as emptyDir keeps a pod's own chmod. Volumes created earlier stay `0700`, fine while every container runs as root. No effect until an image's `USER` is honored (agent-substrate#1918). Cleanup of files a non-root container leaves behind landed in agent-substrate#1910. Tests: `TestPrepareDurableDirVolume`. Exercised on kind with the micro-VM class: uid 65532 writes a durable dir, then suspend and resume. - [x] Tests pass - [x] Appropriate changes to documentation are included in the PR
4d5bcaf to
6361a58
Compare
rootfs and upper were 0700. On gVisor the container's / takes that mode, so a non-root process could not search its own root. 0755 is what containerd and every image root use; the 0700 actor directory above keeps other actors out. The micro-VM guest already sees 0755.
atelet writes the OCI spec before the worker mounts the rootfs, so it cannot read the image's /etc/passwd from a mount. Image.ReadFile reads a file from the cached layers top-down, honoring recorded whiteouts and opaque dirs. Capped at 1 MiB.
Resolve USER as Docker does, against the image's own /etc/passwd and /etc/group: uid:gid as is, a bare uid with its login group (gid 0 without an entry), names looked up or Run/Restore fails, group memberships as supplementary groups. No USER means root. atelet resolves it into the worker's ContainerSpec; the pause container follows the same rule through WorkloadSpec.pause_user. On gVisor every snapshot taken before this needs re-taking, whatever the image: runsc restore checks Process.User, and the pause image sets USER 65535.
Start the process in the image's WORKDIR instead of "/", and create the directory in the actor's upper when the image lacks it. atelet resolves it into the worker's ContainerSpec. runsc restore checks Process.Cwd as well as Process.User, so gVisor snapshots from before this need re-taking.
Substrate makes no compatibility promise before v1.0.0, so a note about one release's snapshots is noise in the upgrade procedure. The API guide describes how the image's USER and WORKDIR apply.
6361a58 to
41969a1
Compare
USERresolves as Docker does, against the image's own/etc/passwdand/etc/group:uid:gidas is, a bare uid with its login group (gid 0 without an entry), names looked up orRun/Restorefails, group memberships as supplementary groups. NoUSERmeans root. atelet resolves it into the worker'sContainerSpec; the pause container follows the same rule throughWorkloadSpec.pause_user. The process starts in the image'sWORKDIR(default/), created in the actor's upper when the image lacks it.Behavior change: images with a
USERstop running as root; images with aWORKDIRstop starting in/. On gVisor no snapshot from before this restores:runsc restorechecksProcess.UserandProcess.Cwdof every container, and the pause image setsUSER 65535. Micro-VM snapshots resume as they were.Merge after #2392 (image layer owners): without it a non-root process cannot write the files its image gives it. On the micro-VM class, images that serve on a privileged port also need #1904.
Live run on kind, both classes, main + #1906 + #2392 + this PR: a node image (USER 1000, WORKDIR /app, durable dir) and the jupyter demo run as their user, write to their workdir and durable dir, and resume on demand after a suspend. On micro-VM uid 1000 cannot bind port 80 (#1904); gVisor allows it.
go test -raceon Linux for atelet, imagecache, ocispec, ateworker-gvisor and kata.