Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ test: manifests generate envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out

GOLANGCI_LINT = $(shell pwd)/bin/golangci-lint
GOLANGCI_LINT_VERSION ?= v1.54.2
GOLANGCI_LINT_VERSION ?= v2.10
golangci-lint:
@[ -f $(GOLANGCI_LINT) ] || { \
set -e ;\
Expand Down
8 changes: 5 additions & 3 deletions api/v1/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,11 @@ type ContainerSpec struct {
VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"`
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
RestartPolicy corev1.RestartPolicy `json:"restartPolicy,omitempty"`
SecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"`
ExtraContainers []corev1.Container `json:"extraContainers,omitempty"`
InitContainers []corev1.Container `json:"initContainers,omitempty"`

// +kubebuilder:default={"fsGroup":82,"runAsGroup":82,"runAsNonRoot":true,"runAsUser":82,"seccompProfile":{"type":"RuntimeDefault"}}
SecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"`
ExtraContainers []corev1.Container `json:"extraContainers,omitempty"`
InitContainers []corev1.Container `json:"initContainers,omitempty"`

// +kubebuilder:default=2
Replicas int32 `json:"replicas,omitempty"`
Expand Down
7 changes: 4 additions & 3 deletions internal/cronjob/scheduled_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ func ScheduledTaskJob(store v1.Store) *batchv1.CronJob {

annotations := util.GetDefaultContainerAnnotations(CONTAINER_NAME_SCHEDULED_JOB, store, store.Spec.SetupJobContainer.Annotations)

containers := append(store.Spec.Container.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(store.Spec.Container.ExtraContainers), corev1.Container{
Name: CONTAINER_NAME_SCHEDULED_JOB,
VolumeMounts: store.Spec.Container.VolumeMounts,
ImagePullPolicy: store.Spec.Container.ImagePullPolicy,
Image: store.Spec.Container.Image,
SecurityContext: util.RestrictedContainerSecurityContext(),
Command: []string{"sh", "-c"},
Args: []string{store.Spec.ScheduledTask.Command},
Env: store.GetEnv(),
Expand Down Expand Up @@ -111,9 +112,9 @@ func ScheduledTaskJob(store v1.Store) *batchv1.CronJob {
EnableServiceLinks: store.Spec.Container.EnableServiceLinks,
RestartPolicy: "Never",
Containers: containers,
SecurityContext: store.Spec.Container.SecurityContext,
SecurityContext: util.DefaultPodSecurityContext(store.Spec.Container.SecurityContext),
ServiceAccountName: sa,
InitContainers: store.Spec.Container.InitContainers,
InitContainers: util.DefaultContainerSecurityContexts(store.Spec.Container.InitContainers),
},
},
},
Expand Down
39 changes: 39 additions & 0 deletions internal/cronjob/scheduled_task_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cronjob_test

import (
"testing"

v1 "github.com/shopware/shopware-operator/api/v1"
"github.com/shopware/shopware-operator/internal/cronjob"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestScheduledTaskJobUsesRestrictedContainerSecurityContext(t *testing.T) {
store := v1.Store{
ObjectMeta: metav1.ObjectMeta{
Name: "test-store",
Namespace: "test",
},
Spec: v1.StoreSpec{
Container: v1.ContainerSpec{
Image: "shopware:latest",
},
ScheduledTask: v1.ScheduledTaskSpec{
Schedule: "0 * * * *",
TimeZone: "Etc/UTC",
Command: "bin/console scheduled-task:run",
},
},
}

result := cronjob.ScheduledTaskJob(store)
container := result.Spec.JobTemplate.Spec.Template.Spec.Containers[0]

assert.NotNil(t, container.SecurityContext)
assert.NotNil(t, container.SecurityContext.AllowPrivilegeEscalation)
assert.False(t, *container.SecurityContext.AllowPrivilegeEscalation)
assert.NotNil(t, container.SecurityContext.Capabilities)
assert.Equal(t, []corev1.Capability{"ALL"}, container.SecurityContext.Capabilities.Drop)
}
7 changes: 4 additions & 3 deletions internal/deployment/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func AdminDeployment(store v1.Store) *appsv1.Deployment {
}
}

containers := append(containerSpec.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(containerSpec.ExtraContainers), corev1.Container{
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Expand Down Expand Up @@ -116,6 +116,7 @@ func AdminDeployment(store v1.Store) *appsv1.Deployment {
Name: appName,
Image: containerSpec.Image,
ImagePullPolicy: containerSpec.ImagePullPolicy,
SecurityContext: util.RestrictedContainerSecurityContext(),
Env: envs,
Comment thread
tombojer marked this conversation as resolved.
VolumeMounts: containerSpec.VolumeMounts,
Ports: []corev1.ContainerPort{
Expand Down Expand Up @@ -170,8 +171,8 @@ func AdminDeployment(store v1.Store) *appsv1.Deployment {
EnableServiceLinks: containerSpec.EnableServiceLinks,
RestartPolicy: containerSpec.RestartPolicy,
Containers: containers,
SecurityContext: containerSpec.SecurityContext,
InitContainers: containerSpec.InitContainers,
SecurityContext: util.DefaultPodSecurityContext(containerSpec.SecurityContext),
InitContainers: util.DefaultContainerSecurityContexts(containerSpec.InitContainers),
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions internal/deployment/storefront.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func StorefrontDeployment(store v1.Store) *appsv1.Deployment {
}
}

containers := append(containerSpec.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(containerSpec.ExtraContainers), corev1.Container{
Name: DEPLOYMENT_STOREFRONT_CONTAINER_NAME,
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
Expand Down Expand Up @@ -121,6 +121,7 @@ func StorefrontDeployment(store v1.Store) *appsv1.Deployment {
},
Image: containerSpec.Image,
ImagePullPolicy: containerSpec.ImagePullPolicy,
SecurityContext: util.RestrictedContainerSecurityContext(),
Env: envs,
Comment thread
tombojer marked this conversation as resolved.
VolumeMounts: containerSpec.VolumeMounts,
Ports: []corev1.ContainerPort{
Expand Down Expand Up @@ -174,8 +175,8 @@ func StorefrontDeployment(store v1.Store) *appsv1.Deployment {
EnableServiceLinks: containerSpec.EnableServiceLinks,
RestartPolicy: containerSpec.RestartPolicy,
Containers: containers,
SecurityContext: containerSpec.SecurityContext,
InitContainers: containerSpec.InitContainers,
SecurityContext: util.DefaultPodSecurityContext(containerSpec.SecurityContext),
InitContainers: util.DefaultContainerSecurityContexts(containerSpec.InitContainers),
},
},
},
Expand Down
26 changes: 25 additions & 1 deletion internal/deployment/storefront_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,36 @@ func TestStorefrontDeployment(t *testing.T) {

result := deployment.StorefrontDeployment(store)

// Verify security context is overwritten
// Verify pod security context is overwritten.
assert.NotNil(t, result.Spec.Template.Spec.SecurityContext)
assert.Equal(t, int64(2000), *result.Spec.Template.Spec.SecurityContext.RunAsGroup)
assert.Nil(t, result.Spec.Template.Spec.SecurityContext.RunAsUser)
})

t.Run("test storefront container security context is restricted", func(t *testing.T) {
store := v1.Store{
ObjectMeta: metav1.ObjectMeta{
Name: "test-store",
Namespace: "test",
},
Spec: v1.StoreSpec{
Container: v1.ContainerSpec{
Image: "shopware:latest",
},
SecretName: "store-secret",
},
}

result := deployment.StorefrontDeployment(store)
container := result.Spec.Template.Spec.Containers[0]

assert.NotNil(t, container.SecurityContext)
assert.NotNil(t, container.SecurityContext.AllowPrivilegeEscalation)
assert.False(t, *container.SecurityContext.AllowPrivilegeEscalation)
assert.NotNil(t, container.SecurityContext.Capabilities)
assert.Equal(t, []corev1.Capability{"ALL"}, container.SecurityContext.Capabilities.Drop)
})

t.Run("test service account merge", func(t *testing.T) {
store := v1.Store{
ObjectMeta: metav1.ObjectMeta{
Expand Down
7 changes: 4 additions & 3 deletions internal/deployment/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ func WorkerDeployment(store v1.Store) *appsv1.Deployment {
// Merge containerSpec.ExtraEnvs to override with merged values from WorkerDeploymentContainer
envs := util.MergeEnv(store.GetEnv(), containerSpec.ExtraEnvs)

containers := append(containerSpec.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(containerSpec.ExtraContainers), corev1.Container{
Name: appName,
Image: containerSpec.Image,
ImagePullPolicy: containerSpec.ImagePullPolicy,
Env: envs,
SecurityContext: util.RestrictedContainerSecurityContext(),
Command: []string{
"bin/console",
},
Expand Down Expand Up @@ -145,8 +146,8 @@ func WorkerDeployment(store v1.Store) *appsv1.Deployment {
EnableServiceLinks: containerSpec.EnableServiceLinks,
RestartPolicy: containerSpec.RestartPolicy,
Containers: containers,
SecurityContext: containerSpec.SecurityContext,
InitContainers: containerSpec.InitContainers,
SecurityContext: util.DefaultPodSecurityContext(containerSpec.SecurityContext),
InitContainers: util.DefaultContainerSecurityContexts(containerSpec.InitContainers),
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions internal/job/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ func getJobSpec(store v1.Store, ex v1.StoreExec, labels map[string]string) batch

envs := util.MergeEnv(store.GetEnv(), ex.Spec.ExtraEnvs)

containers := append(containerSpec.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(containerSpec.ExtraContainers), corev1.Container{
Name: CONTAINER_NAME_COMMAND,
VolumeMounts: containerSpec.VolumeMounts,
ImagePullPolicy: containerSpec.ImagePullPolicy,
Image: containerSpec.Image,
SecurityContext: util.RestrictedContainerSecurityContext(),
Command: []string{"sh", "-c"},
Args: []string{ex.Spec.Script},
Env: envs,
Expand Down Expand Up @@ -154,8 +155,8 @@ func getJobSpec(store v1.Store, ex v1.StoreExec, labels map[string]string) batch
EnableServiceLinks: containerSpec.EnableServiceLinks,
RestartPolicy: "Never",
Containers: containers,
SecurityContext: containerSpec.SecurityContext,
InitContainers: containerSpec.InitContainers,
SecurityContext: util.DefaultPodSecurityContext(containerSpec.SecurityContext),
InitContainers: util.DefaultContainerSecurityContexts(containerSpec.InitContainers),
},
},
}
Expand Down
67 changes: 67 additions & 0 deletions internal/job/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,39 @@ func TestCommandJob(t *testing.T) {
assert.Equal(t, []string{"bin/console cache:clear"}, container.Args)
assert.Equal(t, "shopware-command", container.Name)
})

t.Run("test container security context is restricted", func(t *testing.T) {
store := v1.Store{
ObjectMeta: metav1.ObjectMeta{
Name: "test-store",
Namespace: "test",
},
Spec: v1.StoreSpec{
Container: v1.ContainerSpec{
Image: "shopware:latest",
},
},
}

exec := v1.StoreExec{
ObjectMeta: metav1.ObjectMeta{
Name: "test-exec",
Namespace: "test",
},
Spec: v1.StoreExecSpec{
Script: "echo test",
},
}

result := job.CommandJob(store, exec)
container := result.Spec.Template.Spec.Containers[0]

assert.NotNil(t, container.SecurityContext)
assert.NotNil(t, container.SecurityContext.AllowPrivilegeEscalation)
assert.False(t, *container.SecurityContext.AllowPrivilegeEscalation)
assert.NotNil(t, container.SecurityContext.Capabilities)
assert.Equal(t, []corev1.Capability{"ALL"}, container.SecurityContext.Capabilities.Drop)
})
}

func TestCommandCronJob(t *testing.T) {
Expand Down Expand Up @@ -144,4 +177,38 @@ func TestCommandCronJob(t *testing.T) {
assert.Equal(t, "test-exec", result.Name)
assert.Equal(t, "test", result.Namespace)
})

t.Run("test cron container security context is restricted", func(t *testing.T) {
store := v1.Store{
ObjectMeta: metav1.ObjectMeta{
Name: "test-store",
Namespace: "test",
},
Spec: v1.StoreSpec{
Container: v1.ContainerSpec{
Image: "shopware:latest",
},
},
}

exec := v1.StoreExec{
ObjectMeta: metav1.ObjectMeta{
Name: "test-exec",
Namespace: "test",
},
Spec: v1.StoreExecSpec{
Script: "echo test",
CronSchedule: "*/5 * * * *",
},
}

result := job.CommandCronJob(store, exec)
container := result.Spec.JobTemplate.Spec.Template.Spec.Containers[0]

assert.NotNil(t, container.SecurityContext)
assert.NotNil(t, container.SecurityContext.AllowPrivilegeEscalation)
assert.False(t, *container.SecurityContext.AllowPrivilegeEscalation)
assert.NotNil(t, container.SecurityContext.Capabilities)
assert.Equal(t, []corev1.Capability{"ALL"}, container.SecurityContext.Capabilities.Drop)
})
}
7 changes: 4 additions & 3 deletions internal/job/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ func MigrationJob(store v1.Store) *batchv1.Job {
// Merge containerSpec.ExtraEnvs to override with merged values from MigrationJobContainer
envs := util.MergeEnv(store.GetEnv(), containerSpec.ExtraEnvs)

containers := append(containerSpec.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(containerSpec.ExtraContainers), corev1.Container{
Name: CONTAINER_NAME_MIGRATION_JOB,
VolumeMounts: containerSpec.VolumeMounts,
ImagePullPolicy: containerSpec.ImagePullPolicy,
Image: containerSpec.Image,
SecurityContext: util.RestrictedContainerSecurityContext(),
Command: []string{"sh", "-c"},
Args: []string{store.Spec.MigrationScript},
Env: envs,
Expand Down Expand Up @@ -93,8 +94,8 @@ func MigrationJob(store v1.Store) *batchv1.Job {
EnableServiceLinks: containerSpec.EnableServiceLinks,
RestartPolicy: "Never",
Containers: containers,
SecurityContext: containerSpec.SecurityContext,
InitContainers: containerSpec.InitContainers,
SecurityContext: util.DefaultPodSecurityContext(containerSpec.SecurityContext),
InitContainers: util.DefaultContainerSecurityContexts(containerSpec.InitContainers),
},
},
},
Expand Down
28 changes: 28 additions & 0 deletions internal/job/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,32 @@ func TestMigrationJob(t *testing.T) {
// Verify service account is overwritten
assert.Equal(t, "migration-sa", result.Spec.Template.Spec.ServiceAccountName)
})

t.Run("test container security context is restricted", func(t *testing.T) {
store := v1.Store{
ObjectMeta: metav1.ObjectMeta{
Name: "test-store",
Namespace: "test",
},
Spec: v1.StoreSpec{
Container: v1.ContainerSpec{
Image: "shopware:latest",
},
MigrationScript: "/migrate.sh",
SecretName: "store-secret",
},
Status: v1.StoreStatus{
CurrentImageTag: "shopware:old",
},
}

result := job.MigrationJob(store)
container := result.Spec.Template.Spec.Containers[0]

assert.NotNil(t, container.SecurityContext)
assert.NotNil(t, container.SecurityContext.AllowPrivilegeEscalation)
assert.False(t, *container.SecurityContext.AllowPrivilegeEscalation)
assert.NotNil(t, container.SecurityContext.Capabilities)
assert.Equal(t, []corev1.Capability{"ALL"}, container.SecurityContext.Capabilities.Drop)
})
}
7 changes: 4 additions & 3 deletions internal/job/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ func SetupJob(store v1.Store) *batchv1.Job {
// Merge containerSpec.ExtraEnvs to override with merged values from SetupJobContainer
envs = util.MergeEnv(envs, containerSpec.ExtraEnvs)

containers := append(containerSpec.ExtraContainers, corev1.Container{
containers := append(util.DefaultContainerSecurityContexts(containerSpec.ExtraContainers), corev1.Container{
Name: CONTAINER_NAME_SETUP_JOB,
VolumeMounts: containerSpec.VolumeMounts,
ImagePullPolicy: containerSpec.ImagePullPolicy,
Image: containerSpec.Image,
SecurityContext: util.RestrictedContainerSecurityContext(),
Command: []string{"sh", "-c"},
Args: []string{store.Spec.SetupScript},
Env: envs,
Expand Down Expand Up @@ -102,8 +103,8 @@ func SetupJob(store v1.Store) *batchv1.Job {
EnableServiceLinks: containerSpec.EnableServiceLinks,
RestartPolicy: "Never",
Containers: containers,
SecurityContext: containerSpec.SecurityContext,
InitContainers: containerSpec.InitContainers,
SecurityContext: util.DefaultPodSecurityContext(containerSpec.SecurityContext),
InitContainers: util.DefaultContainerSecurityContexts(containerSpec.InitContainers),
},
},
},
Expand Down
Loading
Loading