Skip to content

Commit 3e89c96

Browse files
committed
p/o/psreadinesscontroller: minor refactoring
1 parent 313bc06 commit 3e89c96

File tree

3 files changed

+136
-67
lines changed

3 files changed

+136
-67
lines changed

pkg/operator/podsecurityreadinesscontroller/podsecurityreadinesscontroller.go

Lines changed: 18 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ import (
44
"context"
55
"time"
66

7-
corev1 "k8s.io/api/core/v1"
87
apierrors "k8s.io/apimachinery/pkg/api/errors"
98
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
109
"k8s.io/apimachinery/pkg/labels"
1110
"k8s.io/apimachinery/pkg/selection"
12-
applyconfiguration "k8s.io/client-go/applyconfigurations/core/v1"
1311
"k8s.io/client-go/kubernetes"
1412
"k8s.io/client-go/rest"
1513
"k8s.io/client-go/util/retry"
@@ -25,11 +23,6 @@ const (
2523
checkInterval = 240 * time.Minute // Adjust the interval as needed.
2624
)
2725

28-
var podSecurityAlertLabels = []string{
29-
psapi.AuditLevelLabel,
30-
psapi.WarnLevelLabel,
31-
}
32-
3326
// PodSecurityReadinessController checks if namespaces are ready for Pod Security Admission enforcement.
3427
type PodSecurityReadinessController struct {
3528
kubeClient kubernetes.Interface
@@ -46,19 +39,12 @@ func NewPodSecurityReadinessController(
4639
) (factory.Controller, error) {
4740
warningsHandler := &warningsHandler{}
4841

49-
kubeClientCopy := rest.CopyConfig(kubeConfig)
50-
kubeClientCopy.WarningHandler = warningsHandler
51-
// We don't want to overwhelm the apiserver with requests. On a cluster with
52-
// 10k namespaces, we would send 10k + 1 requests to the apiserver.
53-
kubeClientCopy.QPS = 2
54-
kubeClientCopy.Burst = 2
55-
kubeClient, err := kubernetes.NewForConfig(kubeClientCopy)
42+
kubeClient, err := newWarningAwareKubeClient(warningsHandler, kubeConfig)
5643
if err != nil {
5744
return nil, err
5845
}
5946

60-
selector := labels.NewSelector()
61-
labelsRequirement, err := labels.NewRequirement(psapi.EnforceLevelLabel, selection.DoesNotExist, []string{})
47+
selector, err := nonEnforcingSelector()
6248
if err != nil {
6349
return nil, err
6450
}
@@ -67,7 +53,7 @@ func NewPodSecurityReadinessController(
6753
operatorClient: operatorClient,
6854
kubeClient: kubeClient,
6955
warningsHandler: warningsHandler,
70-
namespaceSelector: selector.Add(*labelsRequirement).String(),
56+
namespaceSelector: selector,
7157
}
7258

7359
return factory.New().
@@ -114,58 +100,23 @@ func (c *PodSecurityReadinessController) sync(ctx context.Context, syncCtx facto
114100
return err
115101
}
116102

117-
func (c *PodSecurityReadinessController) isNamespaceViolating(ctx context.Context, ns *corev1.Namespace) (bool, error) {
118-
if ns.Labels[psapi.EnforceLevelLabel] != "" {
119-
// If someone has taken care of the enforce label, we don't need to
120-
// check for violations. Global Config nor PS-Label-Syncer will modify
121-
// it.
122-
return false, nil
123-
}
124-
125-
targetLevel := ""
126-
for _, label := range podSecurityAlertLabels {
127-
levelStr, ok := ns.Labels[label]
128-
if !ok {
129-
continue
130-
}
131-
132-
level, err := psapi.ParseLevel(levelStr)
133-
if err != nil {
134-
klog.V(4).InfoS("invalid level", "namespace", ns.Name, "level", levelStr)
135-
continue
136-
}
137-
138-
if targetLevel == "" {
139-
targetLevel = levelStr
140-
continue
141-
}
142-
143-
if psapi.CompareLevels(psapi.Level(targetLevel), level) < 0 {
144-
targetLevel = levelStr
145-
}
146-
}
147-
148-
if targetLevel == "" {
149-
// Global Config will set it to "restricted".
150-
targetLevel = string(psapi.LevelRestricted)
151-
}
152-
153-
nsApply := applyconfiguration.Namespace(ns.Name).WithLabels(map[string]string{
154-
psapi.EnforceLevelLabel: string(targetLevel),
155-
})
156-
157-
_, err := c.kubeClient.CoreV1().
158-
Namespaces().
159-
Apply(ctx, nsApply, metav1.ApplyOptions{
160-
DryRun: []string{metav1.DryRunAll},
161-
FieldManager: "pod-security-readiness-controller",
162-
})
103+
func nonEnforcingSelector() (string, error) {
104+
selector := labels.NewSelector()
105+
labelsRequirement, err := labels.NewRequirement(psapi.EnforceLevelLabel, selection.DoesNotExist, []string{})
163106
if err != nil {
164-
return false, err
107+
return "", err
165108
}
166109

167-
// The information we want is in the warnings. It collects violations.
168-
warnings := c.warningsHandler.PopAll()
110+
return selector.Add(*labelsRequirement).String(), nil
111+
}
112+
113+
func newWarningAwareKubeClient(warningsHandler *warningsHandler, kubeConfig *rest.Config) (*kubernetes.Clientset, error) {
114+
kubeClientCopy := rest.CopyConfig(kubeConfig)
115+
kubeClientCopy.WarningHandler = warningsHandler
116+
// We don't want to overwhelm the apiserver with requests. On a cluster with
117+
// 10k namespaces, we would send 10k + 1 requests to the apiserver.
118+
kubeClientCopy.QPS = 2
119+
kubeClientCopy.Burst = 2
169120

170-
return len(warnings) > 0, nil
121+
return kubernetes.NewForConfig(kubeClientCopy)
171122
}

pkg/operator/podsecurityreadinesscontroller/podsecurityreadinesscontroller_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,49 @@ func TestPodSecurityViolationController(t *testing.T) {
189189
})
190190
}
191191
}
192+
193+
func TestNamespaceSelector(t *testing.T) {
194+
fakeClient := fake.NewSimpleClientset(
195+
&corev1.Namespace{
196+
ObjectMeta: metav1.ObjectMeta{
197+
Name: "ns-without-enforce",
198+
Labels: map[string]string{},
199+
},
200+
},
201+
&corev1.Namespace{
202+
ObjectMeta: metav1.ObjectMeta{
203+
Name: "ns-with-enforce",
204+
Labels: map[string]string{
205+
psapi.EnforceLevelLabel: "restricted",
206+
},
207+
},
208+
},
209+
&corev1.Namespace{
210+
ObjectMeta: metav1.ObjectMeta{
211+
Name: "another-ns-without-enforce",
212+
Labels: map[string]string{},
213+
},
214+
},
215+
)
216+
217+
selector, err := nonEnforcingSelector()
218+
if err != nil {
219+
t.Fatal(err)
220+
}
221+
222+
nsList, err := fakeClient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{LabelSelector: selector})
223+
if err != nil {
224+
t.Fatal(err)
225+
}
226+
227+
if len(nsList.Items) != 2 {
228+
t.Errorf("expected 2 namespaces, got %d", len(nsList.Items))
229+
}
230+
231+
for _, ns := range nsList.Items {
232+
label, ok := ns.Labels[psapi.EnforceLevelLabel]
233+
if ok {
234+
t.Error("unexpected enforce label", label)
235+
}
236+
}
237+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package podsecurityreadinesscontroller
2+
3+
import (
4+
"context"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
applyconfiguration "k8s.io/client-go/applyconfigurations/core/v1"
9+
"k8s.io/klog/v2"
10+
psapi "k8s.io/pod-security-admission/api"
11+
)
12+
13+
var podSecurityAlertLabels = []string{
14+
psapi.AuditLevelLabel,
15+
psapi.WarnLevelLabel,
16+
}
17+
18+
func (c *PodSecurityReadinessController) isNamespaceViolating(ctx context.Context, ns *corev1.Namespace) (bool, error) {
19+
if ns.Labels[psapi.EnforceLevelLabel] != "" {
20+
// If someone has taken care of the enforce label, we don't need to
21+
// check for violations. Global Config nor PS-Label-Syncer will modify
22+
// it.
23+
return false, nil
24+
}
25+
26+
targetLevel := ""
27+
for _, label := range podSecurityAlertLabels {
28+
levelStr, ok := ns.Labels[label]
29+
if !ok {
30+
continue
31+
}
32+
33+
level, err := psapi.ParseLevel(levelStr)
34+
if err != nil {
35+
klog.V(4).InfoS("invalid level", "namespace", ns.Name, "level", levelStr)
36+
continue
37+
}
38+
39+
if targetLevel == "" {
40+
targetLevel = levelStr
41+
continue
42+
}
43+
44+
if psapi.CompareLevels(psapi.Level(targetLevel), level) < 0 {
45+
targetLevel = levelStr
46+
}
47+
}
48+
49+
if targetLevel == "" {
50+
// Global Config will set it to "restricted".
51+
targetLevel = string(psapi.LevelRestricted)
52+
}
53+
54+
nsApply := applyconfiguration.Namespace(ns.Name).WithLabels(map[string]string{
55+
psapi.EnforceLevelLabel: string(targetLevel),
56+
})
57+
58+
_, err := c.kubeClient.CoreV1().
59+
Namespaces().
60+
Apply(ctx, nsApply, metav1.ApplyOptions{
61+
DryRun: []string{metav1.DryRunAll},
62+
FieldManager: "pod-security-readiness-controller",
63+
})
64+
if err != nil {
65+
return false, err
66+
}
67+
68+
// The information we want is in the warnings. It collects violations.
69+
warnings := c.warningsHandler.PopAll()
70+
71+
return len(warnings) > 0, nil
72+
}

0 commit comments

Comments
 (0)