-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[CRI] fix additionalGids: it should fallback to imageConfig.User when securityContext.RunAsUser,RunAsUsername are empty #8136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CRI] fix additionalGids: it should fallback to imageConfig.User when securityContext.RunAsUser,RunAsUsername are empty #8136
Conversation
|
Hi @everpeace. Thanks for your PR. I'm waiting for a containerd member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
8aa35ad to
470b6ba
Compare
|
I set it back to draft because lint fails. I will fix it later. |
a74a123 to
375f750
Compare
It should fallback to imageConfig.User when no securityContext.RunAsUser/RunAsUsername Signed-off-by: Shingo Omura <[email protected]>
375f750 to
727b254
Compare
|
All tests are passed. This PR is ready to review now. |
|
@mikebrow Hi, would you mind reviewing this PR?? Thanks. |
|
/ok-to-test |
mikebrow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.. nicely done!
| userstr = imageConfig.User | ||
| } | ||
| if userstr != "" { | ||
| specOpts = append(specOpts, oci.WithUser(userstr)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering why we're first going through the process above to convert username and group to a single string (user:group if both are present), only to then to parse everything again in oci.WithUser() to split user and group again and see if they're numeric values (should the "happy path" use WithUIDGID() or variants thereof?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why we did it like this. However, It looks the commit introduced it. It should be refactored in another PR. cri-o's corresponding code is more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree it makes sense to refactor in a follow up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Admitted, I haven't dug fully into all of the logic, but it looks like it's because there's a combination of a "strong typed" (securityContext) and fallback to the "weakly typed" (string) from the imageConfig.User.
While trying to read the code, I found the logic to be complex / hard to read, which scared me a bit, as such cases can easily lead to bugs; too many conditions in a row make it hard to spot corner-cases, as well as the conversion from strong-typed to weak typed (followed by "trying to discover" if a uid or username was passed, or other combinations).
So, yes, perhaps out of scope for this PR (TBD?) but it would be good to clean this code up to make it more maintainable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nod.. I had to read it a few times take notes check test cases
Signed-off-by: Shingo Omura <[email protected]>
570ac18 to
50740a1
Compare
mikebrow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
additional commit LGTM
|
@mikebrow What are the remaining tasks for merging this PR? I believe all the comments are addressed and it is ready to merge now. |
|
@mikebrow would you mind merging this PR if you don't see any concerns?? |
fuweid
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
The comments could be addressed in the followup.
| additional-group-for-alice:x:11111:alice | ||
| additional-group-for-root:x:22222:root | ||
| ` | ||
| tempRootDir, err := os.MkdirTemp("", "TestContainerUser-") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use t.TempDir() here and testing framework will cleanup it.
| expected: runtimespec.User{UID: 0, GID: 0, AdditionalGids: []uint32{0, 22222}}, | ||
| }, | ||
| } { | ||
| t.Run(desc, func(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add desc := desc before t.Run to capture range variable just in case that it run in parallel mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always get confused over when a local copy is needed inside a for range block, some examples show it's not needed if param of the func but here it's a t.Run vs a go Run so.. confusion :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops! It should be test := test... my mistake...
t.Run can go in parallel mode so it is like go func(). We need to capture it before spawning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, it makes sense. I will open a fix soon 🙇
What is the issue
I found a bug in setting
runtime.Spec.Process.User.additionalGidsin CRI server/sbserver.If
LinuxContainerSecurityContext.{RunAsUser,RunAsUsername}are empty, contained should fallback to the container image'sConfig.Userfor resolving the primary user and use it to inspect /etc/group in the container image for resolvingadditionalGids. But containerd always fallback to0.Fortunately, in the use of Kubernetes+containerd, the bug does NOT happen because kubelet always fills out
LinuxContainerSecurityContext.RunAsUserfrom the image status (code) when image'sConfig.Useris not empty. So ontainer_create_linux.go#L369-L370 can grab the correct user from the SecurityContext.However, because the cri-api spec does not assume the behavior, which fills out
LinuxContainerSecurityContext.RunAsUserfrom the image'sConfig.User, I think the code should be fixed.CRI-O seems to handle this correctly. See here.
Reproduction
Version
Image and Container Spec
The image
everpeace/test:containerd-image-configis used.The output
Notes for reviewers
The current containerd's CRI implementation doesn't follow the conversion spec config.User to spec.Process.User. The containerd's CRI impl
config.Userin the image, andRunAsGroupin SecurityContextThe issue will be handled in kubernetes/enhancements#3619 separately to avoid breaking changes to the users.