diff --git a/best-practices/disallow-default-namespace/disallow-default-namespace.yaml b/best-practices/disallow-default-namespace/disallow-default-namespace.yaml new file mode 100644 index 00000000..f4caa57d --- /dev/null +++ b/best-practices/disallow-default-namespace/disallow-default-namespace.yaml @@ -0,0 +1,49 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-default-namespace + annotations: + pod-policies.kyverno.io/autogen-controllers: none + policies.kyverno.io/title: Disallow Default Namespace + kyverno.io/kyverno-version: 1.10.0 + policies.kyverno.io/minversion: 1.6.0 + policies.kyverno.io/category: Multi-Tenancy + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Kubernetes Namespaces are an optional feature that provide a way to segment and + isolate cluster resources across multiple applications and users. As a best + practice, workloads should be isolated with Namespaces. Namespaces should be required + and the default (empty) Namespace should not be used. This policy validates that Pods + specify a Namespace name other than `default`. Rule auto-generation is disabled here + due to Pod controllers need to specify the `namespace` field under the top-level `metadata` + object and not at the Pod template level. +spec: + validationFailureAction: Audit + background: true + rules: + - name: validate-namespace + match: + any: + - resources: + kinds: + - Pod + validate: + message: "Using 'default' namespace is not allowed." + pattern: + metadata: + namespace: "!default" + - name: validate-podcontroller-namespace + match: + any: + - resources: + kinds: + - DaemonSet + - Deployment + - Job + - StatefulSet + validate: + message: "Using 'default' namespace is not allowed for pod controllers." + pattern: + metadata: + namespace: "!default" diff --git a/best-practices/disallow-default-namespace/e2e/chainsaw-test.yaml b/best-practices/disallow-default-namespace/e2e/chainsaw-test.yaml new file mode 100755 index 00000000..0df2e4cb --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/chainsaw-test.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: disallow-default-namespace +spec: + steps: + - name: step-01 + try: + - apply: + file: ../disallow-default-namespace.yaml + - patch: + resource: + apiVersion: kyverno.io/v1 + kind: ClusterPolicy + metadata: + name: disallow-default-namespace + spec: + validationFailureAction: Enforce + - assert: + file: policy-ready.yaml + - name: step-02 + try: + - apply: + file: ns.yaml + - name: step-03 + try: + - apply: + file: good-resources.yaml + - apply: + expect: + - check: + ($error != null): true + file: pod-default.yaml + - apply: + expect: + - check: + ($error != null): true + file: ds-default.yaml + - apply: + expect: + - check: + ($error != null): true + file: job-default.yaml + - apply: + expect: + - check: + ($error != null): true + file: ss-default.yaml + - apply: + expect: + - check: + ($error != null): true + file: deploy-default.yaml diff --git a/best-practices/disallow-default-namespace/e2e/deploy-default.yaml b/best-practices/disallow-default-namespace/e2e/deploy-default.yaml new file mode 100644 index 00000000..9f6a91e1 --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/deploy-default.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: bad-busybox + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" \ No newline at end of file diff --git a/best-practices/disallow-default-namespace/e2e/ds-default.yaml b/best-practices/disallow-default-namespace/e2e/ds-default.yaml new file mode 100644 index 00000000..27dd35dc --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/ds-default.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: bad-daemonset + namespace: default +spec: + selector: + matchLabels: + name: good-daemonset + template: + metadata: + labels: + name: good-daemonset + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" \ No newline at end of file diff --git a/best-practices/disallow-default-namespace/e2e/good-resources.yaml b/best-practices/disallow-default-namespace/e2e/good-resources.yaml new file mode 100644 index 00000000..909ea195 --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/good-resources.yaml @@ -0,0 +1,97 @@ +apiVersion: v1 +kind: Pod +metadata: + name: goodpod01 + namespace: not-default-ns +spec: + containers: + - name: busybox + image: "busybox:v1.35" + command: + - "sleep" + - "3000" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: busybox + namespace: not-default-ns +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: good-daemonset + namespace: not-default-ns +spec: + selector: + matchLabels: + name: good-daemonset + template: + metadata: + labels: + name: good-daemonset + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: good-job + namespace: not-default-ns +spec: + template: + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" + restartPolicy: Never +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: good-statefulset + namespace: not-default-ns +spec: + selector: + matchLabels: + app: busybox + serviceName: "busyservice" + replicas: 1 + minReadySeconds: 10 + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" \ No newline at end of file diff --git a/best-practices/disallow-default-namespace/e2e/job-default.yaml b/best-practices/disallow-default-namespace/e2e/job-default.yaml new file mode 100644 index 00000000..a32cc585 --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/job-default.yaml @@ -0,0 +1,15 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: bad-job + namespace: default +spec: + template: + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" + restartPolicy: Never \ No newline at end of file diff --git a/best-practices/disallow-default-namespace/e2e/ns.yaml b/best-practices/disallow-default-namespace/e2e/ns.yaml new file mode 100755 index 00000000..8f5b8c3b --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: not-default-ns diff --git a/best-practices/disallow-default-namespace/e2e/pod-default.yaml b/best-practices/disallow-default-namespace/e2e/pod-default.yaml new file mode 100644 index 00000000..599c05ce --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/pod-default.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: badpod01 + namespace: default +spec: + containers: + - name: busybox + image: "busybox:v1.35" + command: + - "sleep" + - "3000" \ No newline at end of file diff --git a/best-practices/disallow-default-namespace/e2e/policy-ready.yaml b/best-practices/disallow-default-namespace/e2e/policy-ready.yaml new file mode 100755 index 00000000..07756448 --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/policy-ready.yaml @@ -0,0 +1,9 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-default-namespace +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/best-practices/disallow-default-namespace/e2e/ss-default.yaml b/best-practices/disallow-default-namespace/e2e/ss-default.yaml new file mode 100644 index 00000000..6c14a6d0 --- /dev/null +++ b/best-practices/disallow-default-namespace/e2e/ss-default.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: good-statefulset + namespace: default +spec: + selector: + matchLabels: + app: busybox + serviceName: "busyservice" + replicas: 1 + minReadySeconds: 10 + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + command: + - "sleep" + - "3000" \ No newline at end of file diff --git a/best-practices/disallow-default-namespace/kyverno-test.yaml b/best-practices/disallow-default-namespace/kyverno-test.yaml new file mode 100644 index 00000000..ca318b9b --- /dev/null +++ b/best-practices/disallow-default-namespace/kyverno-test.yaml @@ -0,0 +1,28 @@ +name: disallow-default-namespace +policies: + - disallow-default-namespace.yaml +resources: + - resource.yaml +results: + # validate-namespace + - policy: disallow-default-namespace + rule: validate-namespace + resource: badpod01 + kind: Pod + result: fail + - policy: disallow-default-namespace + rule: validate-namespace + resource: goodpod01 + kind: Pod + result: pass + # validate-podcontroller-namespace + - policy: disallow-default-namespace + rule: validate-podcontroller-namespace + resource: baddeployment01 + kind: Deployment + result: fail + - policy: disallow-default-namespace + rule: validate-podcontroller-namespace + resource: gooddeployment01 + kind: Deployment + result: pass diff --git a/best-practices/disallow-default-namespace/resource.yaml b/best-practices/disallow-default-namespace/resource.yaml new file mode 100644 index 00000000..e2b02fae --- /dev/null +++ b/best-practices/disallow-default-namespace/resource.yaml @@ -0,0 +1,66 @@ +apiVersion: v1 +kind: Pod +metadata: + name: badpod01 + namespace: default + labels: + app: myapp +spec: + containers: + - name: nginx + image: nginx +--- +apiVersion: v1 +kind: Pod +metadata: + name: goodpod01 + namespace: foo + labels: + app: myapp +spec: + containers: + - name: nginx + image: nginx +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: baddeployment01 + labels: + app: busybox +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: busybox:1.28 + name: busybox + command: ["sleep", "9999"] +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gooddeployment01 + labels: + app: busybox + namespace: foo +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: busybox:1.28 + name: busybox + command: ["sleep", "9999"] diff --git a/eks-best-practices/disallow-all-secrets.yaml b/eks-best-practices/disallow-all-secrets/disallow-all-secrets.yaml similarity index 97% rename from eks-best-practices/disallow-all-secrets.yaml rename to eks-best-practices/disallow-all-secrets/disallow-all-secrets.yaml index e2a00483..a4e66bbb 100644 --- a/eks-best-practices/disallow-all-secrets.yaml +++ b/eks-best-practices/disallow-all-secrets/disallow-all-secrets.yaml @@ -1,5 +1,5 @@ apiVersion: kyverno.io/v1 -kind: Policy +kind: ClusterPolicy metadata: name: no-secrets annotations: @@ -7,6 +7,7 @@ metadata: policies.kyverno.io/category: EKS Best Practices policies.kyverno.io/severity: medium policies.kyverno.io/subject: Pod, Secret + kyverno.io/kyverno-version: 1.6.0 policies.kyverno.io/minversion: 1.6.0 kyverno.io/kubernetes-version: "1.21" policies.kyverno.io/description: >- diff --git a/eks-best-practices/disallow-all-secrets/e2e/chainsaw-step-01-assert-1.yaml b/eks-best-practices/disallow-all-secrets/e2e/chainsaw-step-01-assert-1.yaml new file mode 100755 index 00000000..9806aed9 --- /dev/null +++ b/eks-best-practices/disallow-all-secrets/e2e/chainsaw-step-01-assert-1.yaml @@ -0,0 +1,10 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: no-secrets +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready + diff --git a/eks-best-practices/disallow-all-secrets/e2e/chainsaw-test.yaml b/eks-best-practices/disallow-all-secrets/e2e/chainsaw-test.yaml new file mode 100755 index 00000000..5c33a254 --- /dev/null +++ b/eks-best-practices/disallow-all-secrets/e2e/chainsaw-test.yaml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: disallow-all-secrets +spec: + steps: + - name: step-01 + try: + - apply: + file: ../disallow-all-secrets.yaml + - patch: + resource: + apiVersion: kyverno.io/v1 + kind: ClusterPolicy + metadata: + name: no-secrets + spec: + validationFailureAction: Enforce + - assert: + file: chainsaw-step-01-assert-1.yaml + - name: step-02 + try: + - apply: + file: pods-good.yaml + - apply: + expect: + - check: + ($error != null): true + file: pods-bad.yaml + - apply: + file: podcontrollers-good.yaml + - apply: + expect: + - check: + ($error != null): true + file: podcontrollers-bad.yaml diff --git a/eks-best-practices/disallow-all-secrets/e2e/podcontrollers-bad.yaml b/eks-best-practices/disallow-all-secrets/e2e/podcontrollers-bad.yaml new file mode 100644 index 00000000..c882c0d2 --- /dev/null +++ b/eks-best-practices/disallow-all-secrets/e2e/podcontrollers-bad.yaml @@ -0,0 +1,189 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: baddeployment01 +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + strategy: {} + template: + metadata: + labels: + app: busybox + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: foo + value: bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: baddeployment02 +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + strategy: {} + template: + metadata: + labels: + app: busybox + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + envFrom: + - secretRef: + name: foo + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - secretRef: + name: foo + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: baddeployment03 +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + strategy: {} + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + secret: + secretName: foo-secret +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: badcronjob01 +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: foo + value: bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + restartPolicy: OnFailure +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: badcronjob02 +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + envFrom: + - secretRef: + name: foo + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - secretRef: + name: foo + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + restartPolicy: OnFailure +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: badcronjob03 +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + secret: + secretName: foo-secret + restartPolicy: OnFailure \ No newline at end of file diff --git a/eks-best-practices/disallow-all-secrets/e2e/podcontrollers-good.yaml b/eks-best-practices/disallow-all-secrets/e2e/podcontrollers-good.yaml new file mode 100644 index 00000000..47e2b1c1 --- /dev/null +++ b/eks-best-practices/disallow-all-secrets/e2e/podcontrollers-good.yaml @@ -0,0 +1,175 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: gooddeployment01 +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + strategy: {} + template: + metadata: + labels: + app: busybox + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: foo + value: bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: gooddeployment02 +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + strategy: {} + template: + metadata: + labels: + app: busybox + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + envFrom: + - configMapRef: + name: foo-bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - configMapRef: + name: foo-bar + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: busybox + name: gooddeployment03 +spec: + replicas: 1 + selector: + matchLabels: + app: busybox + strategy: {} + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + emptyDir: + sizeLimit: 100Mi +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: goodcronjob01 +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: foo + value: bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + restartPolicy: OnFailure +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: goodcronjob02 +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + envFrom: + - configMapRef: + name: foo-bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - configMapRef: + name: foo-bar + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + restartPolicy: OnFailure +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: goodcronjob03 +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + emptyDir: + sizeLimit: 100Mi + restartPolicy: OnFailure \ No newline at end of file diff --git a/eks-best-practices/disallow-all-secrets/e2e/pods-bad.yaml b/eks-best-practices/disallow-all-secrets/e2e/pods-bad.yaml new file mode 100644 index 00000000..b87746e6 --- /dev/null +++ b/eks-best-practices/disallow-all-secrets/e2e/pods-bad.yaml @@ -0,0 +1,96 @@ +apiVersion: v1 +kind: Pod +metadata: + name: badpod01 +spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: foo + value: bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: v1 +kind: Pod +metadata: + name: badpod02 +spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + envFrom: + - secretRef: + name: foo + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - secretRef: + name: foo + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: v1 +kind: Pod +metadata: + name: badpod03 +spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + secret: + secretName: foo-secret +--- +apiVersion: v1 +kind: Pod +metadata: + name: badpod04 +spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: SECRET_BAD + valueFrom: + secretKeyRef: + name: foo + key: pass + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - secretRef: + name: foo + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + secret: + secretName: foo-secret \ No newline at end of file diff --git a/eks-best-practices/disallow-all-secrets/e2e/pods-good.yaml b/eks-best-practices/disallow-all-secrets/e2e/pods-good.yaml new file mode 100644 index 00000000..2209cb7e --- /dev/null +++ b/eks-best-practices/disallow-all-secrets/e2e/pods-good.yaml @@ -0,0 +1,71 @@ +apiVersion: v1 +kind: Pod +metadata: + name: goodpod01 +spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + env: + - name: foo + value: bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: v1 +kind: Pod +metadata: + name: goodpod02 +spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init +--- +apiVersion: v1 +kind: Pod +metadata: + name: goodpod03 +spec: + initContainers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02-init + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox-init + envFrom: + - configMapRef: + name: foo-bar + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + envFrom: + - configMapRef: + name: foo-bar + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 +--- +apiVersion: v1 +kind: Pod +metadata: + name: goodpod04 +spec: + containers: + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox + - image: ghcr.io/kyverno/test-busybox:1.35 + name: busybox02 + volumes: + - name: foo-vol + emptyDir: + sizeLimit: 100Mi \ No newline at end of file diff --git a/workload-security/restrict-binding-clusteradmin/e2e/chainsaw-step-01-assert-1.yaml b/workload-security/restrict-binding-clusteradmin/e2e/chainsaw-step-01-assert-1.yaml new file mode 100755 index 00000000..77ed2b43 --- /dev/null +++ b/workload-security/restrict-binding-clusteradmin/e2e/chainsaw-step-01-assert-1.yaml @@ -0,0 +1,10 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-binding-clusteradmin +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready + diff --git a/workload-security/restrict-binding-clusteradmin/e2e/chainsaw-test.yaml b/workload-security/restrict-binding-clusteradmin/e2e/chainsaw-test.yaml new file mode 100755 index 00000000..2d3c69b0 --- /dev/null +++ b/workload-security/restrict-binding-clusteradmin/e2e/chainsaw-test.yaml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: restrict-binding-clusteradmin +spec: + steps: + - name: step-01 + try: + - apply: + file: ../restrict-binding-clusteradmin.yaml + - patch: + resource: + apiVersion: kyverno.io/v1 + kind: ClusterPolicy + metadata: + name: restrict-binding-clusteradmin + spec: + validationFailureAction: Enforce + - assert: + file: chainsaw-step-01-assert-1.yaml + - name: step-02 + try: + - apply: + file: rb-good.yaml + - apply: + expect: + - check: + ($error != null): true + file: rb-bad.yaml + - apply: + file: crb-good.yaml + - apply: + expect: + - check: + ($error != null): true + file: crb-bad.yaml diff --git a/workload-security/restrict-binding-clusteradmin/e2e/crb-bad.yaml b/workload-security/restrict-binding-clusteradmin/e2e/crb-bad.yaml new file mode 100644 index 00000000..cbbb3c44 --- /dev/null +++ b/workload-security/restrict-binding-clusteradmin/e2e/crb-bad.yaml @@ -0,0 +1,25 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: badcrb01 +subjects: +- kind: Group + name: manager + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: badcrb02 +subjects: +- kind: ServiceAccount + namespace: foo + name: manager +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io diff --git a/workload-security/restrict-binding-clusteradmin/e2e/crb-good.yaml b/workload-security/restrict-binding-clusteradmin/e2e/crb-good.yaml new file mode 100644 index 00000000..24e6cf5d --- /dev/null +++ b/workload-security/restrict-binding-clusteradmin/e2e/crb-good.yaml @@ -0,0 +1,25 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: goodcrb01 +subjects: +- kind: Group + name: manager + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: secret-reader + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: goodcrb02 +subjects: +- kind: ServiceAccount + namespace: foo + name: manager +roleRef: + kind: ClusterRole + name: foo-reader + apiGroup: rbac.authorization.k8s.io diff --git a/workload-security/restrict-binding-clusteradmin/e2e/rb-bad.yaml b/workload-security/restrict-binding-clusteradmin/e2e/rb-bad.yaml new file mode 100644 index 00000000..acb554db --- /dev/null +++ b/workload-security/restrict-binding-clusteradmin/e2e/rb-bad.yaml @@ -0,0 +1,25 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: badrb01 +subjects: +- kind: User + name: foo + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: cluster-admin + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: badrb02 +subjects: +- kind: ServiceAccount + name: foo + namespace: foo +roleRef: + kind: Role + name: cluster-admin + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/workload-security/restrict-binding-clusteradmin/e2e/rb-good.yaml b/workload-security/restrict-binding-clusteradmin/e2e/rb-good.yaml new file mode 100644 index 00000000..14cb85df --- /dev/null +++ b/workload-security/restrict-binding-clusteradmin/e2e/rb-good.yaml @@ -0,0 +1,25 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: goodrb01 +subjects: +- kind: User + name: foo + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: foo-bar + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: goodrb02 +subjects: +- kind: ServiceAccount + name: foo + namespace: foo +roleRef: + kind: Role + name: foo-bar + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/workload-security/restrict-binding-clusteradmin.yaml b/workload-security/restrict-binding-clusteradmin/restrict-binding-clusteradmin.yaml similarity index 91% rename from workload-security/restrict-binding-clusteradmin.yaml rename to workload-security/restrict-binding-clusteradmin/restrict-binding-clusteradmin.yaml index 0a6d9145..6dc4fcc3 100644 --- a/workload-security/restrict-binding-clusteradmin.yaml +++ b/workload-security/restrict-binding-clusteradmin/restrict-binding-clusteradmin.yaml @@ -7,14 +7,14 @@ metadata: policies.kyverno.io/category: Workload Security policies.kyverno.io/severity: medium policies.kyverno.io/subject: RoleBinding, ClusterRoleBinding, RBAC - kyverno.io/kyverno-version: 1.10.0 + kyverno.io/kyverno-version: 1.6.2 policies.kyverno.io/minversion: 1.6.0 kyverno.io/kubernetes-version: "1.23" policies.kyverno.io/description: >- The cluster-admin ClusterRole allows any action to be performed on any resource in the cluster and its granting should be heavily restricted. This policy prevents binding to the cluster-admin ClusterRole in - RoleBinding or ClusterRoleBinding resources. + RoleBinding or ClusterRoleBinding resources. spec: validationFailureAction: Audit background: true diff --git a/workload-security/restrict-secret-role-verbs/e2e/chainsaw-step-01-assert-1.yaml b/workload-security/restrict-secret-role-verbs/e2e/chainsaw-step-01-assert-1.yaml new file mode 100755 index 00000000..acb40c32 --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/e2e/chainsaw-step-01-assert-1.yaml @@ -0,0 +1,10 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-secret-role-verbs +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready + diff --git a/workload-security/restrict-secret-role-verbs/e2e/chainsaw-test.yaml b/workload-security/restrict-secret-role-verbs/e2e/chainsaw-test.yaml new file mode 100755 index 00000000..c3cb1663 --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/e2e/chainsaw-test.yaml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: restrict-secret-role-verbs +spec: + steps: + - name: step-01 + try: + - apply: + file: ../restrict-secret-role-verbs.yaml + - patch: + resource: + apiVersion: kyverno.io/v1 + kind: ClusterPolicy + metadata: + name: restrict-secret-role-verbs + spec: + validationFailureAction: Enforce + - assert: + file: chainsaw-step-01-assert-1.yaml + - name: step-02 + try: + - apply: + file: cr-good.yaml + - apply: + expect: + - check: + ($error != null): true + file: cr-bad.yaml + - apply: + file: role-good.yaml + - apply: + expect: + - check: + ($error != null): true + file: role-bad.yaml diff --git a/workload-security/restrict-secret-role-verbs/e2e/cr-bad.yaml b/workload-security/restrict-secret-role-verbs/e2e/cr-bad.yaml new file mode 100644 index 00000000..1a6f2997 --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/e2e/cr-bad.yaml @@ -0,0 +1,32 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr01 +rules: +- apiGroups: [""] + resources: ["namespaces", "secrets", "pods"] + verbs: ["get", "create"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr02 +rules: +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +- apiGroups: [""] + resources: ["namespaces", "secrets", "pods"] + verbs: ["create", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr03 +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["update", "list", "create"] \ No newline at end of file diff --git a/workload-security/restrict-secret-role-verbs/e2e/cr-good.yaml b/workload-security/restrict-secret-role-verbs/e2e/cr-good.yaml new file mode 100644 index 00000000..420648fc --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/e2e/cr-good.yaml @@ -0,0 +1,29 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr02 +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr03 +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "update", "patch"] \ No newline at end of file diff --git a/workload-security/restrict-secret-role-verbs/e2e/role-bad.yaml b/workload-security/restrict-secret-role-verbs/e2e/role-bad.yaml new file mode 100644 index 00000000..c2cde675 --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/e2e/role-bad.yaml @@ -0,0 +1,32 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badcr01 +rules: +- apiGroups: [""] + resources: ["namespaces", "secrets", "pods"] + verbs: ["get", "create"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badcr02 +rules: +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +- apiGroups: [""] + resources: ["namespaces", "secrets", "pods"] + verbs: ["create", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badcr03 +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["update", "list", "create"] \ No newline at end of file diff --git a/workload-security/restrict-secret-role-verbs/e2e/role-good.yaml b/workload-security/restrict-secret-role-verbs/e2e/role-good.yaml new file mode 100644 index 00000000..c504dcdd --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/e2e/role-good.yaml @@ -0,0 +1,29 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodcr01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodcr02 +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodcr03 +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "update", "patch"] \ No newline at end of file diff --git a/workload-security/restrict-secret-role-verbs/restrict-secret-role-verbs.yaml b/workload-security/restrict-secret-role-verbs/restrict-secret-role-verbs.yaml new file mode 100644 index 00000000..c94f4600 --- /dev/null +++ b/workload-security/restrict-secret-role-verbs/restrict-secret-role-verbs.yaml @@ -0,0 +1,38 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-secret-role-verbs + annotations: + policies.kyverno.io/title: Restrict Secret Verbs in Roles + policies.kyverno.io/category: Workload Security + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Role, ClusterRole, RBAC + kyverno.io/kyverno-version: 1.6.2 + policies.kyverno.io/minversion: 1.6.0 + kyverno.io/kubernetes-version: "1.23" + policies.kyverno.io/description: >- + The verbs `get`, `list`, and `watch` in a Role or ClusterRole, when paired with the Secrets resource, effectively + allows Secrets to be read which may expose sensitive information. This policy prevents + a Role or ClusterRole from using these verbs in tandem with Secret resources. In order to + fully implement this control, it is recommended to pair this policy with another which + also prevents use of the wildcard ('*') in the verbs list either when explicitly naming Secrets + or when also using a wildcard in the base API group. +spec: + validationFailureAction: Audit + background: true + rules: + - name: secret-verbs + match: + any: + - resources: + kinds: + - Role + - ClusterRole + validate: + message: "Requesting verbs `get`, `list`, or `watch` on Secrets is forbidden." + deny: + conditions: + any: + - key: ["get","list","watch"] + operator: AnyIn + value: "{{ request.object.rules[?resources.contains(@,'secrets')].verbs[] }}" \ No newline at end of file