diff --git a/pkg/containerd/opts/spec_windows.go b/pkg/containerd/opts/spec_windows.go index 80b874b08..b0850b8c7 100644 --- a/pkg/containerd/opts/spec_windows.go +++ b/pkg/containerd/opts/spec_windows.go @@ -188,3 +188,15 @@ func WithWindowsDefaultSandboxShares(ctx context.Context, client oci.Client, c * s.Windows.Resources.CPU.Shares = &i return nil } + +// WithWindowsCredentialSpec assigns `credentialSpec` to the +// `runtime.Spec.Windows.CredentialSpec` field. +func WithWindowsCredentialSpec(credentialSpec string) oci.SpecOpts { + return func(ctx context.Context, client oci.Client, c *containers.Container, s *runtimespec.Spec) error { + if s.Windows == nil { + s.Windows = &runtimespec.Windows{} + } + s.Windows.CredentialSpec = credentialSpec + return nil + } +} diff --git a/pkg/server/container_create_windows.go b/pkg/server/container_create_windows.go index e8c81808d..86a08d89e 100644 --- a/pkg/server/container_create_windows.go +++ b/pkg/server/container_create_windows.go @@ -68,13 +68,30 @@ func (c *criService) containerSpec(id string, sandboxID string, sandboxPid uint3 specOpts = append(specOpts, customopts.WithWindowsMounts(c.os, config, extraMounts)) - specOpts = append(specOpts, customopts.WithWindowsResources(config.GetWindows().GetResources())) - - username := config.GetWindows().GetSecurityContext().GetRunAsUsername() - if username != "" { - specOpts = append(specOpts, oci.WithUser(username)) + // Start with the image config user and override below if RunAsUsername is not "". + username := imageConfig.User + + windowsConfig := config.GetWindows() + if windowsConfig != nil { + specOpts = append(specOpts, customopts.WithWindowsResources(windowsConfig.GetResources())) + securityCtx := windowsConfig.GetSecurityContext() + if securityCtx != nil { + runAsUser := securityCtx.GetRunAsUsername() + if runAsUser != "" { + username = runAsUser + } + cs := securityCtx.GetCredentialSpec() + if cs != "" { + specOpts = append(specOpts, customopts.WithWindowsCredentialSpec(cs)) + } + } } - // TODO(windows): Add CredentialSpec support. + + // There really isn't a good Windows way to verify that the username is available in the + // image as early as here like there is for Linux. Later on in the stack hcsshim + // will handle the behavior of erroring out if the user isn't available in the image + // when trying to run the init process. + specOpts = append(specOpts, oci.WithUser(username)) for pKey, pValue := range getPassthroughAnnotations(sandboxConfig.Annotations, ociRuntime.PodAnnotations) { diff --git a/pkg/server/container_create_windows_test.go b/pkg/server/container_create_windows_test.go index 2b75ebb85..99d339e6b 100644 --- a/pkg/server/container_create_windows_test.go +++ b/pkg/server/container_create_windows_test.go @@ -72,7 +72,8 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox MemoryLimitInBytes: 400, }, SecurityContext: &runtime.WindowsContainerSecurityContext{ - RunAsUsername: "test-user", + RunAsUsername: "test-user", + CredentialSpec: "{\"test\": \"spec\"}", }, }, } @@ -91,6 +92,7 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox Entrypoint: []string{"/entrypoint"}, Cmd: []string{"cmd"}, WorkingDir: "/workspace", + User: "ContainerUser", } specCheck := func(t *testing.T, id string, sandboxID string, sandboxPid uint32, spec *runtimespec.Spec) { assert.Nil(t, spec.Root) @@ -111,9 +113,13 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox assert.EqualValues(t, *spec.Windows.Resources.CPU.Maximum, 300) assert.EqualValues(t, *spec.Windows.Resources.Memory.Limit, 400) + // Also checks if override of the image configs user is behaving. t.Logf("Check username") assert.Contains(t, spec.Process.User.Username, "test-user") + t.Logf("Check credential spec") + assert.Contains(t, spec.Windows.CredentialSpec, "{\"test\": \"spec\"}") + t.Logf("Check PodSandbox annotations") assert.Contains(t, spec.Annotations, annotations.SandboxID) assert.EqualValues(t, spec.Annotations[annotations.SandboxID], sandboxID)