From 12cb46ea61c282b4a1a2ed1c67f8cc589be68f6d Mon Sep 17 00:00:00 2001 From: Ugo Giordano Date: Fri, 26 Jun 2026 23:17:06 +0200 Subject: [PATCH] fix(networkpolicies): allow privileged SAs to create NetworkPolicies in openshift-ingress The openshift-ingress namespace has a special-case check that only allows NetworkPolicies whose podSelector targets a non-default ingress controller. This blocks privileged service accounts (matching redhat-*, openshift-*, etc.) from creating NetworkPolicies for non-ingress-controller pods deployed in that namespace. OCP 4.22 introduced a deny-all NetworkPolicy in openshift-ingress, making it necessary for operators like RHOAI to create explicit allow policies for their pods (kube-auth-proxy, payload-processing). Without this fix, the webhook blocks these policies even from privileged SAs. Add the privileged SA check before the ingress controller label check so that trusted operators can manage NetworkPolicies in openshift-ingress without requiring the ingress controller label. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../networkpolicies/networkpolicies.go | 10 ++++++++ .../networkpolicies/networkpolicies_test.go | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/pkg/webhooks/networkpolicies/networkpolicies.go b/pkg/webhooks/networkpolicies/networkpolicies.go index 31d1e759..9e146f49 100644 --- a/pkg/webhooks/networkpolicies/networkpolicies.go +++ b/pkg/webhooks/networkpolicies/networkpolicies.go @@ -96,6 +96,16 @@ func (s *networkpoliciesruleWebhook) authorized(request admissionctl.Request) ad } if np.GetNamespace() == "openshift-ingress" { + // Allow privileged service accounts (e.g. redhat-*, openshift-*) to + // manage NetworkPolicies for non-ingress-controller pods deployed in + // this namespace, such as kube-auth-proxy or payload-processing. + for _, group := range request.UserInfo.Groups { + if privilegedServiceAccountGroupsRe.Match([]byte(group)) { + ret = admissionctl.Allowed(fmt.Sprintf("Privileged service accounts in group(s) '%s' can operate on NetworkPolicies in openshift-ingress", strings.Join(request.UserInfo.Groups, ", "))) + ret.UID = request.AdmissionRequest.UID + return ret + } + } ingressName, labelFound := np.Spec.PodSelector.MatchLabels["ingresscontroller.operator.openshift.io/deployment-ingresscontroller"] if !labelFound || ingressName == "default" { ret = admissionctl.Denied(fmt.Sprintf("User '%s' prevented from creating network policy that may impact default ingress, which is managed by Red Hat. This is in an effort to prevent harmful actions that may cause unintended consequences or affect the stability of the cluster. If you have any questions about this, please reach out to Red Hat support at https://access.redhat.com/support", request.UserInfo.Username)) diff --git a/pkg/webhooks/networkpolicies/networkpolicies_test.go b/pkg/webhooks/networkpolicies/networkpolicies_test.go index 8eab8407..4261da98 100644 --- a/pkg/webhooks/networkpolicies/networkpolicies_test.go +++ b/pkg/webhooks/networkpolicies/networkpolicies_test.go @@ -82,6 +82,12 @@ func (t crudTest) redhatServiceAccount() crudTest { return t } +func (t crudTest) rhoaiServiceAccount() crudTest { + t.testData.username = "system:serviceaccount:redhat-ods-operator:redhat-ods-operator-controller-manager" + t.testData.userGroups = []string{"system:serviceaccounts:redhat-ods-operator", "system:authenticated", "system:authenticated:oauth"} + return t +} + func (t crudTest) namespace(namespace string) crudTest { t.testData.targetNamespace = namespace return t @@ -245,5 +251,23 @@ func TestUsers(t *testing.T) { podSelector("ingresscontroller.operator.openshift.io/deployment-ingresscontroller", "custom"). regularUser().shouldBeAllowed()) + // Privileged service accounts (redhat-*, openshift-*) should be allowed + // to create NetworkPolicies in openshift-ingress without the ingress + // controller label. This is needed for operators like RHOAI that deploy + // pods (kube-auth-proxy, payload-processing) into openshift-ingress. + tests = append(tests, newCrudTest("rhoai-sa-openshift-ingress-no-ingress-label"). + namespace("openshift-ingress"). + podSelector("app", "kube-auth-proxy"). + rhoaiServiceAccount().shouldBeAllowedCRUD()...) + tests = append(tests, newCrudTest("privileged-sa-openshift-ingress-no-ingress-label"). + namespace("openshift-ingress"). + podSelector("app", "payload-processing"). + allowedServiceAccount().shouldBeAllowedCRUD()...) + // Unprivileged SAs should still be denied + tests = append(tests, newCrudTest("unprivileged-sa-openshift-ingress-no-ingress-label"). + namespace("openshift-ingress"). + podSelector("app", "some-pod"). + unprivilegedServiceAccount().shouldBeDeniedCRUD()...) + runNetworkPolicyTests(t, tests) }