Skip to content

Commit 46ef601

Browse files
committed
add a controller that reconciles SCCs' volumes
The storage team added "ephemeral" and "csi" volumes to all SCCs somewhere around OCP version 4.13. However, since the past us set SCCs as "create-only" (due to the legacy permission system), meaning the CVO won't reconcile the SCCs, this change never made it to upgraded clusters' SCCs. People that lack SCC update privileges were installing odd operators they found on the internets in hope to fix their SCC issues. Introduce a controller that adds these volumes to all SCCs that the CVO does not automatically reconcile.
1 parent b352992 commit 46ef601

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
lines changed

bindata/assets/config/config-overrides.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,3 @@ serviceAccountPublicKeyFiles:
1717
# The following path contains the public keys needed to verify bound sa
1818
# tokens. This is only supported post-bootstrap.
1919
- /etc/kubernetes/static-pod-resources/configmaps/bound-sa-token-signing-certs
20-
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package sccreconcilecontroller
2+
3+
import (
4+
"context"
5+
6+
securityv1client "github.com/openshift/client-go/security/clientset/versioned/typed/security/v1"
7+
securityv1informers "github.com/openshift/client-go/security/informers/externalversions/security/v1"
8+
securityv1listers "github.com/openshift/client-go/security/listers/security/v1"
9+
"github.com/openshift/library-go/pkg/controller/factory"
10+
"github.com/openshift/library-go/pkg/operator/events"
11+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/util/sets"
13+
)
14+
15+
type sccReconcileController struct {
16+
sccClient securityv1client.SecurityV1Interface
17+
sccLister securityv1listers.SecurityContextConstraintsLister
18+
}
19+
20+
var createOnlySCCs = []string{
21+
"anyuid",
22+
"hostaccess",
23+
"hostmount-anyuid",
24+
"hostnetwork",
25+
"nonroot",
26+
"restricted",
27+
}
28+
29+
// NewSCCReconcileController reconciles the "ephemeral" and "csi" volumes into
30+
// otherwise "create-only" reconciled SCCs to make these volumes available to
31+
// regular users in upgraded clusters.
32+
//
33+
// TODO:(consider): In the past we tried to reconcile the original (non-v2) SCCs with CVO
34+
// but that backfired badly as people still used the original SCC permission model
35+
// directly writing to SCC's "users" and "groups" fields as compared to
36+
// the newer RBAC approach.
37+
// Consider using this controller to reconcile all the fields BUT "users" and "groups"
38+
// for these older SCCs.
39+
func NewSCCReconcileController(
40+
sccClient securityv1client.SecurityV1Interface,
41+
sccInformer securityv1informers.SecurityContextConstraintsInformer,
42+
recorder events.Recorder,
43+
) (factory.Controller, error) {
44+
c := &sccReconcileController{
45+
sccClient: sccClient,
46+
sccLister: sccInformer.Lister(),
47+
}
48+
49+
return factory.New().
50+
WithSync(c.sync).
51+
WithFilteredEventsInformersQueueKeyFunc(
52+
factory.ObjectNameToKey,
53+
factory.NamesFilter(createOnlySCCs...),
54+
sccInformer.Informer(),
55+
).
56+
ToController("SCCReconcileController", recorder.WithComponentSuffix("scc-reconcile-controller")), nil
57+
}
58+
59+
func (c *sccReconcileController) sync(ctx context.Context, controllerContext factory.SyncContext) error {
60+
sccName := controllerContext.QueueKey()
61+
scc, err := c.sccLister.Get(sccName)
62+
if err != nil {
63+
return err
64+
}
65+
66+
volumeSet := sets.New(scc.Volumes...)
67+
if volumeSet.Has("ephemeral") && volumeSet.Has("csi") {
68+
return nil
69+
}
70+
71+
volumeSet.Insert("ephemeral", "csi")
72+
sccCopy := scc.DeepCopy()
73+
sccCopy.Volumes = volumeSet.UnsortedList()
74+
75+
_, err = c.sccClient.SecurityContextConstraints().Update(ctx, sccCopy, v1.UpdateOptions{})
76+
return err
77+
}

pkg/operator/starter.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
operatorv1client "github.com/openshift/client-go/operator/clientset/versioned"
1616
operatorv1informers "github.com/openshift/client-go/operator/informers/externalversions"
1717
operatorcontrolplaneclient "github.com/openshift/client-go/operatorcontrolplane/clientset/versioned"
18+
securityclient "github.com/openshift/client-go/security/clientset/versioned"
19+
securityvnformers "github.com/openshift/client-go/security/informers/externalversions"
1820
"github.com/openshift/cluster-kube-apiserver-operator/bindata"
1921
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/boundsatokensignercontroller"
2022
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/certrotationcontroller"
@@ -28,6 +30,7 @@ import (
2830
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/operatorclient"
2931
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/podsecurityreadinesscontroller"
3032
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/resourcesynccontroller"
33+
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/sccreconcilecontroller"
3134
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/serviceaccountissuercontroller"
3235
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/startupmonitorreadiness"
3336
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/targetconfigcontroller"
@@ -84,6 +87,10 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
8487
if err != nil {
8588
return err
8689
}
90+
securityClient, err := securityclient.NewForConfig(controllerContext.KubeConfig)
91+
if err != nil {
92+
return err
93+
}
8794
operatorcontrolplaneClient, err := operatorcontrolplaneclient.NewForConfig(controllerContext.KubeConfig)
8895
if err != nil {
8996
return err
@@ -113,6 +120,8 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
113120
return err
114121
}
115122

123+
securityInformers := securityvnformers.NewSharedInformerFactory(securityClient, 10*time.Minute)
124+
116125
desiredVersion := status.VersionForOperatorFromEnv()
117126
missingVersion := "0.0.1-snapshot"
118127

@@ -427,6 +436,12 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
427436
controllerContext.EventRecorder,
428437
)
429438

439+
sccReconcileController, err := sccreconcilecontroller.NewSCCReconcileController(
440+
securityClient.SecurityV1(),
441+
securityInformers.Security().V1().SecurityContextConstraints(),
442+
controllerContext.EventRecorder,
443+
)
444+
430445
podSecurityReadinessController, err := podsecurityreadinesscontroller.NewPodSecurityReadinessController(
431446
controllerContext.ProtoKubeConfig,
432447
operatorClient,
@@ -448,6 +463,7 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
448463
migrationInformer.Start(ctx.Done())
449464
apiextensionsInformers.Start(ctx.Done())
450465
operatorInformers.Start(ctx.Done())
466+
securityInformers.Start(ctx.Done())
451467

452468
go staticPodControllers.Start(ctx)
453469
go resourceSyncController.Run(ctx, 1)
@@ -470,6 +486,7 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
470486
go webhookSupportabilityController.Run(ctx, 1)
471487
go serviceAccountIssuerController.Run(ctx, 1)
472488
go podSecurityReadinessController.Run(ctx, 1)
489+
go sccReconcileController.Run(ctx, 1)
473490

474491
<-ctx.Done()
475492
return nil

0 commit comments

Comments
 (0)