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.