diff --git a/pkg/common/constants/constants.go b/pkg/common/constants/constants.go index 73fb2a0c4e..dafe2b5a6f 100644 --- a/pkg/common/constants/constants.go +++ b/pkg/common/constants/constants.go @@ -12,6 +12,11 @@ package constants +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/pointer" +) + const ( // PostgresSQL DefaultPostgresUser = "pgche" @@ -138,4 +143,14 @@ var ( "app": "che", "component": "che-gateway-config", } + + DefaultWorkspaceContainerSecurityContext = corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SETGID", + "SETUID", + }, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(true), + } ) diff --git a/pkg/deploy/container-build/container_build.go b/pkg/deploy/container-build/container_build.go index b0e97bf53f..ea67d9596a 100644 --- a/pkg/deploy/container-build/container_build.go +++ b/pkg/deploy/container-build/container_build.go @@ -16,6 +16,9 @@ import ( "context" "fmt" + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/types" + "github.com/eclipse-che/che-operator/pkg/common/chetypes" "github.com/eclipse-che/che-operator/pkg/common/constants" defaults "github.com/eclipse-che/che-operator/pkg/common/operator-defaults" @@ -94,8 +97,36 @@ func (cb *ContainerBuildReconciler) Finalize(ctx *chetypes.DeployContext) bool { } func (cb *ContainerBuildReconciler) syncSCC(ctx *chetypes.DeployContext) (bool, error) { - _, err := deploy.CreateIfNotExists(ctx, cb.getSccSpec(ctx)) - return err == nil, err + scc := &securityv1.SecurityContextConstraints{} + if exists, err := deploy.Get(ctx, + types.NamespacedName{Name: ctx.CheCluster.Spec.DevEnvironments.ContainerBuildConfiguration.OpenShiftSecurityContextConstraint}, + scc); err != nil { + return false, err + } else if exists { + if deploy.IsPartOfEclipseCheResourceAndManagedByOperator(scc.Labels) { + // SCC exists and created by operator (custom SCC won't be updated). + // So, remove priority. See details https://issues.redhat.com/browse/CRW-3894 + scc.Priority = nil + + // Ensure kind and version set correctly before invoking `Sync` + scc.Kind = "SecurityContextConstraints" + scc.APIVersion = securityv1.GroupVersion.String() + + return deploy.Sync( + ctx, + scc, + cmp.Options{ + cmp.Comparer(func(x, y securityv1.SecurityContextConstraints) bool { + return pointer.Int32Equal(x.Priority, y.Priority) + }), + }) + } + } else { + // Create a new SCC. If custom SCC exists then it won't be touched. + return deploy.Create(ctx, cb.getSccSpec(ctx)) + } + + return true, nil } func (cb *ContainerBuildReconciler) syncRBAC(ctx *chetypes.DeployContext) (bool, error) { @@ -259,8 +290,6 @@ func (cb *ContainerBuildReconciler) getSccSpec(ctx *chetypes.DeployContext) *sec AllowedCapabilities: []corev1.Capability{"SETUID", "SETGID"}, DefaultAddCapabilities: nil, FSGroup: securityv1.FSGroupStrategyOptions{Type: securityv1.FSGroupStrategyMustRunAs}, - // Temporary workaround for https://github.com/devfile/devworkspace-operator/issues/884 - Priority: pointer.Int32Ptr(20), ReadOnlyRootFilesystem: false, RequiredDropCapabilities: []corev1.Capability{"KILL", "MKNOD"}, RunAsUser: securityv1.RunAsUserStrategyOptions{Type: securityv1.RunAsUserStrategyMustRunAsRange}, diff --git a/pkg/deploy/dev-workspace-config/dev_workspace_config.go b/pkg/deploy/dev-workspace-config/dev_workspace_config.go index c1244cb130..76cf645753 100644 --- a/pkg/deploy/dev-workspace-config/dev_workspace_config.go +++ b/pkg/deploy/dev-workspace-config/dev_workspace_config.go @@ -56,7 +56,7 @@ func (d *DevWorkspaceConfigReconciler) Reconcile(ctx *chetypes.DeployContext) (r dwoc.Config = &controllerv1alpha1.OperatorConfiguration{} } - if err := updateWorkspaceConfig(&ctx.CheCluster.Spec.DevEnvironments, dwoc.Config); err != nil { + if err := updateWorkspaceConfig(ctx.CheCluster, dwoc.Config); err != nil { return reconcile.Result{}, false, err } @@ -71,7 +71,8 @@ func (d *DevWorkspaceConfigReconciler) Finalize(ctx *chetypes.DeployContext) boo return true } -func updateWorkspaceConfig(devEnvironments *chev2.CheClusterDevEnvironments, operatorConfig *controllerv1alpha1.OperatorConfiguration) error { +func updateWorkspaceConfig(cheCluster *chev2.CheCluster, operatorConfig *controllerv1alpha1.OperatorConfiguration) error { + devEnvironments := &cheCluster.Spec.DevEnvironments if operatorConfig.Workspace == nil { operatorConfig.Workspace = &controllerv1alpha1.WorkspaceConfig{} } @@ -84,6 +85,11 @@ func updateWorkspaceConfig(devEnvironments *chev2.CheClusterDevEnvironments, ope return err } + operatorConfig.Workspace.ContainerSecurityContext = nil + if cheCluster.IsContainerBuildCapabilitiesEnabled() { + operatorConfig.Workspace.ContainerSecurityContext = constants.DefaultWorkspaceContainerSecurityContext.DeepCopy() + } + return nil } diff --git a/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go b/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go index eb37b096db..f0b321200d 100644 --- a/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go +++ b/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go @@ -17,6 +17,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" "github.com/eclipse-che/che-operator/pkg/common/constants" "k8s.io/apimachinery/pkg/api/resource" @@ -318,6 +319,144 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, }, }, + { + name: "Create DevWorkspaceOperatorConfig without Pod Security Context if container build disabled", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(true), + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{}, + }, + }, + { + name: "Create DevWorkspaceOperatorConfig with Pod and Container Security Context if container build enabled", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(false), + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + ContainerSecurityContext: &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SETGID", + "SETUID", + }, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(true), + }, + }, + }, + }, + { + name: "Update existing DevWorkspaceOperatorConfig by adding Pod and Container Security Context", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(false), + }, + }, + }, + existedObjects: []runtime.Object{ + &controllerv1alpha1.DevWorkspaceOperatorConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: devWorkspaceConfigName, + Namespace: "eclipse-che", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DevWorkspaceOperatorConfig", + APIVersion: controllerv1alpha1.GroupVersion.String(), + }, + Config: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + }, + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + ContainerSecurityContext: &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SETGID", + "SETUID", + }, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(true), + }, + }, + }, + }, + { + name: "Update existing DevWorkspaceOperatorConfig by removing Pod and Container Security Context", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(true), + }, + }, + }, + existedObjects: []runtime.Object{ + &controllerv1alpha1.DevWorkspaceOperatorConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: devWorkspaceConfigName, + Namespace: "eclipse-che", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DevWorkspaceOperatorConfig", + APIVersion: controllerv1alpha1.GroupVersion.String(), + }, + Config: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + ContainerSecurityContext: &corev1.SecurityContext{}, + }, + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + }, + }, + }, } for _, testCase := range testCases { diff --git a/pkg/deploy/labels.go b/pkg/deploy/labels.go index a189b1a59d..d9b8b106de 100644 --- a/pkg/deploy/labels.go +++ b/pkg/deploy/labels.go @@ -49,3 +49,7 @@ func GetLegacyLabels(component string) map[string]string { "component": component, } } + +func IsPartOfEclipseCheResourceAndManagedByOperator(labels map[string]string) bool { + return labels[constants.KubernetesPartOfLabelKey] == constants.CheEclipseOrg && labels[constants.KubernetesManagedByLabelKey] == GetManagedByLabel() +}