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) }