diff --git a/docs/content/docs/operations/helm.md b/docs/content/docs/operations/helm.md index c54097059f..fa92242e0f 100644 --- a/docs/content/docs/operations/helm.md +++ b/docs/content/docs/operations/helm.md @@ -109,6 +109,9 @@ The configurable parameters of the Helm chart and which default values as detail | webhook.validator.create | Enable or disable validating webhook, overrides `webhook.create` | | | webhook.keystore | The ConfigMap of webhook key store. | useDefaultPassword: true | | webhook.serviceLabels | The labels for flink-operator-webhook-service-resource. | | +| blueGreenAdmissionPolicy.create | Whether to enable ValidatingAdmissionPolicy for protecting Blue/Green child deployments. | true | +| blueGreenAdmissionPolicy.failurePolicy | What happens if policy evaluation fails (Fail = block requests, Ignore = allow on policy errors). | Fail | +| blueGreenAdmissionPolicy.validationActions | Action to take on validation failures (Deny = block the request). | [Deny] | | defaultConfiguration.create | Whether to enable default configuration to create for flink-kubernetes-operator. | true | | defaultConfiguration.append | Whether to append configuration files with configs. | true | | defaultConfiguration.flink-conf.yaml | The default configuration of flink-conf.yaml. | kubernetes.operator.metrics.reporter.slf4j.factory.class: org.apache.flink.metrics.slf4j.Slf4jReporterFactory
kubernetes.operator.metrics.reporter.slf4j.interval: 5 MINUTE
kubernetes.operator.reconcile.interval: 15 s
kubernetes.operator.observer.progress-check.interval: 5 s | @@ -144,6 +147,10 @@ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1 The webhooks can be disabled during helm install by passing the `--set webhook.create=false` parameter or editing the `values.yaml` directly. +## Blue/Green Admission Policy + +If using `FlinkBlueGreenDeployment`, you should enable a `ValidatingAdmissionPolicy` to protect child FlinkDeployments from direct modifications by passing `--set blueGreenAdmissionPolicy.create=true`. This policy only affects FlinkDeployments owned by a FlinkBlueGreenDeployment, allowing updates only from the operator's service account. Requires Kubernetes 1.26+ (beta) or 1.30+ (GA). When rendering templates with `helm template`, ensure `--namespace` matches where the operator is deployed. + ## Watching only specific namespaces The operator supports watching a specific list of namespaces for FlinkDeployment resources. You can enable it by setting the `--set watchNamespaces={flink-test}` parameter. diff --git a/helm/flink-kubernetes-operator/templates/policies/bluegreen_admission_policy.yaml b/helm/flink-kubernetes-operator/templates/policies/bluegreen_admission_policy.yaml new file mode 100644 index 0000000000..6f30433a90 --- /dev/null +++ b/helm/flink-kubernetes-operator/templates/policies/bluegreen_admission_policy.yaml @@ -0,0 +1,75 @@ +{{/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/}} + +{{/* +ValidatingAdmissionPolicy to prevent direct modifications to FlinkDeployments +that are managed by a FlinkBlueGreenDeployment. + +This policy uses CEL expressions evaluated by the Kubernetes API server directly, +requiring no webhook server. Requires Kubernetes 1.30+ (GA) or 1.26+ (beta with +feature gate enabled). + +When a user tries to UPDATE a FlinkDeployment that has an ownerReference to a +FlinkBlueGreenDeployment, the request is denied unless it comes from the +operator's service account. +*/}} + +{{- if .Values.blueGreenAdmissionPolicy.create }} +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: {{ include "flink-operator.name" . }}-block-bluegreen-direct-updates + labels: + {{- include "flink-operator.labels" . | nindent 4 }} +spec: + failurePolicy: {{ .Values.blueGreenAdmissionPolicy.failurePolicy | default "Fail" }} + matchConstraints: + resourceRules: + - apiGroups: ["flink.apache.org"] + apiVersions: ["*"] + operations: ["UPDATE"] + resources: ["flinkdeployments"] + validations: + - expression: | + !has(object.metadata.ownerReferences) || + !object.metadata.ownerReferences.exists(ref, ref.kind == 'FlinkBlueGreenDeployment') || + request.userInfo.username == 'system:serviceaccount:{{ .Release.Namespace }}:{{ include "flink-operator.serviceAccountName" . }}' + message: >- + FlinkDeployments managed by FlinkBlueGreenDeployment cannot be modified directly. + Please update the parent FlinkBlueGreenDeployment instead. + reason: Forbidden + +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: {{ include "flink-operator.name" . }}-block-bluegreen-direct-updates-binding + labels: + {{- include "flink-operator.labels" . | nindent 4 }} +spec: + policyName: {{ include "flink-operator.name" . }}-block-bluegreen-direct-updates + validationActions: + {{- toYaml .Values.blueGreenAdmissionPolicy.validationActions | nindent 4 }} + {{- with .Values.blueGreenAdmissionPolicy.matchResources }} + matchResources: + {{- toYaml . | nindent 4 }} + {{- else }} + matchResources: {} + {{- end }} +{{- end }} + diff --git a/helm/flink-kubernetes-operator/tests/policies/bluegreen_admission_policy_test.yaml b/helm/flink-kubernetes-operator/tests/policies/bluegreen_admission_policy_test.yaml new file mode 100644 index 0000000000..55b45f240c --- /dev/null +++ b/helm/flink-kubernetes-operator/tests/policies/bluegreen_admission_policy_test.yaml @@ -0,0 +1,140 @@ +################################################################################ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# limitations under the License. +################################################################################ + +suite: Test BlueGreen ValidatingAdmissionPolicy + +templates: +- policies/bluegreen_admission_policy.yaml + +release: + name: flink-operator + namespace: flink-operator + +tests: +- it: Should not create admission policy if `blueGreenAdmissionPolicy.create` is `false` + set: + blueGreenAdmissionPolicy: + create: false + asserts: + - hasDocuments: + count: 0 + +- it: Should create ValidatingAdmissionPolicy and binding if `blueGreenAdmissionPolicy.create` is `true` + set: + blueGreenAdmissionPolicy: + create: true + failurePolicy: Fail + validationActions: + - Deny + asserts: + - hasDocuments: + count: 2 + - containsDocument: + apiVersion: admissionregistration.k8s.io/v1 + kind: ValidatingAdmissionPolicy + name: flink-kubernetes-operator-block-bluegreen-direct-updates + - containsDocument: + apiVersion: admissionregistration.k8s.io/v1 + kind: ValidatingAdmissionPolicyBinding + name: flink-kubernetes-operator-block-bluegreen-direct-updates-binding + +- it: Should have correct CEL expression in policy + set: + blueGreenAdmissionPolicy: + create: true + failurePolicy: Fail + validationActions: + - Deny + asserts: + - equal: + path: spec.validations[0].expression + value: | + !has(object.metadata.ownerReferences) || + !object.metadata.ownerReferences.exists(ref, ref.kind == 'FlinkBlueGreenDeployment') || + request.userInfo.username == 'system:serviceaccount:flink-operator:flink-operator' + documentIndex: 0 + +- it: Should set correct failurePolicy + set: + blueGreenAdmissionPolicy: + create: true + failurePolicy: Ignore + validationActions: + - Deny + asserts: + - equal: + path: spec.failurePolicy + value: Ignore + documentIndex: 0 + +- it: Should set correct validationActions in binding + set: + blueGreenAdmissionPolicy: + create: true + failurePolicy: Fail + validationActions: + - Deny + asserts: + - equal: + path: spec.validationActions + value: + - Deny + documentIndex: 1 + +- it: Should only match UPDATE operations on flinkdeployments + set: + blueGreenAdmissionPolicy: + create: true + failurePolicy: Fail + validationActions: + - Deny + asserts: + - equal: + path: spec.matchConstraints.resourceRules[0].apiGroups + value: + - flink.apache.org + documentIndex: 0 + - equal: + path: spec.matchConstraints.resourceRules[0].operations + value: + - UPDATE + documentIndex: 0 + - equal: + path: spec.matchConstraints.resourceRules[0].resources + value: + - flinkdeployments + documentIndex: 0 + +- it: Should use custom service account name in CEL expression + set: + blueGreenAdmissionPolicy: + create: true + failurePolicy: Fail + validationActions: + - Deny + operatorServiceAccount: + create: true + name: "custom-operator-sa" + asserts: + - equal: + path: spec.validations[0].expression + value: | + !has(object.metadata.ownerReferences) || + !object.metadata.ownerReferences.exists(ref, ref.kind == 'FlinkBlueGreenDeployment') || + request.userInfo.username == 'system:serviceaccount:flink-operator:custom-operator-sa' + documentIndex: 0 + diff --git a/helm/flink-kubernetes-operator/values.yaml b/helm/flink-kubernetes-operator/values.yaml index 497bcc7122..9821e4f41d 100644 --- a/helm/flink-kubernetes-operator/values.yaml +++ b/helm/flink-kubernetes-operator/values.yaml @@ -159,6 +159,16 @@ webhook: # key: password-key serviceLabels: {} +# ValidatingAdmissionPolicy to protect child FlinkDeployments from direct modifications +# Uses Kubernetes native ValidatingAdmissionPolicy (requires K8s 1.30+ or 1.26+ with feature gate) +# This is NOT a webhook - it's evaluated directly by the K8s API server +# Enable this if using FlinkBlueGreenDeployment to prevent direct edits to child resources +blueGreenAdmissionPolicy: + create: false + failurePolicy: Fail + validationActions: + - Deny + defaultConfiguration: # If set to true, creates ConfigMaps/VolumeMounts. If set to false, no configuration will be created. # All below fields will be ignored if create is set to false.