Repository: datreeio/datree
Pull request #874 (2023-01-26 15:09:40)

feat: add deprecation policy and rules


Patch:
diff --git a/pkg/defaultPolicies/defaultPolicies.yaml b/pkg/defaultPolicies/defaultPolicies.yaml
index fe91781..76758ee 100644
--- a/pkg/defaultPolicies/defaultPolicies.yaml
+++ b/pkg/defaultPolicies/defaultPolicies.yaml
@@ -416,3 +416,19 @@ policies:
         messageOnFailure: "Invalid value for key `automountServiceAccountToken` - must be set to `false` to prevent granting unnecessary access to the service account"
       - identifier: CONTAINERS_INCORRECT_SECCOMP_PROFILE
         messageOnFailure: "Incorrect value for key seccompProfile - set an explicit value to prevent malicious use of system calls within the container"
+  - name: Deprecation
+    rules:
+      - identifier: K8S_DEPRECATED_APIVERSION_1.16
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version you are trying to use is not supported by the Kubernetes cluster version (>=1.16)"
+      - identifier: K8S_DEPRECATED_APIVERSION_1.17
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version you are trying to use is not supported by the Kubernetes cluster version (>=1.17)"
+      - identifier: K8S_DEPRECATED_APIVERSION_1.19
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.19"
+      - identifier: K8S_DEPRECATED_APIVERSION_1.21
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.21"
+      - identifier: K8S_DEPRECATED_APIVERSION_1.22
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.22"
+      - identifier: K8S_DEPRECATED_APIVERSION_1.23
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.23"
+      - identifier: K8S_DEPRECATED_APIVERSION_1.24
+        messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.24"
diff --git a/pkg/defaultRules/defaultRules.yaml b/pkg/defaultRules/defaultRules.yaml
index da0b810..e7127dc 100644
--- a/pkg/defaultRules/defaultRules.yaml
+++ b/pkg/defaultRules/defaultRules.yaml
@@ -541,14 +541,30 @@ rules:
     complexity: easy
     impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
     schema:
-      properties:
-        apiVersion:
-          type: string
-          not:
-            enum:
-              - "extensions/v1beta1"
-              - "apps/v1beta1"
-              - "apps/v1beta2"
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - apiextensions.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - CustomResourceDefinition
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - admissionregistration.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - MutatingWebhookConfiguration
+                    - ValidatingWebhookConfiguration
   - id: 19
     name: "Prevent deprecated APIs in Kubernetes v1.17"
     uniqueName: "K8S_DEPRECATED_APIVERSION_1.17"
@@ -559,14 +575,54 @@ rules:
     complexity: easy
     impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
     schema:
-      properties:
-        apiVersion:
-          type: string
-          not:
-            enum:
-              - "kubeadm.k8s.io/v1beta1"
-              - "rbac.authorization.k8s.io/v1alpha1"
-              - "rbac.authorization.k8s.io/v1beta1"
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - rbac.authorization.k8s.io/v1alpha1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - ClusterRoleBinding
+                    - ClusterRole
+                    - ClusterRoleBindingList
+                    - ClusterRoleList
+                    - Role
+                    - RoleBinding
+                    - RoleList
+                    - RoleBindingList
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - rbac.authorization.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - ClusterRoleBinding
+                    - ClusterRole
+                    - ClusterRoleBindingList
+                    - ClusterRoleList
+                    - Role
+                    - RoleBinding
+                    - RoleList
+                    - RoleBindingList
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - storage.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - CSINode
   - id: 20
     name: "Prevent containers from having root access capabilities"
     uniqueName: "CONTAINERS_INCORRECT_PRIVILEGED_VALUE_TRUE"
@@ -2721,4 +2777,213 @@ rules:
         $ref: "#"
       items:
         $ref: "#"
-    
+  - id: 90
+    name: Prevent deprecated APIs in Kubernetes v1.19
+    uniqueName: K8S_DEPRECATED_APIVERSION_1.19
+    enabledByDefault: false
+    documentationUrl: "https://hub.datree.io/built-in-rules/prevent-deprecated-api-119"
+    messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.19"
+    category: Deprecation
+    complexity: easy
+    impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
+    schema:
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - networking.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - Ingress
+                    - IngressClass
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - storage.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - CSIDriver
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - certificates.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - CertificateSigningRequest
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - events.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - Event
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - coordination.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - Lease
+                    - LeaseList
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - apiregistration.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - APIService
+                    - APIServiceList
+  - id: 91
+    name: Prevent deprecated APIs in Kubernetes v1.21
+    uniqueName: K8S_DEPRECATED_APIVERSION_1.21
+    enabledByDefault: false
+    documentationUrl: "https://hub.datree.io/built-in-rules/prevent-deprecated-api-121"
+    messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.21"
+    category: Deprecation
+    complexity: easy
+    impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
+    schema:
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - policy/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - PodSecurityPolicy
+                    - PodDisruptionBudget
+                    - PodDisruptionBudgetList
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - batch/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - CronJob
+                    - CronJobList
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - discovery.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - EndpointSlice
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - audit.k8s.io/v1beta1
+                  - audit.k8s.io/v1alpha1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - Event
+                    - EventList
+                    - Policy
+                    - PolicyList
+  - id: 92
+    name: Prevent deprecated APIs in Kubernetes v1.22
+    uniqueName: K8S_DEPRECATED_APIVERSION_1.22
+    enabledByDefault: false
+    documentationUrl: "https://hub.datree.io/built-in-rules/prevent-deprecated-api-122"
+    messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.22"
+    category: Deprecation
+    complexity: easy
+    impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
+    schema:
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - autoscaling/v2beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - HorizontalPodAutoscaler
+                    - HorizontalPodAutoscalerList
+  - id: 93
+    name: Prevent deprecated APIs in Kubernetes v1.23
+    uniqueName: K8S_DEPRECATED_APIVERSION_1.23
+    enabledByDefault: false
+    documentationUrl: "https://hub.datree.io/built-in-rules/prevent-deprecated-api-123"
+    messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.23"
+    category: Deprecation
+    complexity: easy
+    impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
+    schema:
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - autoscaling/v2beta2
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - HorizontalPodAutoscaler
+                    - HorizontalPodAutoscalerList
+  - id: 94
+    name: Prevent deprecated APIs in Kubernetes v1.24
+    uniqueName: K8S_DEPRECATED_APIVERSION_1.24
+    enabledByDefault: false
+    documentationUrl: "https://hub.datree.io/built-in-rules/prevent-deprecated-api-124"
+    messageOnFailure: "Incorrect value for key `apiVersion` - the version of the resource you are trying to use is deprecated in k8s v1.24"
+    category: Deprecation
+    complexity: easy
+    impact: Deploying a resource with a deprecated API version will cause Kubernetes to reject it
+    schema:
+      allOf:
+        - if:
+            properties:
+              apiVersion:
+                enum:
+                  - storage.k8s.io/v1beta1
+          then:
+            properties:
+              kind:
+                not:
+                  enum:
+                    - CSIStorageCapacity
diff --git a/pkg/defaultRules/defaultRulesSchema.json b/pkg/defaultRules/defaultRulesSchema.json
index fe6d43f..171749f 100644
--- a/pkg/defaultRules/defaultRulesSchema.json
+++ b/pkg/defaultRules/defaultRulesSchema.json
@@ -10,15 +10,15 @@
     },
     "rules": {
       "type": "array",
-      "minItems": 89,
-      "maxItems": 89,
+      "minItems": 94,
+      "maxItems": 94,
       "items": {
         "type": "object",
         "properties": {
           "id": {
             "type": "number",
             "minimum": 1,
-            "maximum": 89
+            "maximum": 94
           },
           "name": {
             "type": "string",


Test patch:
diff --git a/pkg/policy/tests/18-fail.yaml b/pkg/policy/tests/18-fail.yaml
index b547fca..5f3a2a5 100644
--- a/pkg/policy/tests/18-fail.yaml
+++ b/pkg/policy/tests/18-fail.yaml
@@ -1,17 +1,30 @@
-apiVersion: apps/v1beta1
-kind: Service
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
 metadata:
-  name: my-service
+  name: crontabs.example.com
 spec:
-  selector:
-    app: MyApp
-  ports:
-    - protocol: TCP
-      port: 80
-      targetPort: 9376
-  clusterIP: 10.0.171.239
-  type: LoadBalancer
-status:
-  loadBalancer:
-    ingress:
-    - ip: 192.0.2.127
+  group: example.com
+  versions:
+  - name: v1beta1
+    served: true
+    storage: true
+  - name: v1
+    served: true
+    storage: false
+  validation:
+    openAPIV3Schema:
+      type: object
+      properties:
+        host:
+          type: string
+        port:
+          type: string
+  conversion:
+    strategy: None
+  scope: Namespaced
+  names:
+    plural: crontabs
+    singular: crontab
+    kind: CronTab
+    shortNames:
+    - ct
diff --git a/pkg/policy/tests/18-pass.yaml b/pkg/policy/tests/18-pass.yaml
index 3253b74..35295be 100644
--- a/pkg/policy/tests/18-pass.yaml
+++ b/pkg/policy/tests/18-pass.yaml
@@ -1,17 +1,30 @@
-apiVersion: apps/v1
-kind: Service
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
 metadata:
-  name: my-service
+  name: crontabs.example.com
 spec:
-  selector:
-    app: MyApp
-  ports:
-    - protocol: TCP
-      port: 80
-      targetPort: 9376
-  clusterIP: 10.0.171.239
-  type: LoadBalancer
-status:
-  loadBalancer:
-    ingress:
-    - ip: 192.0.2.127
+  group: example.com
+  versions:
+  - name: v1beta1
+    served: true
+    storage: true
+  - name: v1
+    served: true
+    storage: false
+  validation:
+    openAPIV3Schema:
+      type: object
+      properties:
+        host:
+          type: string
+        port:
+          type: string
+  conversion:
+    strategy: None
+  scope: Namespaced
+  names:
+    plural: crontabs
+    singular: crontab
+    kind: CronTab
+    shortNames:
+    - ct
diff --git a/pkg/policy/tests/19-fail.yaml b/pkg/policy/tests/19-fail.yaml
index bca33fb..25cc29e 100644
--- a/pkg/policy/tests/19-fail.yaml
+++ b/pkg/policy/tests/19-fail.yaml
@@ -1,17 +1,9 @@
 apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: Service
+kind: Role
 metadata:
-  name: my-service
-spec:
-  selector:
-    app: MyApp
-  ports:
-    - protocol: TCP
-      port: 80
-      targetPort: 9376
-  clusterIP: 10.0.171.239
-  type: LoadBalancer
-status:
-  loadBalancer:
-    ingress:
-    - ip: 192.0.2.127
+  namespace: default
+  name: pod-reader
+rules:
+- apiGroups: [""] # "" indicates the core API group
+  resources: ["pods"]
+  verbs: ["get", "watch", "list"]
diff --git a/pkg/policy/tests/19-pass.yaml b/pkg/policy/tests/19-pass.yaml
index 04c359d..2f7e6c4 100644
--- a/pkg/policy/tests/19-pass.yaml
+++ b/pkg/policy/tests/19-pass.yaml
@@ -1,17 +1,9 @@
 apiVersion: rbac.authorization.k8s.io/v1
-kind: Service
+kind: Role
 metadata:
-  name: my-service
-spec:
-  selector:
-    app: MyApp
-  ports:
-    - protocol: TCP
-      port: 80
-      targetPort: 9376
-  clusterIP: 10.0.171.239
-  type: LoadBalancer
-status:
-  loadBalancer:
-    ingress:
-    - ip: 192.0.2.127
+  namespace: default
+  name: pod-reader
+rules:
+- apiGroups: [""] # "" indicates the core API group
+  resources: ["pods"]
+  verbs: ["get", "watch", "list"]
diff --git a/pkg/policy/tests/90-fail.yaml b/pkg/policy/tests/90-fail.yaml
new file mode 100644
index 0000000..a02e7f0
--- /dev/null
+++ b/pkg/policy/tests/90-fail.yaml
@@ -0,0 +1,18 @@
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+  name: minimal-ingress
+  annotations:
+    nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+  ingressClassName: nginx-example
+  rules:
+  - http:
+      paths:
+      - path: /testpath
+        pathType: Prefix
+        backend:
+          service:
+            name: test
+            port:
+              number: 80
diff --git a/pkg/policy/tests/90-pass.yaml b/pkg/policy/tests/90-pass.yaml
new file mode 100644
index 0000000..55a5837
--- /dev/null
+++ b/pkg/policy/tests/90-pass.yaml
@@ -0,0 +1,18 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: minimal-ingress
+  annotations:
+    nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+  ingressClassName: nginx-example
+  rules:
+  - http:
+      paths:
+      - path: /testpath
+        pathType: Prefix
+        backend:
+          service:
+            name: test
+            port:
+              number: 80
diff --git a/pkg/policy/tests/91-fail.yaml b/pkg/policy/tests/91-fail.yaml
new file mode 100644
index 0000000..bd2bba6
--- /dev/null
+++ b/pkg/policy/tests/91-fail.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: hello
+spec:
+  schedule: "* * * * *"
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+            - name: hello
+              image: busybox:1.28
+              imagePullPolicy: IfNotPresent
+              command:
+                - /bin/sh
+                - -c
+                - date; echo Hello from the Kubernetes cluster
+          restartPolicy: OnFailure
diff --git a/pkg/policy/tests/91-pass.yaml b/pkg/policy/tests/91-pass.yaml
new file mode 100644
index 0000000..4f87ef3
--- /dev/null
+++ b/pkg/policy/tests/91-pass.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+  name: hello
+spec:
+  schedule: "* * * * *"
+  jobTemplate:
+    spec:
+      template:
+        spec:
+          containers:
+            - name: hello
+              image: busybox:1.28
+              imagePullPolicy: IfNotPresent
+              command:
+                - /bin/sh
+                - -c
+                - date; echo Hello from the Kubernetes cluster
+          restartPolicy: OnFailure
diff --git a/pkg/policy/tests/92-fail.yaml b/pkg/policy/tests/92-fail.yaml
new file mode 100644
index 0000000..1b80574
--- /dev/null
+++ b/pkg/policy/tests/92-fail.yaml
@@ -0,0 +1,11 @@
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: php-apache
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: php-apache
+  minReplicas: 1
+  maxReplicas: 10
diff --git a/pkg/policy/tests/92-pass.yaml b/pkg/policy/tests/92-pass.yaml
new file mode 100644
index 0000000..d14448c
--- /dev/null
+++ b/pkg/policy/tests/92-pass.yaml
@@ -0,0 +1,11 @@
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: php-apache
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: php-apache
+  minReplicas: 1
+  maxReplicas: 10
diff --git a/pkg/policy/tests/93-fail.yaml b/pkg/policy/tests/93-fail.yaml
new file mode 100644
index 0000000..a8fe065
--- /dev/null
+++ b/pkg/policy/tests/93-fail.yaml
@@ -0,0 +1,11 @@
+apiVersion: autoscaling/v2beta2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: php-apache
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: php-apache
+  minReplicas: 1
+  maxReplicas: 10
diff --git a/pkg/policy/tests/93-pass.yaml b/pkg/policy/tests/93-pass.yaml
new file mode 100644
index 0000000..d14448c
--- /dev/null
+++ b/pkg/policy/tests/93-pass.yaml
@@ -0,0 +1,11 @@
+apiVersion: autoscaling/v2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: php-apache
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: php-apache
+  minReplicas: 1
+  maxReplicas: 10
diff --git a/pkg/policy/tests/94-fail.yaml b/pkg/policy/tests/94-fail.yaml
new file mode 100644
index 0000000..c64c402
--- /dev/null
+++ b/pkg/policy/tests/94-fail.yaml
@@ -0,0 +1,3 @@
+apiVersion: storage.k8s.io/v1beta1
+kind: CSIStorageCapacity
+capacity: "130"
diff --git a/pkg/policy/tests/94-pass.yaml b/pkg/policy/tests/94-pass.yaml
new file mode 100644
index 0000000..c63d695
--- /dev/null
+++ b/pkg/policy/tests/94-pass.yaml
@@ -0,0 +1,3 @@
+apiVersion: storage.k8s.io/v1
+kind: CSIStorageCapacity
+capacity: "130"