diff --git a/pkg/server/container_create.go b/pkg/server/container_create.go index 447a91cd7..a56127580 100644 --- a/pkg/server/container_create.go +++ b/pkg/server/container_create.go @@ -227,11 +227,16 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta userstr, err := generateUserString( securityContext.GetRunAsUsername(), securityContext.GetRunAsUser(), - securityContext.GetRunAsGroup(), - ) + securityContext.GetRunAsGroup()) + if err != nil { return nil, errors.Wrap(err, "failed to generate user string") } + if userstr == "" { + // Lastly, since no user override was passed via CRI try to set via OCI + // Image + userstr = image.ImageSpec.Config.User + } if userstr != "" { specOpts = append(specOpts, oci.WithUser(userstr)) } @@ -589,7 +594,20 @@ func generateApparmorSpecOpts(apparmorProf string, privileged, apparmorEnabled b } } -// generateUserString generates valid user string based on OCI Image Spec v1.0.0. +// generateUserString generates valid user string based on OCI Image Spec +// v1.0.0. +// +// CRI defines that the following combinations are valid: +// +// (none) -> "" +// username -> username +// username, uid -> username +// username, uid, gid -> username:gid +// username, gid -> username:gid +// uid -> uid +// uid, gid -> uid:gid +// gid -> error +// // TODO(random-liu): Add group name support in CRI. func generateUserString(username string, uid, gid *runtime.Int64Value) (string, error) { var userstr, groupstr string diff --git a/pkg/server/container_create_test.go b/pkg/server/container_create_test.go index a8c17e1e6..c3c978e4a 100644 --- a/pkg/server/container_create_test.go +++ b/pkg/server/container_create_test.go @@ -1230,3 +1230,74 @@ func TestDisableCgroup(t *testing.T) { t.Log("cgroup path should be empty") assert.Empty(t, spec.Linux.CgroupsPath) } + +func TestGenerateUserString(t *testing.T) { + type testcase struct { + // the name of the test case + name string + + u string + uid, gid *runtime.Int64Value + + result string + expectedError bool + } + testcases := []testcase{ + { + name: "Empty", + result: "", + }, + { + name: "Username Only", + u: "testuser", + result: "testuser", + }, + { + name: "Username, UID", + u: "testuser", + uid: &runtime.Int64Value{Value: 1}, + result: "testuser", + }, + { + name: "Username, UID, GID", + u: "testuser", + uid: &runtime.Int64Value{Value: 1}, + gid: &runtime.Int64Value{Value: 10}, + result: "testuser:10", + }, + { + name: "Username, GID", + u: "testuser", + gid: &runtime.Int64Value{Value: 10}, + result: "testuser:10", + }, + { + name: "UID only", + uid: &runtime.Int64Value{Value: 1}, + result: "1", + }, + { + name: "UID, GID", + uid: &runtime.Int64Value{Value: 1}, + gid: &runtime.Int64Value{Value: 10}, + result: "1:10", + }, + { + name: "GID only", + gid: &runtime.Int64Value{Value: 10}, + result: "", + expectedError: true, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + r, err := generateUserString(tc.u, tc.uid, tc.gid) + if tc.expectedError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tc.result, r) + }) + } +} diff --git a/pkg/server/sandbox_run.go b/pkg/server/sandbox_run.go index 74e1f4f33..e8f7e9d31 100644 --- a/pkg/server/sandbox_run.go +++ b/pkg/server/sandbox_run.go @@ -169,6 +169,11 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox if err != nil { return nil, errors.Wrap(err, "failed to generate user string") } + if userstr == "" { + // Lastly, since no user override was passed via CRI try to set via OCI + // Image + userstr = image.ImageSpec.Config.User + } if userstr != "" { specOpts = append(specOpts, oci.WithUser(userstr)) }