Skip to content

Commit e075d0e

Browse files
Merge pull request #29323 from kramaranya/enforce-required-scc-test
OCPBUGS-44961: Fix "Enforce the required-scc monitor test and validate usage of non-standard OCP SCCs"
2 parents 3020953 + 46485ae commit e075d0e

File tree

1 file changed

+103
-24
lines changed

1 file changed

+103
-24
lines changed

pkg/monitortests/authentication/requiredsccmonitortests/monitortest.go

Lines changed: 103 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/openshift/origin/pkg/monitor/monitorapi"
1111
"github.com/openshift/origin/pkg/monitortestframework"
1212
"github.com/openshift/origin/pkg/test/ginkgo/junitapi"
13+
exutil "github.com/openshift/origin/test/extended/util"
1314
v1 "k8s.io/api/core/v1"
1415
"k8s.io/apimachinery/pkg/util/sets"
1516

@@ -31,6 +32,56 @@ var defaultSCCs = sets.NewString(
3132
"restricted-v2",
3233
)
3334

35+
var nonStandardSCCNamespaces = map[string]sets.Set[string]{
36+
"node-exporter": sets.New("openshift-monitoring"),
37+
"machine-api-termination-handler": sets.New("openshift-machine-api"),
38+
}
39+
40+
// namespacesWithPendingSCCPinning includes namespaces with workloads that have pending SCC pinning.
41+
var namespacesWithPendingSCCPinning = sets.NewString(
42+
"openshift-cluster-csi-drivers",
43+
"openshift-cluster-version",
44+
"openshift-image-registry",
45+
"openshift-ingress",
46+
"openshift-ingress-canary",
47+
"openshift-ingress-operator",
48+
"openshift-insights",
49+
"openshift-machine-api",
50+
"openshift-monitoring",
51+
// run-level namespaces
52+
"openshift-cloud-controller-manager",
53+
"openshift-cloud-controller-manager-operator",
54+
"openshift-cluster-api",
55+
"openshift-cluster-machine-approver",
56+
"openshift-dns",
57+
"openshift-dns-operator",
58+
"openshift-etcd",
59+
"openshift-etcd-operator",
60+
"openshift-kube-apiserver",
61+
"openshift-kube-apiserver-operator",
62+
"openshift-kube-controller-manager",
63+
"openshift-kube-controller-manager-operator",
64+
"openshift-kube-proxy",
65+
"openshift-kube-scheduler",
66+
"openshift-kube-scheduler-operator",
67+
"openshift-multus",
68+
"openshift-network-operator",
69+
"openshift-ovn-kubernetes",
70+
"openshift-sdn",
71+
"openshift-storage",
72+
)
73+
74+
// systemNamespaces includes namespaces that should be treated as flaking.
75+
// these namespaces are included because we don't control their creation or labeling on their creation.
76+
var systemNamespaces = sets.NewString(
77+
"default",
78+
"kube-system",
79+
"kube-public",
80+
"openshift-node",
81+
"openshift-infra",
82+
"openshift",
83+
)
84+
3485
type requiredSCCAnnotationChecker struct {
3586
kubeClient kubernetes.Interface
3687
}
@@ -61,7 +112,12 @@ func (w *requiredSCCAnnotationChecker) CollectData(ctx context.Context, storageD
61112

62113
junits := []*junitapi.JUnitTestCase{}
63114
for _, ns := range namespaces.Items {
64-
// require that all workloads in openshift, kube-* or default namespaces must have the required-scc annotation
115+
// skip managed service namespaces
116+
if exutil.ManagedServiceNamespaces.Has(ns.Name) {
117+
continue
118+
}
119+
120+
// require that all workloads in openshift, kube-*, or default namespaces must have the required-scc annotation
65121
// ignore openshift-must-gather-* namespaces which are generated dynamically
66122
isPermanentOpenShiftNamespace := (ns.Name == "openshift" || strings.HasPrefix(ns.Name, "openshift-")) && !strings.HasPrefix(ns.Name, "openshift-must-gather-")
67123
if !strings.HasPrefix(ns.Name, "kube-") && ns.Name != "default" && !isPermanentOpenShiftNamespace {
@@ -75,13 +131,47 @@ func (w *requiredSCCAnnotationChecker) CollectData(ctx context.Context, storageD
75131

76132
failures := make([]string, 0)
77133
for _, pod := range pods.Items {
134+
validatedSCC := pod.Annotations[securityv1.ValidatedSCCAnnotation]
135+
allowedNamespaces, isNonStandard := nonStandardSCCNamespaces[validatedSCC]
136+
78137
if _, exists := pod.Annotations[securityv1.RequiredSCCAnnotation]; exists {
138+
if isNonStandard && !allowedNamespaces.Has(ns.Name) {
139+
failures = append(failures, fmt.Sprintf(
140+
"pod '%s' has a non-standard SCC '%s' not allowed in namespace '%s'; allowed namespaces are: %s",
141+
pod.Name, validatedSCC, ns.Name, strings.Join(allowedNamespaces.UnsortedList(), ", ")))
142+
}
79143
continue
80144
}
81145

82-
suggestedSCC := suggestSCC(&pod)
83146
owners := ownerReferences(&pod)
84-
failures = append(failures, fmt.Sprintf("annotation missing from pod '%s'%s; %s", pod.Name, owners, suggestedSCC))
147+
148+
switch {
149+
case len(validatedSCC) == 0:
150+
failures = append(failures, fmt.Sprintf(
151+
"annotation missing from pod '%s'%s; cannot suggest required-scc, no validated SCC on pod",
152+
pod.Name, owners))
153+
154+
case defaultSCCs.Has(validatedSCC):
155+
failures = append(failures, fmt.Sprintf(
156+
"annotation missing from pod '%s'%s; suggested required-scc: '%s'",
157+
pod.Name, owners, validatedSCC))
158+
159+
case isNonStandard:
160+
if allowedNamespaces.Has(ns.Name) {
161+
failures = append(failures, fmt.Sprintf(
162+
"annotation missing from pod '%s'%s; suggested required-scc: '%s', this is a non-standard SCC",
163+
pod.Name, owners, validatedSCC))
164+
} else {
165+
failures = append(failures, fmt.Sprintf(
166+
"annotation missing from pod '%s'%s; pod is using non-standard SCC '%s' not allowed in namespace '%s'; allowed namespaces are: %s",
167+
pod.Name, owners, validatedSCC, ns.Name, strings.Join(allowedNamespaces.UnsortedList(), ", ")))
168+
}
169+
170+
default:
171+
failures = append(failures, fmt.Sprintf(
172+
"annotation missing from pod '%s'%s; cannot suggest required-scc, validated SCC '%s' is a custom SCC",
173+
pod.Name, owners, validatedSCC))
174+
}
85175
}
86176

87177
testName := fmt.Sprintf("[sig-auth] all workloads in ns/%s must set the '%s' annotation", ns.Name, securityv1.RequiredSCCAnnotation)
@@ -91,18 +181,21 @@ func (w *requiredSCCAnnotationChecker) CollectData(ctx context.Context, storageD
91181
}
92182

93183
failureMsg := strings.Join(failures, "\n")
184+
94185
junits = append(junits,
95186
&junitapi.JUnitTestCase{
96187
Name: testName,
97188
SystemOut: failureMsg,
98189
FailureOutput: &junitapi.FailureOutput{Output: failureMsg},
99-
},
100-
101-
// add a successful test with the same name to cause a flake
102-
&junitapi.JUnitTestCase{
103-
Name: testName,
104-
},
105-
)
190+
})
191+
192+
// add a successful test with the same name to cause a flake if the namespace should be flaking
193+
if namespacesWithPendingSCCPinning.Has(ns.Name) || systemNamespaces.Has(ns.Name) {
194+
junits = append(junits,
195+
&junitapi.JUnitTestCase{
196+
Name: testName,
197+
})
198+
}
106199
}
107200

108201
return nil, junits, nil
@@ -124,20 +217,6 @@ func (w *requiredSCCAnnotationChecker) Cleanup(ctx context.Context) error {
124217
return nil
125218
}
126219

127-
// suggestSCC suggests the assigned SCC only if it belongs to the default set of SCCs
128-
// pods in runlevel 0/1 namespaces won't have any assigned SCC as SCC admission is disabled
129-
func suggestSCC(pod *v1.Pod) string {
130-
if len(pod.Annotations[securityv1.ValidatedSCCAnnotation]) == 0 {
131-
return "cannot suggest required-scc, no validated SCC on pod"
132-
}
133-
134-
if defaultSCCs.Has(pod.Annotations[securityv1.ValidatedSCCAnnotation]) {
135-
return fmt.Sprintf("suggested required-scc: '%s'", pod.Annotations[securityv1.ValidatedSCCAnnotation])
136-
}
137-
138-
return "cannot suggest required-scc, validated SCC is custom"
139-
}
140-
141220
func ownerReferences(pod *v1.Pod) string {
142221
ownerRefs := make([]string, len(pod.OwnerReferences))
143222
for i, or := range pod.OwnerReferences {

0 commit comments

Comments
 (0)