From 313e11a5b076f37f422c28dc61edc14c67387d05 Mon Sep 17 00:00:00 2001 From: DaliborD45 Date: Sat, 22 Aug 2026 10:51:45 +0200 Subject: [PATCH 1/3] feat: created VAP that blocks authorino.spec.image and limits authorino.spec.clusterWide Signed-off-by: DaliborD45 --- Makefile | 7 ++++ .../templates/manifests.yaml | 42 +++++++++++++++++++ config/deploy/manifests.yaml | 42 +++++++++++++++++++ config/install/manifests.yaml | 42 +++++++++++++++++++ config/vap/kustomization.yaml | 5 +++ config/vap/validating_admission_policy.yaml | 26 ++++++++++++ .../validating_admission_policy_binding.yaml | 7 ++++ make/helm.mk | 3 ++ 8 files changed, 174 insertions(+) create mode 100644 config/vap/kustomization.yaml create mode 100644 config/vap/validating_admission_policy.yaml create mode 100644 config/vap/validating_admission_policy_binding.yaml diff --git a/Makefile b/Makefile index ec998391..c97f4938 100644 --- a/Makefile +++ b/Makefile @@ -219,6 +219,10 @@ CERT_MANAGER_VERSION ?= 1.12.1 manifests: controller-gen kustomize authorino-manifests ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) crd rbac:roleName=authorino-operator-manager webhook paths="./..." output:crd:artifacts:config=config/crd/bases && $(KUSTOMIZE) build config/install > $(OPERATOR_MANIFESTS) + # ValidatingAdmissionPolicy/Binding are cluster-scoped. Build them on their own (no namespace + # overlay) and append, so this kustomize version does not stamp a namespace on them. + printf '%s\n' '---' >> $(OPERATOR_MANIFESTS) + $(KUSTOMIZE) build config/vap >> $(OPERATOR_MANIFESTS) $(MAKE) deploy-manifest OPERATOR_IMAGE=$(OPERATOR_IMAGE) .PHONY: authorino-manifests @@ -314,6 +318,9 @@ deploy-manifest: kustomize mkdir -p $(DEPLOYMENT_DIR) cd $(PROJECT_DIR)/config/manager && $(KUSTOMIZE) edit set image controller=$(OPERATOR_IMAGE) ;\ cd $(PROJECT_DIR) && $(KUSTOMIZE) build config/deploy > $(DEPLOYMENT_FILE) + # ValidatingAdmissionPolicy/Binding are cluster-scoped; build separately (no namespace) and append. + printf '%s\n' '---' >> $(DEPLOYMENT_FILE) + $(KUSTOMIZE) build config/vap >> $(DEPLOYMENT_FILE) # clean up cd $(PROJECT_DIR)/config/manager && $(KUSTOMIZE) edit set image controller=${DEFAULT_OPERATOR_IMAGE} diff --git a/charts/authorino-operator/templates/manifests.yaml b/charts/authorino-operator/templates/manifests.yaml index 4a564ead..162a50c6 100644 --- a/charts/authorino-operator/templates/manifests.yaml +++ b/charts/authorino-operator/templates/manifests.yaml @@ -3858,3 +3858,45 @@ spec: runAsNonRoot: true serviceAccountName: authorino-operator terminationGracePeriodSeconds: 10 +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: authorino-restrict-spec-fields +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - operator.authorino.kuadrant.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - authorinos + validations: + - expression: '!has(object.spec.image) || object.spec.image == ''''' + message: spec.image is not allowed; the Authorino image is controlled by the operator + reason: Invalid + - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator' + message: 'spec.clusterWide: true can only be set by the Kuadrant operator' + reason: Invalid + variables: + - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' + name: isKuadrantOperator + - expression: has(object.spec.clusterWide) && object.spec.clusterWide + name: wantsClusterWide + - expression: request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && + oldObject.spec.clusterWide + name: wasClusterWide +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: authorino-restrict-spec-fields-binding +spec: + policyName: authorino-restrict-spec-fields + validationActions: + - Deny diff --git a/config/deploy/manifests.yaml b/config/deploy/manifests.yaml index 612bf1a4..499ff897 100644 --- a/config/deploy/manifests.yaml +++ b/config/deploy/manifests.yaml @@ -3865,3 +3865,45 @@ spec: runAsNonRoot: true serviceAccountName: authorino-operator terminationGracePeriodSeconds: 10 +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: authorino-restrict-spec-fields +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - operator.authorino.kuadrant.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - authorinos + validations: + - expression: '!has(object.spec.image) || object.spec.image == ''''' + message: spec.image is not allowed; the Authorino image is controlled by the operator + reason: Invalid + - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator' + message: 'spec.clusterWide: true can only be set by the Kuadrant operator' + reason: Invalid + variables: + - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' + name: isKuadrantOperator + - expression: has(object.spec.clusterWide) && object.spec.clusterWide + name: wantsClusterWide + - expression: request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && + oldObject.spec.clusterWide + name: wasClusterWide +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: authorino-restrict-spec-fields-binding +spec: + policyName: authorino-restrict-spec-fields + validationActions: + - Deny diff --git a/config/install/manifests.yaml b/config/install/manifests.yaml index 03039a9d..cb939d8e 100644 --- a/config/install/manifests.yaml +++ b/config/install/manifests.yaml @@ -544,3 +544,45 @@ subjects: - kind: ServiceAccount name: authorino-operator namespace: authorino-operator +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: authorino-restrict-spec-fields +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - operator.authorino.kuadrant.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - authorinos + validations: + - expression: '!has(object.spec.image) || object.spec.image == ''''' + message: spec.image is not allowed; the Authorino image is controlled by the operator + reason: Invalid + - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator' + message: 'spec.clusterWide: true can only be set by the Kuadrant operator' + reason: Invalid + variables: + - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' + name: isKuadrantOperator + - expression: has(object.spec.clusterWide) && object.spec.clusterWide + name: wantsClusterWide + - expression: request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && + oldObject.spec.clusterWide + name: wasClusterWide +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: authorino-restrict-spec-fields-binding +spec: + policyName: authorino-restrict-spec-fields + validationActions: + - Deny diff --git a/config/vap/kustomization.yaml b/config/vap/kustomization.yaml new file mode 100644 index 00000000..eeb02281 --- /dev/null +++ b/config/vap/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - validating_admission_policy.yaml + - validating_admission_policy_binding.yaml diff --git a/config/vap/validating_admission_policy.yaml b/config/vap/validating_admission_policy.yaml new file mode 100644 index 00000000..c5b6a87c --- /dev/null +++ b/config/vap/validating_admission_policy.yaml @@ -0,0 +1,26 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: authorino-restrict-spec-fields +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: ["operator.authorino.kuadrant.io"] + apiVersions: ["v1beta1"] + operations: ["CREATE", "UPDATE"] + resources: ["authorinos"] + variables: + - name: isKuadrantOperator + expression: "request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager'" + - name: wantsClusterWide + expression: "has(object.spec.clusterWide) && object.spec.clusterWide" + - name: wasClusterWide + expression: "request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && oldObject.spec.clusterWide" + validations: + - expression: "!has(object.spec.image) || object.spec.image == ''" + message: "spec.image is not allowed; the Authorino image is controlled by the operator" + reason: Invalid + - expression: "!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator" + message: "spec.clusterWide: true can only be set by the Kuadrant operator" + reason: Invalid diff --git a/config/vap/validating_admission_policy_binding.yaml b/config/vap/validating_admission_policy_binding.yaml new file mode 100644 index 00000000..5f248d37 --- /dev/null +++ b/config/vap/validating_admission_policy_binding.yaml @@ -0,0 +1,7 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: authorino-restrict-spec-fields-binding +spec: + policyName: authorino-restrict-spec-fields + validationActions: ["Deny"] diff --git a/make/helm.mk b/make/helm.mk index ea145c9e..e205d0b5 100644 --- a/make/helm.mk +++ b/make/helm.mk @@ -15,6 +15,9 @@ helm-build: yq kustomize manifests ## Build the helm chart from kustomize manife cd config/manager && $(KUSTOMIZE) edit set image controller=$(OPERATOR_IMAGE) # Build the helm chart templates from kustomize manifests $(KUSTOMIZE) build config/helm > $(CHART_DIRECTORY)/templates/manifests.yaml + # ValidatingAdmissionPolicy/Binding are cluster-scoped; build separately (no namespace) and append. + printf '%s\n' '---' >> $(CHART_DIRECTORY)/templates/manifests.yaml + $(KUSTOMIZE) build config/vap >> $(CHART_DIRECTORY)/templates/manifests.yaml V="$(BUNDLE_VERSION)" $(YQ) -i e '.version = strenv(V)' $(CHART_DIRECTORY)/Chart.yaml V="$(BUNDLE_VERSION)" $(YQ) -i e '.appVersion = strenv(V)' $(CHART_DIRECTORY)/Chart.yaml # Roll back edit From d095fc30f0b0a8b9a0136271df0b9b107f03543e Mon Sep 17 00:00:00 2001 From: DaliborD45 Date: Sat, 22 Aug 2026 11:34:33 +0200 Subject: [PATCH 2/3] feat: refactored VAP file structure, created new one restricting to read secrets from all namespaces Signed-off-by: DaliborD45 --- .../templates/manifests.yaml | 46 +++++++++++++++++++ config/deploy/manifests.yaml | 46 +++++++++++++++++++ config/install/manifests.yaml | 46 +++++++++++++++++++ config/vap/kustomization.yaml | 4 +- config/vap/restrict-all-namespaces.yaml | 31 +++++++++++++ ..._policy.yaml => restrict-spec-fields.yaml} | 8 ++++ .../validating_admission_policy_binding.yaml | 7 --- 7 files changed, 179 insertions(+), 9 deletions(-) create mode 100644 config/vap/restrict-all-namespaces.yaml rename config/vap/{validating_admission_policy.yaml => restrict-spec-fields.yaml} (84%) delete mode 100644 config/vap/validating_admission_policy_binding.yaml diff --git a/charts/authorino-operator/templates/manifests.yaml b/charts/authorino-operator/templates/manifests.yaml index 162a50c6..a0d0cb6d 100644 --- a/charts/authorino-operator/templates/manifests.yaml +++ b/charts/authorino-operator/templates/manifests.yaml @@ -3861,6 +3861,43 @@ spec: --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy +metadata: + name: authconfig-restrict-allnamespaces +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - authorino.kuadrant.io + apiVersions: + - v1beta3 + operations: + - CREATE + - UPDATE + resources: + - authconfigs + validations: + - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator' + message: 'allNamespaces: true (cluster-wide secret lookup) can only be set by + the Kuadrant operator' + reason: Forbidden + variables: + - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' + name: isKuadrantOperator + - expression: has(object.spec.authentication) && object.spec.authentication.exists(k, + (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) + && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) + && has(object.spec.authentication[k].x509.allNamespaces) && object.spec.authentication[k].x509.allNamespaces)) + name: wantsAllNamespaces + - expression: request.operation == 'UPDATE' && has(oldObject.spec.authentication) + && oldObject.spec.authentication.exists(k, (has(oldObject.spec.authentication[k].apiKey) + && has(oldObject.spec.authentication[k].apiKey.allNamespaces) && oldObject.spec.authentication[k].apiKey.allNamespaces) + || (has(oldObject.spec.authentication[k].x509) && has(oldObject.spec.authentication[k].x509.allNamespaces) + && oldObject.spec.authentication[k].x509.allNamespaces)) + name: wasAllNamespaces +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy metadata: name: authorino-restrict-spec-fields spec: @@ -3894,6 +3931,15 @@ spec: --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding +metadata: + name: authconfig-restrict-allnamespaces-binding +spec: + policyName: authconfig-restrict-allnamespaces + validationActions: + - Deny +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding metadata: name: authorino-restrict-spec-fields-binding spec: diff --git a/config/deploy/manifests.yaml b/config/deploy/manifests.yaml index 499ff897..1a80beaf 100644 --- a/config/deploy/manifests.yaml +++ b/config/deploy/manifests.yaml @@ -3868,6 +3868,43 @@ spec: --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy +metadata: + name: authconfig-restrict-allnamespaces +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - authorino.kuadrant.io + apiVersions: + - v1beta3 + operations: + - CREATE + - UPDATE + resources: + - authconfigs + validations: + - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator' + message: 'allNamespaces: true (cluster-wide secret lookup) can only be set by + the Kuadrant operator' + reason: Forbidden + variables: + - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' + name: isKuadrantOperator + - expression: has(object.spec.authentication) && object.spec.authentication.exists(k, + (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) + && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) + && has(object.spec.authentication[k].x509.allNamespaces) && object.spec.authentication[k].x509.allNamespaces)) + name: wantsAllNamespaces + - expression: request.operation == 'UPDATE' && has(oldObject.spec.authentication) + && oldObject.spec.authentication.exists(k, (has(oldObject.spec.authentication[k].apiKey) + && has(oldObject.spec.authentication[k].apiKey.allNamespaces) && oldObject.spec.authentication[k].apiKey.allNamespaces) + || (has(oldObject.spec.authentication[k].x509) && has(oldObject.spec.authentication[k].x509.allNamespaces) + && oldObject.spec.authentication[k].x509.allNamespaces)) + name: wasAllNamespaces +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy metadata: name: authorino-restrict-spec-fields spec: @@ -3901,6 +3938,15 @@ spec: --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding +metadata: + name: authconfig-restrict-allnamespaces-binding +spec: + policyName: authconfig-restrict-allnamespaces + validationActions: + - Deny +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding metadata: name: authorino-restrict-spec-fields-binding spec: diff --git a/config/install/manifests.yaml b/config/install/manifests.yaml index cb939d8e..e4fb84ed 100644 --- a/config/install/manifests.yaml +++ b/config/install/manifests.yaml @@ -547,6 +547,43 @@ subjects: --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy +metadata: + name: authconfig-restrict-allnamespaces +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - authorino.kuadrant.io + apiVersions: + - v1beta3 + operations: + - CREATE + - UPDATE + resources: + - authconfigs + validations: + - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator' + message: 'allNamespaces: true (cluster-wide secret lookup) can only be set by + the Kuadrant operator' + reason: Forbidden + variables: + - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' + name: isKuadrantOperator + - expression: has(object.spec.authentication) && object.spec.authentication.exists(k, + (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) + && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) + && has(object.spec.authentication[k].x509.allNamespaces) && object.spec.authentication[k].x509.allNamespaces)) + name: wantsAllNamespaces + - expression: request.operation == 'UPDATE' && has(oldObject.spec.authentication) + && oldObject.spec.authentication.exists(k, (has(oldObject.spec.authentication[k].apiKey) + && has(oldObject.spec.authentication[k].apiKey.allNamespaces) && oldObject.spec.authentication[k].apiKey.allNamespaces) + || (has(oldObject.spec.authentication[k].x509) && has(oldObject.spec.authentication[k].x509.allNamespaces) + && oldObject.spec.authentication[k].x509.allNamespaces)) + name: wasAllNamespaces +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy metadata: name: authorino-restrict-spec-fields spec: @@ -580,6 +617,15 @@ spec: --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding +metadata: + name: authconfig-restrict-allnamespaces-binding +spec: + policyName: authconfig-restrict-allnamespaces + validationActions: + - Deny +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding metadata: name: authorino-restrict-spec-fields-binding spec: diff --git a/config/vap/kustomization.yaml b/config/vap/kustomization.yaml index eeb02281..5123cacc 100644 --- a/config/vap/kustomization.yaml +++ b/config/vap/kustomization.yaml @@ -1,5 +1,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - validating_admission_policy.yaml - - validating_admission_policy_binding.yaml + - restrict-spec-fields.yaml + - restrict-all-namespaces.yaml diff --git a/config/vap/restrict-all-namespaces.yaml b/config/vap/restrict-all-namespaces.yaml new file mode 100644 index 00000000..b5e03c52 --- /dev/null +++ b/config/vap/restrict-all-namespaces.yaml @@ -0,0 +1,31 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: authconfig-restrict-all-namespaces +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: ["authorino.kuadrant.io"] + apiVersions: ["v1beta3"] + operations: ["CREATE", "UPDATE"] + resources: ["authconfigs"] + variables: + - name: isKuadrantOperator + expression: "request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager'" + - name: wantsAllNamespaces + expression: "has(object.spec.authentication) && object.spec.authentication.exists(k, (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) && has(object.spec.authentication[k].x509.allNamespaces) && object.spec.authentication[k].x509.allNamespaces))" + - name: wasAllNamespaces + expression: "request.operation == 'UPDATE' && has(oldObject.spec.authentication) && oldObject.spec.authentication.exists(k, (has(oldObject.spec.authentication[k].apiKey) && has(oldObject.spec.authentication[k].apiKey.allNamespaces) && oldObject.spec.authentication[k].apiKey.allNamespaces) || (has(oldObject.spec.authentication[k].x509) && has(oldObject.spec.authentication[k].x509.allNamespaces) && oldObject.spec.authentication[k].x509.allNamespaces))" + validations: + - expression: "!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator" + message: "allNamespaces: true (cluster-wide secret lookup) can only be set by the Kuadrant operator" + reason: Forbidden +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: authconfig-restrict-all-namespaces-binding +spec: + policyName: authconfig-restrict-all-namespaces + validationActions: ["Deny"] diff --git a/config/vap/validating_admission_policy.yaml b/config/vap/restrict-spec-fields.yaml similarity index 84% rename from config/vap/validating_admission_policy.yaml rename to config/vap/restrict-spec-fields.yaml index c5b6a87c..98f66370 100644 --- a/config/vap/validating_admission_policy.yaml +++ b/config/vap/restrict-spec-fields.yaml @@ -24,3 +24,11 @@ spec: - expression: "!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator" message: "spec.clusterWide: true can only be set by the Kuadrant operator" reason: Invalid +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: authorino-restrict-spec-fields-binding +spec: + policyName: authorino-restrict-spec-fields + validationActions: ["Deny"] diff --git a/config/vap/validating_admission_policy_binding.yaml b/config/vap/validating_admission_policy_binding.yaml deleted file mode 100644 index 5f248d37..00000000 --- a/config/vap/validating_admission_policy_binding.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingAdmissionPolicyBinding -metadata: - name: authorino-restrict-spec-fields-binding -spec: - policyName: authorino-restrict-spec-fields - validationActions: ["Deny"] From 5938b841879a3867a22c333a25cd337310a99190 Mon Sep 17 00:00:00 2001 From: DaliborD45 Date: Mon, 24 Aug 2026 13:10:59 +0200 Subject: [PATCH 3/3] feat: permissions on action is now granted by a cluster role Signed-off-by: DaliborD45 --- .../templates/manifests.yaml | 47 ++++++++++++++----- config/deploy/manifests.yaml | 47 ++++++++++++++----- config/install/manifests.yaml | 47 ++++++++++++++----- config/vap/kustomization.yaml | 2 + config/vap/restrict-all-namespaces.yaml | 8 ++-- config/vap/restrict-spec-fields.yaml | 8 ++-- config/vap/set-cluster-wide-role.yaml | 8 ++++ config/vap/set-privileged-fields-role.yaml | 8 ++++ 8 files changed, 134 insertions(+), 41 deletions(-) create mode 100644 config/vap/set-cluster-wide-role.yaml create mode 100644 config/vap/set-privileged-fields-role.yaml diff --git a/charts/authorino-operator/templates/manifests.yaml b/charts/authorino-operator/templates/manifests.yaml index a0d0cb6d..594925fd 100644 --- a/charts/authorino-operator/templates/manifests.yaml +++ b/charts/authorino-operator/templates/manifests.yaml @@ -3859,10 +3859,34 @@ spec: serviceAccountName: authorino-operator terminationGracePeriodSeconds: 10 --- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-cluster-wide +rules: +- apiGroups: + - operator.authorino.kuadrant.io + resources: + - authorinos + verbs: + - set-cluster-wide +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-privileged-fields +rules: +- apiGroups: + - authorino.kuadrant.io + resources: + - authconfigs + verbs: + - set-privileged-fields +--- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: - name: authconfig-restrict-allnamespaces + name: authconfig-restrict-all-namespaces spec: failurePolicy: Fail matchConstraints: @@ -3877,13 +3901,13 @@ spec: resources: - authconfigs validations: - - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator' + - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isExempt' message: 'allNamespaces: true (cluster-wide secret lookup) can only be set by - the Kuadrant operator' + a subject granted the ''set-privileged-fields'' permission on authconfigs' reason: Forbidden variables: - - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' - name: isKuadrantOperator + - expression: authorizer.requestResource.check('set-privileged-fields').allowed() + name: isExempt - expression: has(object.spec.authentication) && object.spec.authentication.exists(k, (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) @@ -3917,12 +3941,13 @@ spec: - expression: '!has(object.spec.image) || object.spec.image == ''''' message: spec.image is not allowed; the Authorino image is controlled by the operator reason: Invalid - - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator' - message: 'spec.clusterWide: true can only be set by the Kuadrant operator' + - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isExempt' + message: 'spec.clusterWide: true can only be set by a subject granted the ''set-cluster-wide'' + permission on authorinos' reason: Invalid variables: - - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' - name: isKuadrantOperator + - expression: authorizer.requestResource.check('set-cluster-wide').allowed() + name: isExempt - expression: has(object.spec.clusterWide) && object.spec.clusterWide name: wantsClusterWide - expression: request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && @@ -3932,9 +3957,9 @@ spec: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: - name: authconfig-restrict-allnamespaces-binding + name: authconfig-restrict-all-namespaces-binding spec: - policyName: authconfig-restrict-allnamespaces + policyName: authconfig-restrict-all-namespaces validationActions: - Deny --- diff --git a/config/deploy/manifests.yaml b/config/deploy/manifests.yaml index 1a80beaf..158b45f2 100644 --- a/config/deploy/manifests.yaml +++ b/config/deploy/manifests.yaml @@ -3866,10 +3866,34 @@ spec: serviceAccountName: authorino-operator terminationGracePeriodSeconds: 10 --- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-cluster-wide +rules: +- apiGroups: + - operator.authorino.kuadrant.io + resources: + - authorinos + verbs: + - set-cluster-wide +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-privileged-fields +rules: +- apiGroups: + - authorino.kuadrant.io + resources: + - authconfigs + verbs: + - set-privileged-fields +--- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: - name: authconfig-restrict-allnamespaces + name: authconfig-restrict-all-namespaces spec: failurePolicy: Fail matchConstraints: @@ -3884,13 +3908,13 @@ spec: resources: - authconfigs validations: - - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator' + - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isExempt' message: 'allNamespaces: true (cluster-wide secret lookup) can only be set by - the Kuadrant operator' + a subject granted the ''set-privileged-fields'' permission on authconfigs' reason: Forbidden variables: - - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' - name: isKuadrantOperator + - expression: authorizer.requestResource.check('set-privileged-fields').allowed() + name: isExempt - expression: has(object.spec.authentication) && object.spec.authentication.exists(k, (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) @@ -3924,12 +3948,13 @@ spec: - expression: '!has(object.spec.image) || object.spec.image == ''''' message: spec.image is not allowed; the Authorino image is controlled by the operator reason: Invalid - - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator' - message: 'spec.clusterWide: true can only be set by the Kuadrant operator' + - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isExempt' + message: 'spec.clusterWide: true can only be set by a subject granted the ''set-cluster-wide'' + permission on authorinos' reason: Invalid variables: - - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' - name: isKuadrantOperator + - expression: authorizer.requestResource.check('set-cluster-wide').allowed() + name: isExempt - expression: has(object.spec.clusterWide) && object.spec.clusterWide name: wantsClusterWide - expression: request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && @@ -3939,9 +3964,9 @@ spec: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: - name: authconfig-restrict-allnamespaces-binding + name: authconfig-restrict-all-namespaces-binding spec: - policyName: authconfig-restrict-allnamespaces + policyName: authconfig-restrict-all-namespaces validationActions: - Deny --- diff --git a/config/install/manifests.yaml b/config/install/manifests.yaml index e4fb84ed..6c82c757 100644 --- a/config/install/manifests.yaml +++ b/config/install/manifests.yaml @@ -545,10 +545,34 @@ subjects: name: authorino-operator namespace: authorino-operator --- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-cluster-wide +rules: +- apiGroups: + - operator.authorino.kuadrant.io + resources: + - authorinos + verbs: + - set-cluster-wide +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-privileged-fields +rules: +- apiGroups: + - authorino.kuadrant.io + resources: + - authconfigs + verbs: + - set-privileged-fields +--- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicy metadata: - name: authconfig-restrict-allnamespaces + name: authconfig-restrict-all-namespaces spec: failurePolicy: Fail matchConstraints: @@ -563,13 +587,13 @@ spec: resources: - authconfigs validations: - - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator' + - expression: '!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isExempt' message: 'allNamespaces: true (cluster-wide secret lookup) can only be set by - the Kuadrant operator' + a subject granted the ''set-privileged-fields'' permission on authconfigs' reason: Forbidden variables: - - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' - name: isKuadrantOperator + - expression: authorizer.requestResource.check('set-privileged-fields').allowed() + name: isExempt - expression: has(object.spec.authentication) && object.spec.authentication.exists(k, (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) @@ -603,12 +627,13 @@ spec: - expression: '!has(object.spec.image) || object.spec.image == ''''' message: spec.image is not allowed; the Authorino image is controlled by the operator reason: Invalid - - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator' - message: 'spec.clusterWide: true can only be set by the Kuadrant operator' + - expression: '!variables.wantsClusterWide || variables.wasClusterWide || variables.isExempt' + message: 'spec.clusterWide: true can only be set by a subject granted the ''set-cluster-wide'' + permission on authorinos' reason: Invalid variables: - - expression: request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager' - name: isKuadrantOperator + - expression: authorizer.requestResource.check('set-cluster-wide').allowed() + name: isExempt - expression: has(object.spec.clusterWide) && object.spec.clusterWide name: wantsClusterWide - expression: request.operation == 'UPDATE' && has(oldObject.spec.clusterWide) && @@ -618,9 +643,9 @@ spec: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingAdmissionPolicyBinding metadata: - name: authconfig-restrict-allnamespaces-binding + name: authconfig-restrict-all-namespaces-binding spec: - policyName: authconfig-restrict-allnamespaces + policyName: authconfig-restrict-all-namespaces validationActions: - Deny --- diff --git a/config/vap/kustomization.yaml b/config/vap/kustomization.yaml index 5123cacc..5a110bbc 100644 --- a/config/vap/kustomization.yaml +++ b/config/vap/kustomization.yaml @@ -3,3 +3,5 @@ kind: Kustomization resources: - restrict-spec-fields.yaml - restrict-all-namespaces.yaml + - set-privileged-fields-role.yaml + - set-cluster-wide-role.yaml diff --git a/config/vap/restrict-all-namespaces.yaml b/config/vap/restrict-all-namespaces.yaml index b5e03c52..1e4b153e 100644 --- a/config/vap/restrict-all-namespaces.yaml +++ b/config/vap/restrict-all-namespaces.yaml @@ -11,15 +11,15 @@ spec: operations: ["CREATE", "UPDATE"] resources: ["authconfigs"] variables: - - name: isKuadrantOperator - expression: "request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager'" + - name: isExempt + expression: "authorizer.requestResource.check('set-privileged-fields').allowed()" - name: wantsAllNamespaces expression: "has(object.spec.authentication) && object.spec.authentication.exists(k, (has(object.spec.authentication[k].apiKey) && has(object.spec.authentication[k].apiKey.allNamespaces) && object.spec.authentication[k].apiKey.allNamespaces) || (has(object.spec.authentication[k].x509) && has(object.spec.authentication[k].x509.allNamespaces) && object.spec.authentication[k].x509.allNamespaces))" - name: wasAllNamespaces expression: "request.operation == 'UPDATE' && has(oldObject.spec.authentication) && oldObject.spec.authentication.exists(k, (has(oldObject.spec.authentication[k].apiKey) && has(oldObject.spec.authentication[k].apiKey.allNamespaces) && oldObject.spec.authentication[k].apiKey.allNamespaces) || (has(oldObject.spec.authentication[k].x509) && has(oldObject.spec.authentication[k].x509.allNamespaces) && oldObject.spec.authentication[k].x509.allNamespaces))" validations: - - expression: "!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isKuadrantOperator" - message: "allNamespaces: true (cluster-wide secret lookup) can only be set by the Kuadrant operator" + - expression: "!variables.wantsAllNamespaces || variables.wasAllNamespaces || variables.isExempt" + message: "allNamespaces: true (cluster-wide secret lookup) can only be set by a subject granted the 'set-privileged-fields' permission on authconfigs" reason: Forbidden --- apiVersion: admissionregistration.k8s.io/v1 diff --git a/config/vap/restrict-spec-fields.yaml b/config/vap/restrict-spec-fields.yaml index 98f66370..8f908022 100644 --- a/config/vap/restrict-spec-fields.yaml +++ b/config/vap/restrict-spec-fields.yaml @@ -11,8 +11,8 @@ spec: operations: ["CREATE", "UPDATE"] resources: ["authorinos"] variables: - - name: isKuadrantOperator - expression: "request.userInfo.username == 'system:serviceaccount:kuadrant-system:kuadrant-operator-controller-manager'" + - name: isExempt + expression: "authorizer.requestResource.check('set-cluster-wide').allowed()" - name: wantsClusterWide expression: "has(object.spec.clusterWide) && object.spec.clusterWide" - name: wasClusterWide @@ -21,8 +21,8 @@ spec: - expression: "!has(object.spec.image) || object.spec.image == ''" message: "spec.image is not allowed; the Authorino image is controlled by the operator" reason: Invalid - - expression: "!variables.wantsClusterWide || variables.wasClusterWide || variables.isKuadrantOperator" - message: "spec.clusterWide: true can only be set by the Kuadrant operator" + - expression: "!variables.wantsClusterWide || variables.wasClusterWide || variables.isExempt" + message: "spec.clusterWide: true can only be set by a subject granted the 'set-cluster-wide' permission on authorinos" reason: Invalid --- apiVersion: admissionregistration.k8s.io/v1 diff --git a/config/vap/set-cluster-wide-role.yaml b/config/vap/set-cluster-wide-role.yaml new file mode 100644 index 00000000..f7b7a915 --- /dev/null +++ b/config/vap/set-cluster-wide-role.yaml @@ -0,0 +1,8 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-cluster-wide +rules: + - apiGroups: ["operator.authorino.kuadrant.io"] + resources: ["authorinos"] + verbs: ["set-cluster-wide"] diff --git a/config/vap/set-privileged-fields-role.yaml b/config/vap/set-privileged-fields-role.yaml new file mode 100644 index 00000000..4e9afff6 --- /dev/null +++ b/config/vap/set-privileged-fields-role.yaml @@ -0,0 +1,8 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: authorino-set-privileged-fields +rules: + - apiGroups: ["authorino.kuadrant.io"] + resources: ["authconfigs"] + verbs: ["set-privileged-fields"]