Created
June 28, 2024 08:04
-
-
Save iyalang/014d5364b37f09d4ca5ee0507fd4b267 to your computer and use it in GitHub Desktop.
Revisions
-
iyalang created this gist
Jun 28, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,273 @@ --- apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: pdb-validation annotations: policies.kyverno.io/title: Check PodDisruptionBudget minAvailable and maxUnavailable policies.kyverno.io/category: Other policies.kyverno.io/subject: PodDisruptionBudget, Deployment, StatefulSet policies.kyverno.io/description: >- This policy ensures that all PodDisruptionBudgets (PDBs) are configured to allow for some disruptions. spec: validationFailureAction: Enforce background: false rules: # Check if maxUnavailable is > 0 - name: pdb-maxunavailable match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE validate: message: "The value of maxUnavailable must be greater than zero." deny: conditions: any: - key: '{{ request.object.spec.maxUnavailable || "null" }}' operator: Equals value: 0 - key: '{{ request.object.spec.maxUnavailable || "null" }}' operator: Equals value: "0%" # Check if minAvailable != 100% - name: pdb-minavailable-100-percent match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE validate: message: "minAvailable should not be 100% since that prevents all disruptions." deny: conditions: any: - key: '{{ request.object.spec.minAvailable || "none" }}' operator: Equals value: "100%" # Check if minAvailable != the number of Deployment replicas - name: pdb-minavailable-deployments match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE context: - name: replicasDeployment apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/deployments' # This "none":"none" map is added to labels of deployments that have zero labels, # else the rule would fail with "failed to load context: Invalid type" jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.annotations."downscaler/original-replicas" || spec.replicas || "null"' - name: deploymentName apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/deployments' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.name || "null"' - name: hpaCount apiCall: urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers' jmesPath: items[?spec.scaleTargetRef.name=='{{deploymentName}}'] | length(@) validate: message: >- The minAvailable value of the PDB should be lower than the number of replicas of the Deployment or StatefulSet. If your Deployment/StatefulSet has only one replica, please don't create any PDBs for it. deny: conditions: all: - key: '{{ request.object.spec.minAvailable || "0" }}' operator: GreaterThanOrEquals value: '{{ replicasDeployment }}' # Not checking min replicas if there is an HPA because replicas are set there - key: '{{ hpaCount }}' operator: Equals value: 0 # Check if minAvailable != the number of StatefulSet replicas - name: pdb-minavailable-statefulsets match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE context: - name: replicasStatefulSet apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/statefulsets' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.annotations."downscaler/original-replicas" || spec.replicas || "null"' - name: statefulSetName apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/statefulsets' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.name || "null"' - name: hpaCount apiCall: urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers' jmesPath: items[?spec.scaleTargetRef.name=='{{statefulSetName}}'] | length(@) validate: message: >- The minAvailable value of the PDB should be lower than the number of replicas of the Deployment or StatefulSet. If your Deployment/StatefulSet has only one replica, please don't create any PDBs for it. deny: conditions: all: - key: '{{ request.object.spec.minAvailable || "0" }}' operator: GreaterThanOrEquals value: '{{ replicasStatefulSet }}' - key: '{{ hpaCount }}' operator: Equals value: 0 # Check if Deployment has more than 1 replica - name: pdb-minavailable-deployments-one-replica match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE context: - name: replicasDeployment apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/deployments' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.annotations."downscaler/original-replicas" || spec.replicas || "null"' - name: deploymentName apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/deployments' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.name || "null"' - name: hpaCount apiCall: urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers' jmesPath: items[?spec.scaleTargetRef.name=='{{deploymentName}}'] | length(@) validate: message: >- Deployments or StatefulSets that have only 1 replica are not allowed to have PDBs since this would prevent any disruptions. deny: conditions: all: - key: '{{ replicasDeployment }}' operator: Equals value: 1 - key: '{{ hpaCount }}' operator: Equals value: 0 # Check if StatefulSet has more than 1 replica - name: pdb-minavailable-statefulsets-one-replica match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE context: - name: replicasStatefulSet apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/statefulsets' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.annotations."downscaler/original-replicas" || spec.replicas || "null"' - name: statefulSetName apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/statefulsets' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.name || "null"' - name: hpaCount apiCall: urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers' jmesPath: items[?spec.scaleTargetRef.name=='{{statefulSetName}}'] | length(@) validate: message: >- Deployments or StatefulSets that have only 1 replica are not allowed to have PDBs since this would prevent any disruptions. deny: conditions: all: - key: '{{ replicasStatefulSet }}' operator: Equals value: 1 - key: '{{ hpaCount }}' operator: Equals value: 0 # Check if minAvailable != minReplicas in the HPA (if it exists) - name: pdb-minavailable-hpa-deployments match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE context: - name: deploymentName apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/deployments' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.name || "null"' - name: hpaMinReplicasDeployment apiCall: urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers' jmesPath: items[?spec.scaleTargetRef.name=='{{deploymentName}}'] | [0] | metadata.annotations."downscaler/original-replicas" || spec.minReplicas validate: message: >- The HPA for the corresponding Deployment or StatefulSet has its minReplicas equal to the minAvailable value of the PDB which is not permitted. If minReplicas of the HPA equals 1, please don't create any PDBs. deny: conditions: any: - key: '{{ request.object.spec.minAvailable || "0" }}' operator: GreaterThanOrEquals value: '{{ hpaMinReplicasDeployment }}' # Check if minAvailable != minReplicas in the HPA (if it exists) - name: pdb-minavailable-hpa-statefulsets match: any: - resources: kinds: - PodDisruptionBudget preconditions: any: - key: '{{request.operation}}' operator: NotEquals value: DELETE context: - name: statefulSetName apiCall: urlPath: '/apis/apps/v1/namespaces/{{request.namespace}}/statefulsets' jmesPath: 'items[?label_match(`{{request.object.spec.selector.matchLabels}}`, spec.template.metadata.labels || {"none":"none"})] | [0] | metadata.name || "null"' - name: hpaMinReplicasStatefulSet apiCall: urlPath: '/apis/autoscaling/v2/namespaces/{{request.namespace}}/horizontalpodautoscalers' jmesPath: items[?spec.scaleTargetRef.name=='{{statefulSetName}}'] | [0] | metadata.annotations."downscaler/original-replicas" || spec.minReplicas || "null" validate: message: >- The HPA for the corresponding Deployment or StatefulSet has its minReplicas equal to the minAvailable value of the PDB which is not permitted. If minReplicas of the HPA equals 1, please don't create any PDBs. deny: conditions: any: - key: '{{ request.object.spec.minAvailable || "0" }}' operator: GreaterThanOrEquals value: '{{ hpaMinReplicasStatefulSet }}'