Skip to content

Commit 03046af

Browse files
committed
chore: Improve DWO Webhook
Signed-off-by: Anatolii Bazko <abazko@redhat.com>
1 parent f72ccd0 commit 03046af

5 files changed

Lines changed: 55 additions & 44 deletions

File tree

pkg/library/kubernetes/provision.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ func HandleKubernetesComponents(workspace *common.DevWorkspaceWithConfig, api sy
5656
return nil
5757
}
5858

59+
var validatedK8sComponents []string
60+
if data, ok := workspace.Annotations[constants.DevWorkspaceValidatedK8sResourcesAnnotation]; ok {
61+
if err := json.Unmarshal([]byte(data), &validatedK8sComponents); err != nil {
62+
return fmt.Errorf("failed to parse %s annotation: %w", constants.DevWorkspaceValidatedK8sResourcesAnnotation, err)
63+
}
64+
}
65+
5966
for _, component := range kubeComponents {
6067
// Ignore error as we filtered list above
6168
k8sLikeComponent, _ := getK8sLikeComponent(component)
@@ -64,7 +71,7 @@ func HandleKubernetesComponents(workspace *common.DevWorkspaceWithConfig, api sy
6471
return &dwerrors.FailError{Message: fmt.Sprintf("could not process component %s", component.Name), Err: err}
6572
}
6673

67-
err = restrictK8sComponent(workspace, obj)
74+
err = restrictK8sComponent(workspace, obj, validatedK8sComponents)
6875
if err != nil {
6976
return &dwerrors.FailError{Message: fmt.Sprintf("could not process component %s", component.Name), Err: err}
7077
}
@@ -138,14 +145,7 @@ func addMetadata(obj client.Object, workspace *common.DevWorkspaceWithConfig, ap
138145
return nil
139146
}
140147

141-
func restrictK8sComponent(workspace *common.DevWorkspaceWithConfig, obj client.Object) error {
142-
var validatedK8sComponents []string
143-
if raw := workspace.Annotations[constants.DevWorkspaceValidatedK8sResourcesAnnotation]; raw != "" {
144-
if err := json.Unmarshal([]byte(raw), &validatedK8sComponents); err != nil {
145-
return fmt.Errorf("failed to parse %s annotation: %w", constants.DevWorkspaceValidatedK8sResourcesAnnotation, err)
146-
}
147-
}
148-
148+
func restrictK8sComponent(workspace *common.DevWorkspaceWithConfig, obj client.Object, validatedK8sComponents []string) error {
149149
gvk := obj.GetObjectKind().GroupVersionKind()
150150
switch gvk {
151151
case
@@ -159,11 +159,9 @@ func restrictK8sComponent(workspace *common.DevWorkspaceWithConfig, obj client.O
159159
dw.SchemeGroupVersion.WithKind("DevWorkspaceTemplate"):
160160
return fmt.Errorf("DevWorkspace objects are not permitted within DevWorkspace components")
161161
default:
162-
// For backward compatibility, skip the validation for already-running workspaces since the
163-
// annotation may not be present on workspaces created before this check was introduced.
164-
// Note: workspaces that are being started just after DWO is updated may fail to start
165-
// if the webhook has not re-validated them, as the annotation will be absent.
166-
if workspace.Status.Phase != dw.DevWorkspaceStatusRunning {
162+
// For backward compatibility, skip the validation when the annotation is absent, as it
163+
// may not be present on workspaces created before this check was introduced.
164+
if validatedK8sComponents != nil {
167165
if !slices.Contains(validatedK8sComponents, gvk.String()) {
168166
return fmt.Errorf("user is not authorized to create %s resources", gvk.Kind)
169167
}

pkg/provision/workspace/rbac/role.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ package rbac
1616
import (
1717
"fmt"
1818

19-
dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
2019
"github.com/devfile/devworkspace-operator/pkg/common"
2120
"github.com/devfile/devworkspace-operator/pkg/constants"
2221
"github.com/devfile/devworkspace-operator/pkg/dwerrors"
@@ -37,13 +36,11 @@ func syncRoles(workspace *common.DevWorkspaceWithConfig, api sync.ClusterAPI) er
3736
return nil
3837
}
3938
sccName := workspace.Spec.Template.Attributes.GetString(constants.WorkspaceSCCAttribute, nil)
40-
// For backward compatibility, skip the validation for already-running workspaces since the
41-
// annotation may not be present on workspaces created before this check was introduced.
42-
// Note: workspaces that are being started just after DWO is updated may fail to start
43-
// if the webhook has not re-validated them, as the annotation will be absent.
44-
if workspace.Status.Phase != dw.DevWorkspaceStatusRunning {
45-
validatedSCC := workspace.Annotations[constants.DevWorkspaceValidatedSCCAnnotation]
46-
if validatedSCC != sccName {
39+
40+
// For backward compatibility, skip the validation when the annotation is absent, as it
41+
// may not be present on workspaces created before this check was introduced.
42+
if validatedSCCName, ok := workspace.Annotations[constants.DevWorkspaceValidatedSCCAnnotation]; ok {
43+
if validatedSCCName != sccName {
4744
return fmt.Errorf("user is not authorized to use SecurityContextConstraints '%s'", sccName)
4845
}
4946
}

pkg/webhook/cluster_roles.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,33 @@ func getSpecClusterRole() (*v1.ClusterRole, error) {
163163
"get",
164164
},
165165
},
166+
{
167+
APIGroups: []string{
168+
"route.openshift.io",
169+
},
170+
Resources: []string{
171+
"routes",
172+
},
173+
Verbs: []string{
174+
"create",
175+
"get",
176+
"delete",
177+
},
178+
},
179+
{
180+
APIGroups: []string{
181+
"config.openshift.io",
182+
},
183+
Resources: []string{
184+
"proxies",
185+
},
186+
ResourceNames: []string{
187+
"cluster",
188+
},
189+
Verbs: []string{
190+
"get",
191+
},
192+
},
166193
},
167194
}
168195

webhook/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
2828
"github.com/devfile/devworkspace-operator/pkg/httpfactory"
2929
kubesync "github.com/devfile/devworkspace-operator/pkg/library/kubernetes"
30+
configv1 "github.com/openshift/api/config/v1"
3031
routev1 "github.com/openshift/api/route/v1"
3132
templatev1 "github.com/openshift/api/template/v1"
3233
"k8s.io/utils/ptr"
@@ -79,10 +80,10 @@ func init() {
7980
utilruntime.Must(dwv1.AddToScheme(scheme))
8081
utilruntime.Must(dwv2.AddToScheme(scheme))
8182

82-
// For deserializer
8383
if infrastructure.IsOpenShift() {
8484
utilruntime.Must(routev1.Install(scheme))
8585
utilruntime.Must(templatev1.Install(scheme))
86+
utilruntime.Must(configv1.Install(scheme))
8687
}
8788
}
8889

webhook/workspace/handler/workspace.go

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -308,38 +308,26 @@ func setValidatedPermissionsAnnotations(
308308
validatedSCC string,
309309
validatedKubernetesResources []string,
310310
) (bool, error) {
311-
sort.Strings(validatedKubernetesResources)
312-
313-
validatedKubernetesResourcesStr := ""
311+
validatedKubernetesResourcesStr := "[]"
314312
if len(validatedKubernetesResources) > 0 {
313+
sort.Strings(validatedKubernetesResources)
314+
315315
bytes, err := json.Marshal(validatedKubernetesResources)
316316
if err != nil {
317317
return false, fmt.Errorf("failed to marshal validated kubernetes resources: %w", err)
318318
}
319+
319320
validatedKubernetesResourcesStr = string(bytes)
320321
}
321322

322-
changed := setOrDeleteAnnotation(workspace, constants.DevWorkspaceValidatedSCCAnnotation, validatedSCC)
323+
changed := workspace.Annotations[constants.DevWorkspaceValidatedSCCAnnotation] != validatedSCC
323324
changed = changed ||
324-
setOrDeleteAnnotation(workspace, constants.DevWorkspaceValidatedK8sResourcesAnnotation, validatedKubernetesResourcesStr)
325-
326-
return changed, nil
327-
}
325+
workspace.Annotations[constants.DevWorkspaceValidatedK8sResourcesAnnotation] != validatedKubernetesResourcesStr
328326

329-
func setOrDeleteAnnotation(workspace *dwv2.DevWorkspace, key, newValue string) bool {
330-
oldValue, oldValueExists := workspace.Annotations[key]
327+
workspace.Annotations = maputils.Append(workspace.Annotations, constants.DevWorkspaceValidatedSCCAnnotation, validatedSCC)
328+
workspace.Annotations = maputils.Append(workspace.Annotations, constants.DevWorkspaceValidatedK8sResourcesAnnotation, validatedKubernetesResourcesStr)
331329

332-
if newValue == "" {
333-
if len(workspace.Annotations) == 0 {
334-
return false
335-
}
336-
delete(workspace.Annotations, key)
337-
338-
return oldValueExists
339-
}
340-
341-
workspace.Annotations = maputils.Append(workspace.Annotations, key, newValue)
342-
return oldValue != newValue
330+
return changed, nil
343331
}
344332

345333
func hasFinalizer(obj client.Object, finalizer string) bool {

0 commit comments

Comments
 (0)