Skip to content

Commit

Permalink
[V2] Set default statefulset image based on securityProfile (#693)
Browse files Browse the repository at this point in the history
### Proposed changes

This update removes the default CRD validation marker from the
`workspace.spec.image` field, allowing for dynamic image selection based
on the value of `workspace.spec.securityProfile`. When `securityProfile`
is set to `baseline`, the image defaults to `pulumi/pulumi:latest`. If
`securityProfile` is marked as `restricted`, the system will instead
select `pulumi/pulumi:latest-nonroot`. If a user specifies their own
image, then that value is used instead. Handling these default settings
within the controller is necessary, as CRD validation markers cannot
accommodate conditional defaults.

Before implementing this feature, additional ginkgo tests were
introduced to confirm that the desired behavior is properly achieved.

### Related issues (optional)

Closes: #653
  • Loading branch information
rquitales authored Sep 26, 2024
1 parent b912fd4 commit 88a213d
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 13 deletions.
11 changes: 9 additions & 2 deletions operator/api/auto/v1alpha1/workspace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const (
SecurityProfileBaseline SecurityProfile = "baseline"
// SecurityProfileRestricted applies the restricted security profile.
SecurityProfileRestricted SecurityProfile = "restricted"

// SecurityProfileBaselineDefaultImage is the default image used when the security profile is 'baseline'.
SecurityProfileBaselineDefaultImage = "pulumi/pulumi:latest"
// SecurityProfileRestrictedDefaultImage is the default image used when the security profile is 'restricted'.
SecurityProfileRestrictedDefaultImage = "pulumi/pulumi:latest-nonroot"
)

// WorkspaceSpec defines the desired state of Workspace
Expand All @@ -47,8 +52,10 @@ type WorkspaceSpec struct {
// +optional
SecurityProfile SecurityProfile `json:"securityProfile,omitempty"`

// Image is the Docker image containing the 'pulumi' executable.
// +kubebuilder:default="pulumi/pulumi:latest"
// Image is the container image containing the 'pulumi' executable. If no image is provided,
// the default image is used based on the securityProfile:
// for 'baseline', it defaults to 'pulumi/pulumi:latest';
// for 'restricted', it defaults to 'pulumi/pulumi:latest-nonroot'.
Image string `json:"image,omitempty"`

// Image pull policy.
Expand Down
7 changes: 5 additions & 2 deletions operator/config/crd/bases/auto.pulumi.com_workspaces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,11 @@ spec:
type: string
type: object
image:
default: pulumi/pulumi:latest
description: Image is the Docker image containing the 'pulumi' executable.
description: |-
Image is the container image containing the 'pulumi' executable. If no image is provided,
the default image is used based on the securityProfile:
for 'baseline', it defaults to 'pulumi/pulumi:latest';
for 'restricted', it defaults to 'pulumi/pulumi:latest-nonroot'.
type: string
imagePullPolicy:
description: |-
Expand Down
16 changes: 10 additions & 6 deletions operator/config/crd/bases/pulumi.com_stacks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1122,9 +1122,11 @@ spec:
type: string
type: object
image:
default: pulumi/pulumi:latest
description: Image is the Docker image containing the 'pulumi'
executable.
description: |-
Image is the container image containing the 'pulumi' executable. If no image is provided,
the default image is used based on the securityProfile:
for 'baseline', it defaults to 'pulumi/pulumi:latest';
for 'restricted', it defaults to 'pulumi/pulumi:latest-nonroot'.
type: string
imagePullPolicy:
description: |-
Expand Down Expand Up @@ -10657,9 +10659,11 @@ spec:
type: string
type: object
image:
default: pulumi/pulumi:latest
description: Image is the Docker image containing the 'pulumi'
executable.
description: |-
Image is the container image containing the 'pulumi' executable. If no image is provided,
the default image is used based on the securityProfile:
for 'baseline', it defaults to 'pulumi/pulumi:latest';
for 'restricted', it defaults to 'pulumi/pulumi:latest-nonroot'.
type: string
imagePullPolicy:
description: |-
Expand Down
22 changes: 21 additions & 1 deletion operator/internal/controller/auto/workspace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ func newStatefulSet(ctx context.Context, w *autov1alpha1.Workspace, source *sour
Containers: []corev1.Container{
{
Name: "pulumi",
Image: w.Spec.Image,
Image: getDefaultSSImage(w.Spec.Image, w.Spec.SecurityProfile),
ImagePullPolicy: w.Spec.ImagePullPolicy,
Resources: w.Spec.Resources,
VolumeMounts: []corev1.VolumeMount{
Expand Down Expand Up @@ -674,3 +674,23 @@ func mergePodTemplateSpec(_ context.Context, base *corev1.PodTemplateSpec, patch

return patchResult, nil
}

// getDefaultSSImage returns the default image for the StatefulSet container based on the security profile.
// If the user had provided an image, then that image is returned instead.
func getDefaultSSImage(image string, securityProfile autov1alpha1.SecurityProfile) string {
if image != "" {
return image
}

switch securityProfile {
case autov1alpha1.SecurityProfileRestricted:
return autov1alpha1.SecurityProfileRestrictedDefaultImage
case autov1alpha1.SecurityProfileBaseline:
return autov1alpha1.SecurityProfileBaselineDefaultImage
default:
// This should not happen, since the securityProfile has a default value.
// If for some reason it is empty, then we should default to the baseline image
// since we can't tell if the container can run in a restricted environment.
return autov1alpha1.SecurityProfileBaselineDefaultImage
}
}
42 changes: 40 additions & 2 deletions operator/internal/controller/auto/workspace_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@ var _ = Describe("Workspace Controller", func() {
})

Describe("spec.image", func() {
It("uses pulumi/pulumi:latest by default", func(ctx context.Context) {
It("uses pulumi/pulumi:latest-nonroot by default", func(ctx context.Context) {
_, err := reconcileF(ctx)
Expect(err).NotTo(HaveOccurred())
container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi")
Expect(container).NotTo(BeNil())
Expect(container.Image).To(Equal("pulumi/pulumi:latest"))
Expect(container.Image).To(Equal("pulumi/pulumi:latest-nonroot"))
})
When("image is set", func() {
BeforeEach(func(ctx context.Context) {
Expand Down Expand Up @@ -254,6 +254,25 @@ var _ = Describe("Workspace Controller", func() {
sc := ss.Spec.Template.Spec.SecurityContext
Expect(sc.RunAsNonRoot).To(BeNil())
})
It("uses the default 'pulumi/pulumi:latest` image", func(ctx context.Context) {
_, err := reconcileF(ctx)
Expect(err).NotTo(HaveOccurred())
container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi")
Expect(container).NotTo(BeNil())
Expect(container.Image).To(Equal("pulumi/pulumi:latest"))
})
When("a custom image is set", func() {
BeforeEach(func(ctx context.Context) {
obj.Spec.Image = "test/pulumi:v3.42.0"
})
It("uses the specified image for the pulumi container", func(ctx context.Context) {
_, err := reconcileF(ctx)
Expect(err).NotTo(HaveOccurred())
container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi")
Expect(container).NotTo(BeNil())
Expect(container.Image).To(Equal("test/pulumi:v3.42.0"))
})
})
})
Describe("Restricted", func() {
BeforeEach(func(ctx context.Context) {
Expand All @@ -269,6 +288,25 @@ var _ = Describe("Workspace Controller", func() {
fetch := findContainer(ss.Spec.Template.Spec.InitContainers, "fetch")
Expect(fetch.SecurityContext.AllowPrivilegeEscalation).To(PointTo(BeFalse()))
})
It("uses the default 'pulumi/pulumi:latest-nonroot` image", func(ctx context.Context) {
_, err := reconcileF(ctx)
Expect(err).NotTo(HaveOccurred())
container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi")
Expect(container).NotTo(BeNil())
Expect(container.Image).To(Equal("pulumi/pulumi:latest-nonroot"))
})
When("a custom image is set", func() {
BeforeEach(func(ctx context.Context) {
obj.Spec.Image = "test/pulumi:v3.42.0"
})
It("uses the specified image for the pulumi container", func(ctx context.Context) {
_, err := reconcileF(ctx)
Expect(err).NotTo(HaveOccurred())
container := findContainer(ss.Spec.Template.Spec.Containers, "pulumi")
Expect(container).NotTo(BeNil())
Expect(container.Image).To(Equal("test/pulumi:v3.42.0"))
})
})
})
})

Expand Down

0 comments on commit 88a213d

Please sign in to comment.