From 417cef2e80412991b021d8a7ef6b6234ef2a240c Mon Sep 17 00:00:00 2001 From: peefy Date: Fri, 27 Oct 2023 11:03:12 +0800 Subject: [PATCH] feat: add all model source code on github packages Signed-off-by: peefy --- .gitignore | 18 +- add-app-armor-annotation/README.md | 38 +++++ add-app-armor-annotation/kcl.mod | 5 + add-app-armor-annotation/main.k | 9 + add-app-armor-annotation/suite/good.yaml | 28 +++ add-capabilities/README.md | 16 ++ add-capabilities/kcl.mod | 5 + add-capabilities/main.k | 7 + add-capabilities/suite/good.yaml | 26 +++ add-certificates-volume/README.md | 16 ++ add-certificates-volume/kcl.mod | 5 + add-certificates-volume/main.k | 13 ++ add-certificates-volume/suite/good.yaml | 27 +++ add-default-resources/README.md | 5 + add-default-resources/kcl.mod | 5 + add-default-resources/main.k | 9 + add-default-resources/suite/good.yaml | 28 +++ add-default-securitycontext/README.md | 5 + add-default-securitycontext/kcl.mod | 5 + add-default-securitycontext/main.k | 9 + add-default-securitycontext/suite/good.yaml | 27 +++ add-emptydir-sizelimit/README.md | 5 + add-emptydir-sizelimit/kcl.mod | 5 + add-emptydir-sizelimit/main.k | 7 + add-emptydir-sizelimit/suite/good.yaml | 31 ++++ add-image-as-env-var/README.md | 5 + add-image-as-env-var/kcl.mod | 5 + add-image-as-env-var/main.k | 9 + add-image-as-env-var/suite/good.yaml | 26 +++ add-istio-sidecar-injection/README.md | 5 + add-istio-sidecar-injection/kcl.mod | 5 + add-istio-sidecar-injection/main.k | 6 + add-istio-sidecar-injection/suite/good.yaml | 20 +++ add-linkerd-policy-annotation/README.md | 5 + add-linkerd-policy-annotation/kcl.mod | 5 + add-linkerd-policy-annotation/main.k | 5 + add-linkerd-policy-annotation/suite/good.yaml | 22 +++ add-ndots/README.md | 5 + add-ndots/kcl.mod | 5 + add-ndots/main.k | 9 + add-ndots/suite/good.yaml | 24 +++ add-nodeselector/README.md | 5 + add-nodeselector/kcl.mod | 4 + add-nodeselector/main.k | 7 + add-nodeselector/suite/good.yaml | 25 +++ add-psa-labels/README.md | 5 + add-psa-labels/kcl.mod | 5 + add-psa-labels/main.k | 7 + add-psa-labels/suite/good.yaml | 22 +++ add-quota/README.md | 5 + add-quota/kcl.mod | 4 + add-quota/main.k | 36 ++++ add-quota/suite/good.yaml | 16 ++ add-runtime-class-name/README.md | 5 + add-runtime-class-name/kcl.mod | 5 + add-runtime-class-name/main.k | 4 + add-runtime-class-name/suite/good.yaml | 27 +++ allowed-image-repos/README.md | 5 + allowed-image-repos/kcl.mod | 4 + allowed-image-repos/main.k | 25 +++ allowed-image-repos/suite/bad.yaml | 38 +++++ allowed-image-repos/suite/good.yaml | 38 +++++ append-env/README.md | 5 + append-env/kcl.mod | 5 + append-env/main.k | 10 ++ append-env/suite/good.yaml | 37 ++++ conditionally-add-annotations/README.md | 5 + conditionally-add-annotations/kcl.mod | 5 + conditionally-add-annotations/main.k | 10 ++ .../suite/config.yaml | 16 ++ conditionally-add-annotations/suite/good.yaml | 29 ++++ conditionally-add-labels/README.md | 5 + conditionally-add-labels/kcl.mod | 5 + conditionally-add-labels/main.k | 10 ++ conditionally-add-labels/suite/config.yaml | 16 ++ conditionally-add-labels/suite/good.yaml | 29 ++++ deny-all/README.md | 5 + deny-all/kcl.mod | 4 + deny-all/main.k | 1 + deny-all/suite/bad.yaml | 26 +++ deny-all/suite/good.yaml | 11 ++ deny-commands-in-exec-probe/README.md | 5 + deny-commands-in-exec-probe/kcl.mod | 5 + deny-commands-in-exec-probe/main.k | 14 ++ deny-commands-in-exec-probe/suite/bad.yaml | 29 ++++ deny-commands-in-exec-probe/suite/good.yaml | 29 ++++ deny-endpoint-edit-default-role/README.md | 5 + deny-endpoint-edit-default-role/kcl.mod | 4 + deny-endpoint-edit-default-role/main.k | 32 ++++ .../suite/bad.yaml | 116 +++++++++++++ .../suite/good.yaml | 160 ++++++++++++++++++ disallow-anonymous/README.md | 5 + disallow-anonymous/kcl.mod | 4 + disallow-anonymous/main.k | 21 +++ disallow-anonymous/suite/bad.yaml | 31 ++++ disallow-anonymous/suite/good.yaml | 32 ++++ disallow-host-ports/README.md | 5 + disallow-host-ports/kcl.mod | 5 + disallow-host-ports/main.k | 12 ++ disallow-host-ports/suite/bad.yaml | 25 +++ disallow-host-ports/suite/good.yaml | 29 ++++ disallow-ingress-wildcard/README.md | 5 + disallow-ingress-wildcard/kcl.mod | 4 + disallow-ingress-wildcard/main.k | 15 ++ disallow-ingress-wildcard/suite/bad.yaml | 40 +++++ disallow-ingress-wildcard/suite/good.yaml | 30 ++++ disallow-privileged-containers/README.md | 5 + disallow-privileged-containers/kcl.mod | 5 + disallow-privileged-containers/main.k | 11 ++ disallow-privileged-containers/suite/bad.yaml | 27 +++ .../suite/good.yaml | 31 ++++ disallow-svc-lb/README.md | 5 + disallow-svc-lb/kcl.mod | 4 + disallow-svc-lb/main.k | 12 ++ disallow-svc-lb/suite/bad.yaml | 19 +++ disallow-svc-lb/suite/good.yaml | 23 +++ disallow-svc-node-port/README.md | 5 + disallow-svc-node-port/kcl.mod | 4 + disallow-svc-node-port/main.k | 12 ++ disallow-svc-node-port/suite/bad.yaml | 24 +++ disallow-svc-node-port/suite/good.yaml | 23 +++ disallowed-image-repos/README.md | 5 + disallowed-image-repos/kcl.mod | 4 + disallowed-image-repos/main.k | 23 +++ disallowed-image-repos/suite/bad.yaml | 28 +++ disallowed-image-repos/suite/good.yaml | 28 +++ external-ips/README.md | 5 + external-ips/kcl.mod | 5 + external-ips/main.k | 10 ++ external-ips/suite/bad.yaml | 29 ++++ external-ips/suite/config.yaml | 14 ++ external-ips/suite/good.yaml | 29 ++++ helloworld/kcl.mod | 4 +- horizontal-pod-auto-scaler/README.md | 5 + horizontal-pod-auto-scaler/kcl.mod | 4 + horizontal-pod-auto-scaler/main.k | 35 ++++ horizontal-pod-auto-scaler/suite/bad.yaml | 40 +++++ horizontal-pod-auto-scaler/suite/good.yaml | 39 +++++ https-only/README.md | 5 + https-only/kcl.mod | 5 + https-only/main.k | 9 + https-only/suite/bad.yaml | 28 +++ https-only/suite/config.yaml | 15 ++ https-only/suite/good.yaml | 38 +++++ insert-pod-antiaffinity/README.md | 5 + insert-pod-antiaffinity/kcl.mod | 5 + insert-pod-antiaffinity/main.k | 12 ++ insert-pod-antiaffinity/suite/good.yaml | 36 ++++ k8s_manifests_containers/README.md | 5 + k8s_manifests_containers/kcl.mod | 4 + k8s_manifests_containers/main.k | 19 +++ merge/README.md | 5 + merge/kcl.mod | 5 + merge/main.k | 41 +++++ nginx-ingress/README.md | 1 + .../restrict-ingress-annotations/README.md | 5 + .../restrict-ingress-annotations/kcl.mod | 5 + .../restrict-ingress-annotations/main.k | 24 +++ .../suite/bad.yaml | 145 ++++++++++++++++ .../suite/good.yaml | 65 +++++++ .../restrict-ingress-paths/README.md | 5 + nginx-ingress/restrict-ingress-paths/kcl.mod | 5 + nginx-ingress/restrict-ingress-paths/main.k | 18 ++ .../restrict-ingress-paths/suite/bad.yaml | 81 +++++++++ .../restrict-ingress-paths/suite/good.yaml | 37 ++++ pod-security-policy/selinux/README.md | 5 + pod-security-policy/selinux/kcl.mod | 5 + pod-security-policy/selinux/main.k | 13 ++ pod-security-policy/selinux/suite/good.yaml | 22 +++ psp-allow-privilege-escalation/README.md | 5 + psp-allow-privilege-escalation/kcl.mod | 4 + psp-allow-privilege-escalation/main.k | 39 +++++ psp-allow-privilege-escalation/suite/bad.yaml | 27 +++ .../suite/good.yaml | 27 +++ psp-app-armor/README.md | 5 + psp-app-armor/kcl.mod | 4 + psp-app-armor/main.k | 47 +++++ psp-app-armor/suite/bad.yaml | 31 ++++ psp-app-armor/suite/good.yaml | 31 ++++ psp-capabilities/README.md | 5 + psp-capabilities/kcl.mod | 4 + psp-capabilities/main.k | 61 +++++++ psp-capabilities/suite/bad.yaml | 35 ++++ psp-capabilities/suite/good.yaml | 36 ++++ psp-flexvolume-drivers/README.md | 5 + psp-flexvolume-drivers/kcl.mod | 4 + psp-flexvolume-drivers/main.k | 27 +++ psp-flexvolume-drivers/suite/bad.yaml | 37 ++++ psp-flexvolume-drivers/suite/good.yaml | 37 ++++ readonly-root-fs/README.md | 5 + readonly-root-fs/kcl.mod | 4 + readonly-root-fs/main.k | 9 + readonly-root-fs/suite/good.yaml | 22 +++ replica-limits/README.md | 5 + replica-limits/kcl.mod | 5 + replica-limits/main.k | 13 ++ replica-limits/suite/bad.yaml | 37 ++++ replica-limits/suite/config.yaml | 15 ++ replica-limits/suite/good.yaml | 37 ++++ required-annotations/README.md | 5 + required-annotations/kcl.mod | 5 + required-annotations/main.k | 17 ++ required-annotations/suite/bad.yaml | 35 ++++ required-annotations/suite/config.yaml | 16 ++ required-annotations/suite/good.yaml | 42 +++++ required-image-digests/README.md | 5 + required-image-digests/kcl.mod | 4 + required-image-digests/main.k | 39 +++++ required-image-digests/suite/bad.yaml | 22 +++ required-image-digests/suite/good.yaml | 22 +++ required-labels/README.md | 5 + required-labels/kcl.mod | 5 + required-labels/main.k | 16 ++ required-labels/suite/bad.yaml | 35 ++++ required-labels/suite/config.yaml | 16 ++ required-labels/suite/good.yaml | 42 +++++ required-probes/README.md | 5 + required-probes/kcl.mod | 4 + required-probes/main.k | 39 +++++ required-probes/suite/bad.yaml | 30 ++++ required-probes/suite/good.yaml | 35 ++++ set-annotations/README.md | 4 + set-annotations/kcl.mod | 2 +- set-labels/README.md | 5 + set-labels/kcl.mod | 5 + set-labels/main.k | 6 + set-labels/suite/config.yaml | 9 + set-labels/suite/good.yaml | 25 +++ set-replicas/README.md | 5 + set-replicas/kcl.mod | 5 + set-replicas/main.k | 7 + set-replicas/suite/config.yaml | 8 + set-replicas/suite/good.yaml | 30 ++++ .../README.md | 5 + .../kcl.mod | 4 + .../main.k | 29 ++++ .../suite/bad.yaml | 38 +++++ .../suite/good.yaml | 38 +++++ validate-container-limits/README.md | 5 + validate-container-limits/kcl.mod | 4 + validate-container-limits/main.k | 44 +++++ validate-container-limits/suite/bad.yaml | 30 ++++ validate-container-limits/suite/good.yaml | 30 ++++ validate-container-requests/README.md | 5 + validate-container-requests/kcl.mod | 4 + validate-container-requests/main.k | 44 +++++ validate-container-requests/suite/bad.yaml | 30 ++++ validate-container-requests/suite/good.yaml | 30 ++++ validate-deprecated-api/README.md | 5 + validate-deprecated-api/kcl.mod | 4 + validate-deprecated-api/main.k | 29 ++++ validate-deprecated-api/suite/bad.yaml | 54 ++++++ validate-deprecated-api/suite/good.yaml | 54 ++++++ validate-probes/README.md | 5 + validate-probes/kcl.mod | 5 + validate-probes/main.k | 12 ++ validate-probes/suite/bad.yaml | 58 +++++++ validate-probes/suite/good.yaml | 58 +++++++ web-service/README.md | 84 +++++++++ web-service/kcl.mod | 5 + web-service/main.k | 96 +++++++++++ web-service/suite/config.yaml | 20 +++ web-service/suite/good.yaml | 23 +++ whoami-yaml/README.md | 5 + whoami-yaml/kcl.mod | 5 + whoami-yaml/main.k | 42 +++++ whoami-yaml/suite/good.yaml | 11 ++ whoami/README.md | 5 + whoami/kcl.mod | 5 + whoami/main.k | 40 +++++ whoami/suite/good.yaml | 11 ++ 271 files changed, 5043 insertions(+), 4 deletions(-) create mode 100644 add-app-armor-annotation/README.md create mode 100644 add-app-armor-annotation/kcl.mod create mode 100644 add-app-armor-annotation/main.k create mode 100644 add-app-armor-annotation/suite/good.yaml create mode 100644 add-capabilities/README.md create mode 100644 add-capabilities/kcl.mod create mode 100644 add-capabilities/main.k create mode 100644 add-capabilities/suite/good.yaml create mode 100644 add-certificates-volume/README.md create mode 100644 add-certificates-volume/kcl.mod create mode 100644 add-certificates-volume/main.k create mode 100644 add-certificates-volume/suite/good.yaml create mode 100644 add-default-resources/README.md create mode 100644 add-default-resources/kcl.mod create mode 100644 add-default-resources/main.k create mode 100644 add-default-resources/suite/good.yaml create mode 100644 add-default-securitycontext/README.md create mode 100644 add-default-securitycontext/kcl.mod create mode 100644 add-default-securitycontext/main.k create mode 100644 add-default-securitycontext/suite/good.yaml create mode 100644 add-emptydir-sizelimit/README.md create mode 100644 add-emptydir-sizelimit/kcl.mod create mode 100644 add-emptydir-sizelimit/main.k create mode 100644 add-emptydir-sizelimit/suite/good.yaml create mode 100644 add-image-as-env-var/README.md create mode 100644 add-image-as-env-var/kcl.mod create mode 100644 add-image-as-env-var/main.k create mode 100644 add-image-as-env-var/suite/good.yaml create mode 100644 add-istio-sidecar-injection/README.md create mode 100644 add-istio-sidecar-injection/kcl.mod create mode 100644 add-istio-sidecar-injection/main.k create mode 100644 add-istio-sidecar-injection/suite/good.yaml create mode 100644 add-linkerd-policy-annotation/README.md create mode 100644 add-linkerd-policy-annotation/kcl.mod create mode 100644 add-linkerd-policy-annotation/main.k create mode 100644 add-linkerd-policy-annotation/suite/good.yaml create mode 100644 add-ndots/README.md create mode 100644 add-ndots/kcl.mod create mode 100644 add-ndots/main.k create mode 100644 add-ndots/suite/good.yaml create mode 100644 add-nodeselector/README.md create mode 100644 add-nodeselector/kcl.mod create mode 100644 add-nodeselector/main.k create mode 100644 add-nodeselector/suite/good.yaml create mode 100644 add-psa-labels/README.md create mode 100644 add-psa-labels/kcl.mod create mode 100644 add-psa-labels/main.k create mode 100644 add-psa-labels/suite/good.yaml create mode 100644 add-quota/README.md create mode 100644 add-quota/kcl.mod create mode 100644 add-quota/main.k create mode 100644 add-quota/suite/good.yaml create mode 100644 add-runtime-class-name/README.md create mode 100644 add-runtime-class-name/kcl.mod create mode 100644 add-runtime-class-name/main.k create mode 100644 add-runtime-class-name/suite/good.yaml create mode 100644 allowed-image-repos/README.md create mode 100644 allowed-image-repos/kcl.mod create mode 100644 allowed-image-repos/main.k create mode 100644 allowed-image-repos/suite/bad.yaml create mode 100644 allowed-image-repos/suite/good.yaml create mode 100644 append-env/README.md create mode 100644 append-env/kcl.mod create mode 100644 append-env/main.k create mode 100644 append-env/suite/good.yaml create mode 100644 conditionally-add-annotations/README.md create mode 100644 conditionally-add-annotations/kcl.mod create mode 100644 conditionally-add-annotations/main.k create mode 100644 conditionally-add-annotations/suite/config.yaml create mode 100644 conditionally-add-annotations/suite/good.yaml create mode 100644 conditionally-add-labels/README.md create mode 100644 conditionally-add-labels/kcl.mod create mode 100644 conditionally-add-labels/main.k create mode 100644 conditionally-add-labels/suite/config.yaml create mode 100644 conditionally-add-labels/suite/good.yaml create mode 100644 deny-all/README.md create mode 100644 deny-all/kcl.mod create mode 100644 deny-all/main.k create mode 100644 deny-all/suite/bad.yaml create mode 100644 deny-all/suite/good.yaml create mode 100644 deny-commands-in-exec-probe/README.md create mode 100644 deny-commands-in-exec-probe/kcl.mod create mode 100644 deny-commands-in-exec-probe/main.k create mode 100644 deny-commands-in-exec-probe/suite/bad.yaml create mode 100644 deny-commands-in-exec-probe/suite/good.yaml create mode 100644 deny-endpoint-edit-default-role/README.md create mode 100644 deny-endpoint-edit-default-role/kcl.mod create mode 100644 deny-endpoint-edit-default-role/main.k create mode 100644 deny-endpoint-edit-default-role/suite/bad.yaml create mode 100644 deny-endpoint-edit-default-role/suite/good.yaml create mode 100644 disallow-anonymous/README.md create mode 100644 disallow-anonymous/kcl.mod create mode 100644 disallow-anonymous/main.k create mode 100644 disallow-anonymous/suite/bad.yaml create mode 100644 disallow-anonymous/suite/good.yaml create mode 100644 disallow-host-ports/README.md create mode 100644 disallow-host-ports/kcl.mod create mode 100644 disallow-host-ports/main.k create mode 100644 disallow-host-ports/suite/bad.yaml create mode 100644 disallow-host-ports/suite/good.yaml create mode 100644 disallow-ingress-wildcard/README.md create mode 100644 disallow-ingress-wildcard/kcl.mod create mode 100644 disallow-ingress-wildcard/main.k create mode 100644 disallow-ingress-wildcard/suite/bad.yaml create mode 100644 disallow-ingress-wildcard/suite/good.yaml create mode 100644 disallow-privileged-containers/README.md create mode 100644 disallow-privileged-containers/kcl.mod create mode 100644 disallow-privileged-containers/main.k create mode 100644 disallow-privileged-containers/suite/bad.yaml create mode 100644 disallow-privileged-containers/suite/good.yaml create mode 100644 disallow-svc-lb/README.md create mode 100644 disallow-svc-lb/kcl.mod create mode 100644 disallow-svc-lb/main.k create mode 100644 disallow-svc-lb/suite/bad.yaml create mode 100644 disallow-svc-lb/suite/good.yaml create mode 100644 disallow-svc-node-port/README.md create mode 100644 disallow-svc-node-port/kcl.mod create mode 100644 disallow-svc-node-port/main.k create mode 100644 disallow-svc-node-port/suite/bad.yaml create mode 100644 disallow-svc-node-port/suite/good.yaml create mode 100644 disallowed-image-repos/README.md create mode 100644 disallowed-image-repos/kcl.mod create mode 100644 disallowed-image-repos/main.k create mode 100644 disallowed-image-repos/suite/bad.yaml create mode 100644 disallowed-image-repos/suite/good.yaml create mode 100644 external-ips/README.md create mode 100644 external-ips/kcl.mod create mode 100644 external-ips/main.k create mode 100644 external-ips/suite/bad.yaml create mode 100644 external-ips/suite/config.yaml create mode 100644 external-ips/suite/good.yaml create mode 100644 horizontal-pod-auto-scaler/README.md create mode 100644 horizontal-pod-auto-scaler/kcl.mod create mode 100644 horizontal-pod-auto-scaler/main.k create mode 100644 horizontal-pod-auto-scaler/suite/bad.yaml create mode 100644 horizontal-pod-auto-scaler/suite/good.yaml create mode 100644 https-only/README.md create mode 100644 https-only/kcl.mod create mode 100644 https-only/main.k create mode 100644 https-only/suite/bad.yaml create mode 100644 https-only/suite/config.yaml create mode 100644 https-only/suite/good.yaml create mode 100644 insert-pod-antiaffinity/README.md create mode 100644 insert-pod-antiaffinity/kcl.mod create mode 100644 insert-pod-antiaffinity/main.k create mode 100644 insert-pod-antiaffinity/suite/good.yaml create mode 100644 k8s_manifests_containers/README.md create mode 100644 k8s_manifests_containers/kcl.mod create mode 100644 k8s_manifests_containers/main.k create mode 100644 merge/README.md create mode 100644 merge/kcl.mod create mode 100644 merge/main.k create mode 100644 nginx-ingress/README.md create mode 100644 nginx-ingress/restrict-ingress-annotations/README.md create mode 100644 nginx-ingress/restrict-ingress-annotations/kcl.mod create mode 100644 nginx-ingress/restrict-ingress-annotations/main.k create mode 100644 nginx-ingress/restrict-ingress-annotations/suite/bad.yaml create mode 100644 nginx-ingress/restrict-ingress-annotations/suite/good.yaml create mode 100644 nginx-ingress/restrict-ingress-paths/README.md create mode 100644 nginx-ingress/restrict-ingress-paths/kcl.mod create mode 100644 nginx-ingress/restrict-ingress-paths/main.k create mode 100644 nginx-ingress/restrict-ingress-paths/suite/bad.yaml create mode 100644 nginx-ingress/restrict-ingress-paths/suite/good.yaml create mode 100644 pod-security-policy/selinux/README.md create mode 100644 pod-security-policy/selinux/kcl.mod create mode 100644 pod-security-policy/selinux/main.k create mode 100644 pod-security-policy/selinux/suite/good.yaml create mode 100644 psp-allow-privilege-escalation/README.md create mode 100644 psp-allow-privilege-escalation/kcl.mod create mode 100644 psp-allow-privilege-escalation/main.k create mode 100644 psp-allow-privilege-escalation/suite/bad.yaml create mode 100644 psp-allow-privilege-escalation/suite/good.yaml create mode 100644 psp-app-armor/README.md create mode 100644 psp-app-armor/kcl.mod create mode 100644 psp-app-armor/main.k create mode 100644 psp-app-armor/suite/bad.yaml create mode 100644 psp-app-armor/suite/good.yaml create mode 100644 psp-capabilities/README.md create mode 100644 psp-capabilities/kcl.mod create mode 100644 psp-capabilities/main.k create mode 100644 psp-capabilities/suite/bad.yaml create mode 100644 psp-capabilities/suite/good.yaml create mode 100644 psp-flexvolume-drivers/README.md create mode 100644 psp-flexvolume-drivers/kcl.mod create mode 100644 psp-flexvolume-drivers/main.k create mode 100644 psp-flexvolume-drivers/suite/bad.yaml create mode 100644 psp-flexvolume-drivers/suite/good.yaml create mode 100644 readonly-root-fs/README.md create mode 100644 readonly-root-fs/kcl.mod create mode 100644 readonly-root-fs/main.k create mode 100644 readonly-root-fs/suite/good.yaml create mode 100644 replica-limits/README.md create mode 100644 replica-limits/kcl.mod create mode 100644 replica-limits/main.k create mode 100644 replica-limits/suite/bad.yaml create mode 100644 replica-limits/suite/config.yaml create mode 100644 replica-limits/suite/good.yaml create mode 100644 required-annotations/README.md create mode 100644 required-annotations/kcl.mod create mode 100644 required-annotations/main.k create mode 100644 required-annotations/suite/bad.yaml create mode 100644 required-annotations/suite/config.yaml create mode 100644 required-annotations/suite/good.yaml create mode 100644 required-image-digests/README.md create mode 100644 required-image-digests/kcl.mod create mode 100644 required-image-digests/main.k create mode 100644 required-image-digests/suite/bad.yaml create mode 100644 required-image-digests/suite/good.yaml create mode 100644 required-labels/README.md create mode 100644 required-labels/kcl.mod create mode 100644 required-labels/main.k create mode 100644 required-labels/suite/bad.yaml create mode 100644 required-labels/suite/config.yaml create mode 100644 required-labels/suite/good.yaml create mode 100644 required-probes/README.md create mode 100644 required-probes/kcl.mod create mode 100644 required-probes/main.k create mode 100644 required-probes/suite/bad.yaml create mode 100644 required-probes/suite/good.yaml create mode 100644 set-labels/README.md create mode 100644 set-labels/kcl.mod create mode 100644 set-labels/main.k create mode 100644 set-labels/suite/config.yaml create mode 100644 set-labels/suite/good.yaml create mode 100644 set-replicas/README.md create mode 100644 set-replicas/kcl.mod create mode 100644 set-replicas/main.k create mode 100644 set-replicas/suite/config.yaml create mode 100644 set-replicas/suite/good.yaml create mode 100644 validate-auto-mount-service-account-token/README.md create mode 100644 validate-auto-mount-service-account-token/kcl.mod create mode 100644 validate-auto-mount-service-account-token/main.k create mode 100644 validate-auto-mount-service-account-token/suite/bad.yaml create mode 100644 validate-auto-mount-service-account-token/suite/good.yaml create mode 100644 validate-container-limits/README.md create mode 100644 validate-container-limits/kcl.mod create mode 100644 validate-container-limits/main.k create mode 100644 validate-container-limits/suite/bad.yaml create mode 100644 validate-container-limits/suite/good.yaml create mode 100644 validate-container-requests/README.md create mode 100644 validate-container-requests/kcl.mod create mode 100644 validate-container-requests/main.k create mode 100644 validate-container-requests/suite/bad.yaml create mode 100644 validate-container-requests/suite/good.yaml create mode 100644 validate-deprecated-api/README.md create mode 100644 validate-deprecated-api/kcl.mod create mode 100644 validate-deprecated-api/main.k create mode 100644 validate-deprecated-api/suite/bad.yaml create mode 100644 validate-deprecated-api/suite/good.yaml create mode 100644 validate-probes/README.md create mode 100644 validate-probes/kcl.mod create mode 100644 validate-probes/main.k create mode 100644 validate-probes/suite/bad.yaml create mode 100644 validate-probes/suite/good.yaml create mode 100644 web-service/README.md create mode 100644 web-service/kcl.mod create mode 100644 web-service/main.k create mode 100644 web-service/suite/config.yaml create mode 100644 web-service/suite/good.yaml create mode 100644 whoami-yaml/README.md create mode 100644 whoami-yaml/kcl.mod create mode 100644 whoami-yaml/main.k create mode 100644 whoami-yaml/suite/good.yaml create mode 100644 whoami/README.md create mode 100644 whoami/kcl.mod create mode 100644 whoami/main.k create mode 100644 whoami/suite/good.yaml diff --git a/.gitignore b/.gitignore index 1d74e219..521192c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,17 @@ -.vscode/ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ +.kclvm +.DS_store diff --git a/add-app-armor-annotation/README.md b/add-app-armor-annotation/README.md new file mode 100644 index 00000000..ecd84aea --- /dev/null +++ b/add-app-armor-annotation/README.md @@ -0,0 +1,38 @@ +## Introduction + +`add-app-armor-annotation` is a kcl mutation package, which can be used to add apparmor annotations for the Kubernetes resources. + +In the earlier Pod Security Policy controller, it was possible to define +a setting which would enable AppArmor for all the containers within a Pod so +they may be assigned the desired profile. Assigning an AppArmor profile, accomplished +via an annotation, is useful in that it allows secure defaults to be defined and may +also result in passing other validation rules such as those in the Pod Security Standards. +This policy mutates Pods to add an annotation for every container to enabled AppArmor +at the runtime/default level. + +The KCL code is as follows: + +```python +capabilities: [str] = option("params")?.capabilities or ["SETUID", "SETFCAP"] +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + metadata.annotations: { + "container.apparmor.security.beta.kubernetes.io/${container.name}": "runtime/default" + } + } for container in item.spec.containers] +} for item in option("items") or []] +``` + +## How to Use + +Add the source into your `KCLRun` resource and use the [kubectl kcl plugin](https://kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kubectl-kcl-plugin) or the [kcl operator](https://kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kcl-operator) to integrate this model. + +```yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-app-armor-annotation +spec: + source: oci://ghcr.io/kcl-lang/add-app-armor-annotation +``` diff --git a/add-app-armor-annotation/kcl.mod b/add-app-armor-annotation/kcl.mod new file mode 100644 index 00000000..f35ac622 --- /dev/null +++ b/add-app-armor-annotation/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-app-armor-annotation" +edition = "*" +version = "0.1.0" +description = "`add-app-armor-annotation` is a kcl mutation package, which can be used to add apparmor annotations for the Kubernetes resources." diff --git a/add-app-armor-annotation/main.k b/add-app-armor-annotation/main.k new file mode 100644 index 00000000..979d14e7 --- /dev/null +++ b/add-app-armor-annotation/main.k @@ -0,0 +1,9 @@ +capabilities: [str] = option("params")?.capabilities or ["SETUID", "SETFCAP"] +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + metadata.annotations: { + "container.apparmor.security.beta.kubernetes.io/${container.name}": "runtime/default" + } + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/add-app-armor-annotation/suite/good.yaml b/add-app-armor-annotation/suite/good.yaml new file mode 100644 index 00000000..acb34793 --- /dev/null +++ b/add-app-armor-annotation/suite/good.yaml @@ -0,0 +1,28 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-app-armor-annotation + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + In the earlier Pod Security Policy controller, it was possible to define + a setting which would enable AppArmor for all the containers within a Pod so + they may be assigned the desired profile. Assigning an AppArmor profile, accomplished + via an annotation, is useful in that it allows secure defaults to be defined and may + also result in passing other validation rules such as those in the Pod Security Standards. + This policy mutates Pods to add an annotation for every container to enabled AppArmor + at the runtime/default level. +spec: + source: ./examples/mutation/add-app-armor-annotation/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-capabilities/README.md b/add-capabilities/README.md new file mode 100644 index 00000000..05193281 --- /dev/null +++ b/add-capabilities/README.md @@ -0,0 +1,16 @@ +## Introduction + +`add-capabilities` is a kcl mutation package. + +## How to Use + +Add the source into your `KCLRun` resource and use the [kubectl kcl plugin](https://kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kubectl-kcl-plugin) or the [kcl operator](https://kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kcl-operator) to integrate this model. + +```yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-capabilities +spec: + source: oci://ghcr.io/kcl-lang/add-capabilities +``` diff --git a/add-capabilities/kcl.mod b/add-capabilities/kcl.mod new file mode 100644 index 00000000..675bfc6c --- /dev/null +++ b/add-capabilities/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-capabilities" +edition = "*" +version = "0.1.0" +description = "`add-capabilities` is a kcl mutation package." diff --git a/add-capabilities/main.k b/add-capabilities/main.k new file mode 100644 index 00000000..84dad320 --- /dev/null +++ b/add-capabilities/main.k @@ -0,0 +1,7 @@ +capabilities: [str] = option("params")?.capabilities or ["SETUID", "SETFCAP"] +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + "securityContext": {"capabilities": {"add" += [c] if c not in (container?.securityContext?.capabilities?.drop or []) else [] for c in capabilities}} + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/add-capabilities/suite/good.yaml b/add-capabilities/suite/good.yaml new file mode 100644 index 00000000..96e02426 --- /dev/null +++ b/add-capabilities/suite/good.yaml @@ -0,0 +1,26 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-capabilities + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + In the earlier Pod Security Policy controller, it was possible to configure a policy + to add capabilities to containers within a Pod. This made it easier to assign some basic defaults + rather than blocking Pods or to simply provide capabilities for certain workloads if not specified. + This policy mutates Pods to add the capabilities SETFCAP and SETUID so long as they are not listed + as dropped capabilities first. +spec: + source: ./examples/mutation/add-capabilities/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-certificates-volume/README.md b/add-certificates-volume/README.md new file mode 100644 index 00000000..c63052fa --- /dev/null +++ b/add-certificates-volume/README.md @@ -0,0 +1,16 @@ +## Introduction + +`add-certificates-volume` is a kcl mutation package. + +## How to Use + +Add the source into your `KCLRun` resource and use the [kubectl kcl plugin](https://kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kubectl-kcl-plugin) or the [kcl operator](https://kcl-lang.io/docs/user_docs/guides/working-with-k8s/mutate-manifests/kcl-operator) to integrate this model. + +```yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-certificates-volume +spec: + source: oci://ghcr.io/kcl-lang/add-certificates-volume +``` diff --git a/add-certificates-volume/kcl.mod b/add-certificates-volume/kcl.mod new file mode 100644 index 00000000..b7174045 --- /dev/null +++ b/add-certificates-volume/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-certificates-volume" +edition = "*" +version = "0.1.0" +description = "`add-certificates-volume` is a kcl mutation package." diff --git a/add-certificates-volume/main.k b/add-certificates-volume/main.k new file mode 100644 index 00000000..a1812af4 --- /dev/null +++ b/add-certificates-volume/main.k @@ -0,0 +1,13 @@ +items = [item | { + if item.kind == "Pod": + spec.volumes += [{ + name = "etc-ssl-certs" + configMap.name = "ca-pemstore" + }] + spec.containers: [{ + volumeMounts += [{ + name = "etc-ssl-certs" + mountPath = "/etc/ssl/certs" + }] + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/add-certificates-volume/suite/good.yaml b/add-certificates-volume/suite/good.yaml new file mode 100644 index 00000000..24b006d2 --- /dev/null +++ b/add-certificates-volume/suite/good.yaml @@ -0,0 +1,27 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-certificates-volume + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + In some cases you would need to trust custom CA certificates for all the containers of a Pod. + It makes sense to be in a ConfigMap so that you can automount them by only setting an annotation. + This policy adds a volume to all containers in a Pod containing the certificate if the annotation + called `inject-certs` with value `enabled` is found. +spec: + source: ./examples/mutation/add-certificates-volume/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx + annotations: + inject-certs: "enabled" +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-default-resources/README.md b/add-default-resources/README.md new file mode 100644 index 00000000..8e0e18b3 --- /dev/null +++ b/add-default-resources/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-default-resources) diff --git a/add-default-resources/kcl.mod b/add-default-resources/kcl.mod new file mode 100644 index 00000000..2d7e5b3e --- /dev/null +++ b/add-default-resources/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-default-resources" +edition = "*" +version = "0.1.0" +description = "`add-default-resources` is a kcl mutation package" diff --git a/add-default-resources/main.k b/add-default-resources/main.k new file mode 100644 index 00000000..a00001d8 --- /dev/null +++ b/add-default-resources/main.k @@ -0,0 +1,9 @@ +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + resources.requests: { + memory = "100Mi" + cpu = "100m" + } + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/add-default-resources/suite/good.yaml b/add-default-resources/suite/good.yaml new file mode 100644 index 00000000..2584dc65 --- /dev/null +++ b/add-default-resources/suite/good.yaml @@ -0,0 +1,28 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-default-resources + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Pods which don't specify at least resource requests are assigned a QoS class + of BestEffort which can hog resources for other Pods on Nodes. At a minimum, + all Pods should specify resource requests in order to be labeled as the QoS + class Burstable. This sample mutates any container in a Pod which doesn't + specify memory or cpu requests to apply some sane defaults. +spec: + source: ./examples/mutation/add-default-resources/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + - name: kcl + image: kcllang/kcl diff --git a/add-default-securitycontext/README.md b/add-default-securitycontext/README.md new file mode 100644 index 00000000..27d2a59f --- /dev/null +++ b/add-default-securitycontext/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-default-securitycontext) diff --git a/add-default-securitycontext/kcl.mod b/add-default-securitycontext/kcl.mod new file mode 100644 index 00000000..5ee599d2 --- /dev/null +++ b/add-default-securitycontext/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-default-securitycontext" +edition = "*" +version = "0.1.0" +description = "`add-default-securitycontext` is a kcl mutation package" diff --git a/add-default-securitycontext/main.k b/add-default-securitycontext/main.k new file mode 100644 index 00000000..c7f5f989 --- /dev/null +++ b/add-default-securitycontext/main.k @@ -0,0 +1,9 @@ +items = [item | { + if item.kind == "Pod": + spec.securityContext: { + runAsNonRoot = True + runAsUser = 1000 + runAsGroup = 3000 + fsGroup = 2000 + } +} for item in option("items") or []] diff --git a/add-default-securitycontext/suite/good.yaml b/add-default-securitycontext/suite/good.yaml new file mode 100644 index 00000000..bdecb248 --- /dev/null +++ b/add-default-securitycontext/suite/good.yaml @@ -0,0 +1,27 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-default-securitycontext + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + A Pod securityContext entry defines fields such as the user and group which should be used to run the Pod. + Sometimes choosing default values for users rather than blocking is a better alternative to not impede + such Pod definitions. This policy will mutate a Pod to set `runAsNonRoot`, `runAsUser`, `runAsGroup`, and + `fsGroup` fields within the Pod securityContext if they are not already set. +spec: + source: ./examples/mutation/add-default-securitycontext/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + - name: kcl + image: kcllang/kcl diff --git a/add-emptydir-sizelimit/README.md b/add-emptydir-sizelimit/README.md new file mode 100644 index 00000000..7a5d010a --- /dev/null +++ b/add-emptydir-sizelimit/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-emptydir-sizelimit) diff --git a/add-emptydir-sizelimit/kcl.mod b/add-emptydir-sizelimit/kcl.mod new file mode 100644 index 00000000..57702515 --- /dev/null +++ b/add-emptydir-sizelimit/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-emptydir-sizelimit" +edition = "*" +version = "0.1.0" +description = "`add-emptydir-sizelimit` is a kcl mutation package" diff --git a/add-emptydir-sizelimit/main.k b/add-emptydir-sizelimit/main.k new file mode 100644 index 00000000..a1bcbd9d --- /dev/null +++ b/add-emptydir-sizelimit/main.k @@ -0,0 +1,7 @@ +items = [item | { + if item.kind == "Pod": + spec.volumes: [{ + if "emptyDir" in v and (v?.emptyDir?.sizeLimit or "") != "100Mi": + emptyDir.sizeLimit = "100Mi" + } for v in item.spec.volumes or []] or Undefined +} for item in option("items") or []] diff --git a/add-emptydir-sizelimit/suite/good.yaml b/add-emptydir-sizelimit/suite/good.yaml new file mode 100644 index 00000000..026c2bcc --- /dev/null +++ b/add-emptydir-sizelimit/suite/good.yaml @@ -0,0 +1,31 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-emptydir-sizelimit + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + When a Pod requests an emptyDir, by default it does not have a size limit which + may allow it to consume excess or all of the space in the medium backing the volume. + This can quickly overrun a Node and may result in a denial of service for other + workloads. This policy adds a sizeLimit field to all Pods mounting emptyDir + volumes, if not present, and sets it to 100Mi. +spec: + source: ./examples/mutation/add-emptydir-sizelimit/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + - name: kcl + image: kcllang/kcl + volumes: + - emptyDir: {} + name: wordpress-persistent-storage diff --git a/add-image-as-env-var/README.md b/add-image-as-env-var/README.md new file mode 100644 index 00000000..41b91af4 --- /dev/null +++ b/add-image-as-env-var/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-image-as-env-var) diff --git a/add-image-as-env-var/kcl.mod b/add-image-as-env-var/kcl.mod new file mode 100644 index 00000000..fc4c0bdf --- /dev/null +++ b/add-image-as-env-var/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-image-as-env-var" +edition = "*" +version = "0.1.0" +description = "`add-image-as-env-var` is a kcl mutation package" diff --git a/add-image-as-env-var/main.k b/add-image-as-env-var/main.k new file mode 100644 index 00000000..5087b199 --- /dev/null +++ b/add-image-as-env-var/main.k @@ -0,0 +1,9 @@ +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + env += [{ + name = "K8S_IMAGE" + value = container.image + }] + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/add-image-as-env-var/suite/good.yaml b/add-image-as-env-var/suite/good.yaml new file mode 100644 index 00000000..6429e931 --- /dev/null +++ b/add-image-as-env-var/suite/good.yaml @@ -0,0 +1,26 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-image-as-env-var + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + The Kubernetes downward API only has the ability to express so many + options as environment variables. The image consumed in a Pod is commonly + needed to make the application aware of some logic it must take. This policy + takes the value of the `image` field and adds it as an environment variable + to Pods. +spec: + source: ./examples/mutation/add-image-as-env-var/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-istio-sidecar-injection/README.md b/add-istio-sidecar-injection/README.md new file mode 100644 index 00000000..886a0dd9 --- /dev/null +++ b/add-istio-sidecar-injection/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-istio-sidecar-injection) diff --git a/add-istio-sidecar-injection/kcl.mod b/add-istio-sidecar-injection/kcl.mod new file mode 100644 index 00000000..38e6e1c6 --- /dev/null +++ b/add-istio-sidecar-injection/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-istio-sidecar-injection" +edition = "*" +version = "0.1.0" +description = "`add-istio-sidecar-injection` is a kcl mutation package" diff --git a/add-istio-sidecar-injection/main.k b/add-istio-sidecar-injection/main.k new file mode 100644 index 00000000..3d170e91 --- /dev/null +++ b/add-istio-sidecar-injection/main.k @@ -0,0 +1,6 @@ +items = [item | { + if item.kind == "Namespace": + metadata.labels: { + "istio-injection" = "enabled" + } +} for item in option("items")] diff --git a/add-istio-sidecar-injection/suite/good.yaml b/add-istio-sidecar-injection/suite/good.yaml new file mode 100644 index 00000000..8db96d70 --- /dev/null +++ b/add-istio-sidecar-injection/suite/good.yaml @@ -0,0 +1,20 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-istio-sidecar-injection + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + In order for Istio to inject sidecars to workloads deployed into Namespaces, + the label `istio-injection` must be set to `enabled`. As an alternative to + rejecting Namespace definitions which don't already contain this label, + it can be added automatically. This policy adds the label `istio-inject` + set to `enabled` for all new Namespaces. +spec: + source: ./examples/mutation/add-istio-sidecar-injection/main.k +--- +apiVersion: v1 +kind: Namespace +metadata: + name: sampleapp diff --git a/add-linkerd-policy-annotation/README.md b/add-linkerd-policy-annotation/README.md new file mode 100644 index 00000000..4348d398 --- /dev/null +++ b/add-linkerd-policy-annotation/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-linkerd-policy-annotation) diff --git a/add-linkerd-policy-annotation/kcl.mod b/add-linkerd-policy-annotation/kcl.mod new file mode 100644 index 00000000..4c0b263e --- /dev/null +++ b/add-linkerd-policy-annotation/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-linkerd-policy-annotation" +edition = "*" +version = "0.1.0" +description = "`add-linkerd-policy-annotation` is a kcl mutation package" diff --git a/add-linkerd-policy-annotation/main.k b/add-linkerd-policy-annotation/main.k new file mode 100644 index 00000000..96710f0a --- /dev/null +++ b/add-linkerd-policy-annotation/main.k @@ -0,0 +1,5 @@ +items = [item | { + metadata.annotations: { + "config.linkerd.io/default-inbound-policy" = "deny" + } +} for item in option("items")] diff --git a/add-linkerd-policy-annotation/suite/good.yaml b/add-linkerd-policy-annotation/suite/good.yaml new file mode 100644 index 00000000..1df9b6d8 --- /dev/null +++ b/add-linkerd-policy-annotation/suite/good.yaml @@ -0,0 +1,22 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-linkerd-policy-annotation + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Add Linkerd Policy Annotation +spec: + source: ./examples/mutation/add-linkerd-policy-annotation/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-ndots/README.md b/add-ndots/README.md new file mode 100644 index 00000000..e47ff397 --- /dev/null +++ b/add-ndots/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-ndots) diff --git a/add-ndots/kcl.mod b/add-ndots/kcl.mod new file mode 100644 index 00000000..3e67e0f7 --- /dev/null +++ b/add-ndots/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-ndots" +edition = "*" +version = "0.1.0" +description = "`add-ndots` is a kcl mutation package" diff --git a/add-ndots/main.k b/add-ndots/main.k new file mode 100644 index 00000000..a5c73c1c --- /dev/null +++ b/add-ndots/main.k @@ -0,0 +1,9 @@ +items = [item | { + if item.kind == "Pod": + spec.dnsConfig.options += [ + { + name = "ndots" + value: "1" + } + ] +} for item in option("items")] diff --git a/add-ndots/suite/good.yaml b/add-ndots/suite/good.yaml new file mode 100644 index 00000000..6fcddbf1 --- /dev/null +++ b/add-ndots/suite/good.yaml @@ -0,0 +1,24 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-ndots + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + The ndots value controls where DNS lookups are first performed in a cluster + and needs to be set to a lower value than the default of 5 in some cases. + This policy mutates all Pods to add the ndots option with a value of 1. +spec: + source: ./examples/mutation/add-ndots/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-nodeselector/README.md b/add-nodeselector/README.md new file mode 100644 index 00000000..77461efb --- /dev/null +++ b/add-nodeselector/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-nodeselector) diff --git a/add-nodeselector/kcl.mod b/add-nodeselector/kcl.mod new file mode 100644 index 00000000..69037c75 --- /dev/null +++ b/add-nodeselector/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "add-nodeselector" +version = "0.1.0" +description = "`add-nodeselector` is a kcl mutation package" diff --git a/add-nodeselector/main.k b/add-nodeselector/main.k new file mode 100644 index 00000000..00b2c5f8 --- /dev/null +++ b/add-nodeselector/main.k @@ -0,0 +1,7 @@ +params = option("params") or {} +# Use `k = v` to override existing selector +selector: {str:str} = {k = v for k, v in params.selector or {}} +items = [item | { + if item.kind == "Pod": + spec.nodeSelector: selector +} for item in option("items")] diff --git a/add-nodeselector/suite/good.yaml b/add-nodeselector/suite/good.yaml new file mode 100644 index 00000000..618e12ce --- /dev/null +++ b/add-nodeselector/suite/good.yaml @@ -0,0 +1,25 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-nodeselector + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Add nodeselector +spec: + params: + selector: + foo: bar + source: ./examples/mutation/add-nodeselector/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/add-psa-labels/README.md b/add-psa-labels/README.md new file mode 100644 index 00000000..5938e2fc --- /dev/null +++ b/add-psa-labels/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-psa-labels) diff --git a/add-psa-labels/kcl.mod b/add-psa-labels/kcl.mod new file mode 100644 index 00000000..df0069ed --- /dev/null +++ b/add-psa-labels/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-psa-labels" +edition = "*" +version = "0.1.0" +description = "`add-psa-labels` is a kcl mutation package" diff --git a/add-psa-labels/main.k b/add-psa-labels/main.k new file mode 100644 index 00000000..69ca7dca --- /dev/null +++ b/add-psa-labels/main.k @@ -0,0 +1,7 @@ +items = [item | { + if item.kind == "Namespace": + metadata.labels: { + "pod-security.kubernetes.io/enforce" = "baseline" + "pod-security.kubernetes.io/warn" = "restricted" + } +} for item in option("items")] diff --git a/add-psa-labels/suite/good.yaml b/add-psa-labels/suite/good.yaml new file mode 100644 index 00000000..d8747745 --- /dev/null +++ b/add-psa-labels/suite/good.yaml @@ -0,0 +1,22 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-psa-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Pod Security Admission (PSA) can be controlled via the assignment of labels + at the Namespace level which define the Pod Security Standard (PSS) profile + in use and the action to take. If not using a cluster-wide configuration + via an AdmissionConfiguration file, Namespaces must be explicitly labeled. + This policy assigns the labels `pod-security.kubernetes.io/enforce=baseline` + and `pod-security.kubernetes.io/warn=restricted` to all new Namespaces if + those labels are not included. +spec: + source: ./examples/mutation/add-psa-labels/main.k +--- +apiVersion: v1 +kind: Namespace +metadata: + name: sampleapp diff --git a/add-quota/README.md b/add-quota/README.md new file mode 100644 index 00000000..de134e70 --- /dev/null +++ b/add-quota/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-quota) diff --git a/add-quota/kcl.mod b/add-quota/kcl.mod new file mode 100644 index 00000000..6dcdd57a --- /dev/null +++ b/add-quota/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "add-quota" +version = "0.1.0" +description = "`add-quota` is a kcl mutation package" diff --git a/add-quota/main.k b/add-quota/main.k new file mode 100644 index 00000000..4a923223 --- /dev/null +++ b/add-quota/main.k @@ -0,0 +1,36 @@ +ns_list = [item.metadata.name for item in option("items") if item.kind == "Namespace"] + +items = option("items") + [ + { + apiVersion: "v1" + kind: "ResourceQuota" + name: "default-resourcequota" + synchronize: True + namespace: ns + data.spec.hard: { + 'requests.cpu': '4' + 'requests.memory': str(16Gi) + 'limits.cpu': '4' + 'limits.memory': str(16Gi) + } + } for ns in ns_list +] + [ + { + apiVersion: "v1" + kind: "LimitRange" + name: "default-limitrange" + synchronize: True + namespace: ns + data.spec.limits = [{ + default: { + cpu: str(500m) + memory: str(1Gi) + } + defaultRequest: { + cpu: str(200m) + memory: str(256Mi) + } + type: "Container" + }] + } for ns in ns_list +] diff --git a/add-quota/suite/good.yaml b/add-quota/suite/good.yaml new file mode 100644 index 00000000..a04029c2 --- /dev/null +++ b/add-quota/suite/good.yaml @@ -0,0 +1,16 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-quota + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Add quota +spec: + source: ./examples/mutation/add-quota/main.k +--- +apiVersion: v1 +kind: Namespace +metadata: + name: sampleapp diff --git a/add-runtime-class-name/README.md b/add-runtime-class-name/README.md new file mode 100644 index 00000000..7920f56d --- /dev/null +++ b/add-runtime-class-name/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/add-runtime-class-name) diff --git a/add-runtime-class-name/kcl.mod b/add-runtime-class-name/kcl.mod new file mode 100644 index 00000000..a0649b4d --- /dev/null +++ b/add-runtime-class-name/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-runtime-class-name" +edition = "*" +version = "0.1.0" +description = "`add-runtime-class-name` is a kcl mutation package" diff --git a/add-runtime-class-name/main.k b/add-runtime-class-name/main.k new file mode 100644 index 00000000..0d08d551 --- /dev/null +++ b/add-runtime-class-name/main.k @@ -0,0 +1,4 @@ +items = [item | { + if item.kind == "Pod": + spec.runtimeClassName = option("params").name or "prodclass" +} for item in option("items") or []] diff --git a/add-runtime-class-name/suite/good.yaml b/add-runtime-class-name/suite/good.yaml new file mode 100644 index 00000000..78f73872 --- /dev/null +++ b/add-runtime-class-name/suite/good.yaml @@ -0,0 +1,27 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: add-runtime-class-name + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + In the earlier Pod Security Policy controller, it was possible to configure a policy to add + a Pod's runtimeClassName. This was beneficial in that various container runtimes could be + specified according to a policy. This Kyverno policies mutates Pods to add a runtimeClassName + of `prodclass`. +spec: + params: + name: runc + source: ./examples/mutation/add-runtime-class-name/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/allowed-image-repos/README.md b/allowed-image-repos/README.md new file mode 100644 index 00000000..210272af --- /dev/null +++ b/allowed-image-repos/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/allowed-image-repos) diff --git a/allowed-image-repos/kcl.mod b/allowed-image-repos/kcl.mod new file mode 100644 index 00000000..7e0b58e2 --- /dev/null +++ b/allowed-image-repos/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "allowed-image-repos" +version = "0.1.0" +description = "`allowed-image-repos` is a kcl validation package" diff --git a/allowed-image-repos/main.k b/allowed-image-repos/main.k new file mode 100644 index 00000000..dcbfcaf6 --- /dev/null +++ b/allowed-image-repos/main.k @@ -0,0 +1,25 @@ +"""Requires container images to begin with a string from the specified list. + +Ref: https://github.com/open-policy-agent/gatekeeper-library/blob/master/src/general/allowedrepos/constraint.tmpl +""" + +# The list of prefixes a container image is allowed to have. +repos: [str] = option("params").repos or [] + +# Define the validation function +validate = lambda item { + containers = [] + if item.kind == "Pod" and repos: + containers = (item.spec.containers or []) + (item.spec.phemeralContainers or []) + (item.spec.initContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.phemeralContainers or []) + (item.spec.template.spec.initContainers or []) + images: [str] = [c.image for c in containers] + assert all image in images { + all repo in repos { + image.startswith(repo) + } + } if images and repos, """Use of image is disallowed for ${item.kind}: ${item.metadata.name}, valid repos ${repos}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/allowed-image-repos/suite/bad.yaml b/allowed-image-repos/suite/bad.yaml new file mode 100644 index 00000000..71bdc3d9 --- /dev/null +++ b/allowed-image-repos/suite/bad.yaml @@ -0,0 +1,38 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: allowed-image-repos + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires container images to begin with a string from the specified list. + + Ref: https://github.com/open-policy-agent/gatekeeper-library/blob/master/src/general/allowedrepos/constraint.tmpl +spec: + params: + repos: + - nginx + source: ./examples/validation/allowed-image-repos/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deploy + labels: + app: kcl +spec: + replicas: 3 + selector: + matchLabels: + app: kcl + template: + metadata: + labels: + app: kcl + spec: + containers: + - name: kcl + image: kcllang/kcl + ports: + - containerPort: 80 diff --git a/allowed-image-repos/suite/good.yaml b/allowed-image-repos/suite/good.yaml new file mode 100644 index 00000000..fbce9a15 --- /dev/null +++ b/allowed-image-repos/suite/good.yaml @@ -0,0 +1,38 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: allowed-image-repos + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires container images to begin with a string from the specified list. + + Ref: https://github.com/open-policy-agent/gatekeeper-library/blob/master/src/general/allowedrepos/constraint.tmpl +spec: + params: + repos: + - nginx + source: ./examples/validation/allowed-image-repos/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deploy + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/append-env/README.md b/append-env/README.md new file mode 100644 index 00000000..5e74b56f --- /dev/null +++ b/append-env/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/append-env) diff --git a/append-env/kcl.mod b/append-env/kcl.mod new file mode 100644 index 00000000..5e7643a0 --- /dev/null +++ b/append-env/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "append-env" +edition = "*" +version = "0.1.0" +description = "`append-env` is a kcl mutation package" diff --git a/append-env/main.k b/append-env/main.k new file mode 100644 index 00000000..77e04d5d --- /dev/null +++ b/append-env/main.k @@ -0,0 +1,10 @@ +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + env += option("params").env + } for container in item.spec.containers] + elif item.kind == "Deployment": + spec.template.spec.containers: [{ + env += option("params").env + } for container in item.spec.template.spec.containers] +} for item in option("items") or []] diff --git a/append-env/suite/good.yaml b/append-env/suite/good.yaml new file mode 100644 index 00000000..03c306b9 --- /dev/null +++ b/append-env/suite/good.yaml @@ -0,0 +1,37 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: append-env + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Append env list for `Pod` and `Deployment` resources +spec: + params: + env: + name: test_name + value: test_value + source: ./examples/mutation/append-env/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/conditionally-add-annotations/README.md b/conditionally-add-annotations/README.md new file mode 100644 index 00000000..026af864 --- /dev/null +++ b/conditionally-add-annotations/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/conditionally-add-annotations) diff --git a/conditionally-add-annotations/kcl.mod b/conditionally-add-annotations/kcl.mod new file mode 100644 index 00000000..e88737d6 --- /dev/null +++ b/conditionally-add-annotations/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "conditionally-add-annotations" +edition = "*" +version = "0.1.0" +description = "`conditionally-add-annotations` is a kcl mutation package" diff --git a/conditionally-add-annotations/main.k b/conditionally-add-annotations/main.k new file mode 100644 index 00000000..fe6c24e9 --- /dev/null +++ b/conditionally-add-annotations/main.k @@ -0,0 +1,10 @@ +params = option("params") or {} +toMatch = params.toMatch or {} +toAdd = params.toAdd or {} +items = [item | { + # If all annotations are matched, patch more annotations + if all key, value in toMatch { + item.metadata.annotations[key] == value + }: + metadata.annotations: toAdd +} for item in option("items") or []] diff --git a/conditionally-add-annotations/suite/config.yaml b/conditionally-add-annotations/suite/config.yaml new file mode 100644 index 00000000..d8b62857 --- /dev/null +++ b/conditionally-add-annotations/suite/config.yaml @@ -0,0 +1,16 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: conditionally-add-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Conditionally add annotations +spec: + params: + toMatch: + config.kubernetes.io/local-config: "true" + toAdd: + configmanagement.gke.io/managed: disabled + source: oci://ghcr.io/kcl-lang/conditionally-add-annotations diff --git a/conditionally-add-annotations/suite/good.yaml b/conditionally-add-annotations/suite/good.yaml new file mode 100644 index 00000000..ef21b143 --- /dev/null +++ b/conditionally-add-annotations/suite/good.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: conditionally-add-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Conditionally add annotations +spec: + params: + toMatch: + config.kubernetes.io/local-config: "true" + toAdd: + configmanagement.gke.io/managed: disabled + source: ./examples/mutation/conditionally-add-annotations/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx + annotations: + config.kubernetes.io/local-config: "true" +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/conditionally-add-labels/README.md b/conditionally-add-labels/README.md new file mode 100644 index 00000000..263b18ba --- /dev/null +++ b/conditionally-add-labels/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/conditionally-add-labels) diff --git a/conditionally-add-labels/kcl.mod b/conditionally-add-labels/kcl.mod new file mode 100644 index 00000000..3b946602 --- /dev/null +++ b/conditionally-add-labels/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "conditionally-add-labels" +edition = "*" +version = "0.1.0" +description = "`conditionally-add-labels` is a kcl mutation package" diff --git a/conditionally-add-labels/main.k b/conditionally-add-labels/main.k new file mode 100644 index 00000000..76d62948 --- /dev/null +++ b/conditionally-add-labels/main.k @@ -0,0 +1,10 @@ +params = option("params") +toMatch = params.toMatch +toAdd = params.toAdd +items = [item | { + # If all labels are matched, patch more labels + if all key, value in toMatch { + item.metadata.labels[key] == value + }: + metadata.labels: toAdd +} for item in option("items")] diff --git a/conditionally-add-labels/suite/config.yaml b/conditionally-add-labels/suite/config.yaml new file mode 100644 index 00000000..10a8a433 --- /dev/null +++ b/conditionally-add-labels/suite/config.yaml @@ -0,0 +1,16 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: conditionally-add-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Conditionally add labels +spec: + params: + toMatch: + config.kubernetes.io/local-config: "true" + toAdd: + configmanagement.gke.io/managed: disabled + source: oci://ghcr.io/kcl-lang/conditionally-add-labels diff --git a/conditionally-add-labels/suite/good.yaml b/conditionally-add-labels/suite/good.yaml new file mode 100644 index 00000000..52c5f54e --- /dev/null +++ b/conditionally-add-labels/suite/good.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: conditionally-add-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Conditionally add annotations +spec: + params: + toMatch: + config.kubernetes.io/local-config: "true" + toAdd: + configmanagement.gke.io/managed: disabled + source: ./examples/mutation/conditionally-add-labels/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx + labels: + config.kubernetes.io/local-config: "true" +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/deny-all/README.md b/deny-all/README.md new file mode 100644 index 00000000..a640ac20 --- /dev/null +++ b/deny-all/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/deny-all) diff --git a/deny-all/kcl.mod b/deny-all/kcl.mod new file mode 100644 index 00000000..401b8f06 --- /dev/null +++ b/deny-all/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "deny-all" +version = "0.1.0" +description = "`deny-all` is a kcl validation package" diff --git a/deny-all/main.k b/deny-all/main.k new file mode 100644 index 00000000..c9b0426d --- /dev/null +++ b/deny-all/main.k @@ -0,0 +1 @@ +assert False if option("items"), "Deny all objects and the input object list is ${option('items')}" diff --git a/deny-all/suite/bad.yaml b/deny-all/suite/bad.yaml new file mode 100644 index 00000000..3a1ce0fd --- /dev/null +++ b/deny-all/suite/bad.yaml @@ -0,0 +1,26 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: deny-all + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Deny all objects if there are input objects. +spec: + source: ./examples/validation/deny-all/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - ps diff --git a/deny-all/suite/good.yaml b/deny-all/suite/good.yaml new file mode 100644 index 00000000..f2c7be43 --- /dev/null +++ b/deny-all/suite/good.yaml @@ -0,0 +1,11 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: deny-all + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Deny all objects if there are input objects. +spec: + source: ./examples/validation/deny-all/main.k diff --git a/deny-commands-in-exec-probe/README.md b/deny-commands-in-exec-probe/README.md new file mode 100644 index 00000000..f94bb905 --- /dev/null +++ b/deny-commands-in-exec-probe/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/deny-commands-in-exec-probe) diff --git a/deny-commands-in-exec-probe/kcl.mod b/deny-commands-in-exec-probe/kcl.mod new file mode 100644 index 00000000..a17efa4b --- /dev/null +++ b/deny-commands-in-exec-probe/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "deny-commands-in-exec-probe" +edition = "*" +version = "0.1.0" +description = "`deny-commands-in-exec-probe` is a kcl validation package" diff --git a/deny-commands-in-exec-probe/main.k b/deny-commands-in-exec-probe/main.k new file mode 100644 index 00000000..55f09c9a --- /dev/null +++ b/deny-commands-in-exec-probe/main.k @@ -0,0 +1,14 @@ +import regex + +# Define the validation function +validate = lambda item { + if item.kind == "Pod" and item.spec.containers: + assert all c in item.spec.containers { + all m in c.livenessProbe.exec.command { + not (regex.match(m, "\\bjcmd\\b") or regex.match(m, "\\bps\\b") or regex.match(m, "\\bls\\b")) + } if c.livenessProbe?.exec?.command + }, "Cannot use commands `jcmd`, `ps`, or `ls` in liveness probes for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/deny-commands-in-exec-probe/suite/bad.yaml b/deny-commands-in-exec-probe/suite/bad.yaml new file mode 100644 index 00000000..78071f7f --- /dev/null +++ b/deny-commands-in-exec-probe/suite/bad.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: deny-commands-in-exec-probe + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Developers may feel compelled to use simple shell commands as a workaround to + creating "proper" liveness or readiness probes for a Pod. Such a practice can be discouraged + via detection of those commands. This policy prevents the use of certain commands + `jcmd`, `ps`, or `ls` if found in a Pod's liveness exec probe. +spec: + source: ./examples/validation/deny-commands-in-exec-probe/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - ps diff --git a/deny-commands-in-exec-probe/suite/good.yaml b/deny-commands-in-exec-probe/suite/good.yaml new file mode 100644 index 00000000..01505254 --- /dev/null +++ b/deny-commands-in-exec-probe/suite/good.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: deny-commands-in-exec-probe + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Developers may feel compelled to use simple shell commands as a workaround to + creating "proper" liveness or readiness probes for a Pod. Such a practice can be discouraged + via detection of those commands. This policy prevents the use of certain commands + `jcmd`, `ps`, or `ls` if found in a Pod's liveness exec probe. +spec: + source: ./examples/validation/deny-commands-in-exec-probe/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - kcl diff --git a/deny-endpoint-edit-default-role/README.md b/deny-endpoint-edit-default-role/README.md new file mode 100644 index 00000000..8fcabdfa --- /dev/null +++ b/deny-endpoint-edit-default-role/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/deny-endpoint-edit-default-role) diff --git a/deny-endpoint-edit-default-role/kcl.mod b/deny-endpoint-edit-default-role/kcl.mod new file mode 100644 index 00000000..d0e13e60 --- /dev/null +++ b/deny-endpoint-edit-default-role/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "deny-endpoint-edit-default-role" +version = "0.1.0" +description = "`deny-endpoint-edit-default-role` is a kcl validation package" diff --git a/deny-endpoint-edit-default-role/main.k b/deny-endpoint-edit-default-role/main.k new file mode 100644 index 00000000..8a05efc0 --- /dev/null +++ b/deny-endpoint-edit-default-role/main.k @@ -0,0 +1,32 @@ +"""Many Kubernetes installations by default have a system:aggregate-to-edit +ClusterRole which does not properly restrict access to editing Endpoints. +This ConstraintTemplate forbids the system:aggregate-to-edit ClusterRole +from granting permission to create/patch/update Endpoints. + +ClusterRole/system:aggregate-to-edit should not allow +Endpoint edit permissions due to CVE-2021-25740, Endpoint & EndpointSlice +permissions allow cross-Namespace forwarding, +https://github.com/kubernetes/kubernetes/issues/103675 + +Reference: https://github.com/open-policy-agent/gatekeeper-library/blob/master/library/general/block-endpoint-edit-default-role/template.yaml +""" + +# Define the validation function +validate = lambda item { + if (item?.metadata?.name or "") == "system:aggregate-to-edit": + rules = item.rules or [] + # Check all rules if rules exist + assert all rule in rules { + # Check evrey rule verbs if rule resources exist "endpoints" + all res in rule.resources { + # Check every verbs + all verb in rule.verbs { + verb not in ["create", "patch", "update"] + } if rule.verbs and res == "endpoints" + } if rule.resources + } if rules, "ClusterRole system:aggregate-to-edit should not allow endpoint edit permissions. For k8s version < 1.22, the Cluster Role should be annotated with rbac.authorization.kubernetes.io/autoupdate=false to prevent autoreconciliation back to default permissions for this role." + item +} + +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/deny-endpoint-edit-default-role/suite/bad.yaml b/deny-endpoint-edit-default-role/suite/bad.yaml new file mode 100644 index 00000000..891ad474 --- /dev/null +++ b/deny-endpoint-edit-default-role/suite/bad.yaml @@ -0,0 +1,116 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: deny-endpoint-edit-default-role + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Many Kubernetes installations by default have a system:aggregate-to-edit + ClusterRole which does not properly restrict access to editing Endpoints. + This ConstraintTemplate forbids the system:aggregate-to-edit ClusterRole + from granting permission to create/patch/update Endpoints. + + ClusterRole/system:aggregate-to-edit should not allow + Endpoint edit permissions due to CVE-2021-25740, Endpoint & EndpointSlice + permissions allow cross-Namespace forwarding, + https://github.com/kubernetes/kubernetes/issues/103675 + + Reference: https://github.com/open-policy-agent/gatekeeper-library/blob/master/library/general/block-endpoint-edit-default-role/template.yaml +spec: + source: ./examples/validation/deny-endpoint-edit-default-role/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - ps +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + creationTimestamp: null + labels: + kubernetes.io/bootstrapping: rbac-defaults + rbac.authorization.k8s.io/aggregate-to-edit: "true" + name: system:aggregate-to-edit +rules: +- apiGroups: + - "" + resources: + - pods/attach + - pods/exec + - pods/portforward + - pods/proxy + - secrets + - services/proxy + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - impersonate +- apiGroups: + - "" + resources: + - pods + - pods/attach + - pods/exec + - pods/portforward + - pods/proxy + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - replicationcontrollers + - replicationcontrollers/scale + - secrets + - serviceaccounts + - services + - services/proxy + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - apps + resources: + - daemonsets + - deployments + - deployments/rollback + - deployments/scale + - endpoints + - replicasets + - replicasets/scale + - statefulsets + - statefulsets/scale + verbs: + - create + - delete + - deletecollection + - patch + - update diff --git a/deny-endpoint-edit-default-role/suite/good.yaml b/deny-endpoint-edit-default-role/suite/good.yaml new file mode 100644 index 00000000..0ba6d30b --- /dev/null +++ b/deny-endpoint-edit-default-role/suite/good.yaml @@ -0,0 +1,160 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: deny-endpoint-edit-default-role + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Many Kubernetes installations by default have a system:aggregate-to-edit + ClusterRole which does not properly restrict access to editing Endpoints. + This ConstraintTemplate forbids the system:aggregate-to-edit ClusterRole + from granting permission to create/patch/update Endpoints. + + ClusterRole/system:aggregate-to-edit should not allow + Endpoint edit permissions due to CVE-2021-25740, Endpoint & EndpointSlice + permissions allow cross-Namespace forwarding, + https://github.com/kubernetes/kubernetes/issues/103675 + + Reference: https://github.com/open-policy-agent/gatekeeper-library/blob/master/library/general/block-endpoint-edit-default-role/template.yaml +spec: + source: ./examples/validation/deny-endpoint-edit-default-role/main.k +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + creationTimestamp: null + labels: + kubernetes.io/bootstrapping: rbac-defaults + rbac.authorization.k8s.io/aggregate-to-edit: "true" + name: system:aggregate-to-edit +rules: +- apiGroups: + - "" + resources: + - pods/attach + - pods/exec + - pods/portforward + - pods/proxy + - secrets + - services/proxy + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - impersonate +- apiGroups: + - "" + resources: + - pods + - pods/attach + - pods/exec + - pods/portforward + - pods/proxy + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - replicationcontrollers + - replicationcontrollers/scale + - secrets + - serviceaccounts + - services + - services/proxy + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - apps + resources: + - daemonsets + - deployments + - deployments/rollback + - deployments/scale + - replicasets + - replicasets/scale + - statefulsets + - statefulsets/scale + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - batch + resources: + - cronjobs + - jobs + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - extensions + resources: + - daemonsets + - deployments + - deployments/rollback + - deployments/scale + - ingresses + - networkpolicies + - replicasets + - replicasets/scale + - replicationcontrollers/scale + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - create + - delete + - deletecollection + - patch + - update +- apiGroups: + - networking.k8s.io + resources: + - ingresses + - networkpolicies + verbs: + - create + - delete + - deletecollection + - patch + - update diff --git a/disallow-anonymous/README.md b/disallow-anonymous/README.md new file mode 100644 index 00000000..02e53acd --- /dev/null +++ b/disallow-anonymous/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-anonymous) diff --git a/disallow-anonymous/kcl.mod b/disallow-anonymous/kcl.mod new file mode 100644 index 00000000..41d065cf --- /dev/null +++ b/disallow-anonymous/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-anonymous" +version = "0.1.0" +description = "`disallow-anonymous` is a kcl validation package" diff --git a/disallow-anonymous/main.k b/disallow-anonymous/main.k new file mode 100644 index 00000000..5d37d08a --- /dev/null +++ b/disallow-anonymous/main.k @@ -0,0 +1,21 @@ +"""Disallows associating ClusterRole and Role resources +to the system:anonymous user and system:unauthenticated group. +""" + +schema Params: + allowedRoles?: [str] + +params: Params = option("params") + +# Define the validation function +validate = lambda item { + if item.kind in ["ClusterRoleBinding"]: + if item.roleRef.name not in (params.allowedRoles or []): + if any subject in item.subjects { + subject.name in ["system:unauthenticated", "system:anonymous"] + }: + assert False, "Unauthenticated user reference is not allowed in for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-anonymous/suite/bad.yaml b/disallow-anonymous/suite/bad.yaml new file mode 100644 index 00000000..554bf525 --- /dev/null +++ b/disallow-anonymous/suite/bad.yaml @@ -0,0 +1,31 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-anonymous + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Disallows associating ClusterRole and Role resources + to the system:anonymous user and system:unauthenticated group. +spec: + params: + allowedRoles: + - cluster-role-1 + source: ./examples/validation/disallow-anonymous/main.k +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-2 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:unauthenticated diff --git a/disallow-anonymous/suite/good.yaml b/disallow-anonymous/suite/good.yaml new file mode 100644 index 00000000..8524bf18 --- /dev/null +++ b/disallow-anonymous/suite/good.yaml @@ -0,0 +1,32 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-anonymous + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Disallows associating ClusterRole and Role resources + to the system:anonymous user and system:unauthenticated group. +spec: + params: + allowedRoles: + - cluster-role-1 + source: ./examples/validation/disallow-anonymous/main.k +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-1 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-1 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:unauthenticated + diff --git a/disallow-host-ports/README.md b/disallow-host-ports/README.md new file mode 100644 index 00000000..b966a7d0 --- /dev/null +++ b/disallow-host-ports/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-host-ports) diff --git a/disallow-host-ports/kcl.mod b/disallow-host-ports/kcl.mod new file mode 100644 index 00000000..ef618136 --- /dev/null +++ b/disallow-host-ports/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "disallow-host-ports" +edition = "*" +version = "0.1.0" +description = "`disallow-host-ports` is a kcl validation package" diff --git a/disallow-host-ports/main.k b/disallow-host-ports/main.k new file mode 100644 index 00000000..c38ae7ba --- /dev/null +++ b/disallow-host-ports/main.k @@ -0,0 +1,12 @@ +# Define the validation function +validate = lambda item { + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.phemeralContainers or []) + (item.spec.initContainers or []) + ports = [p.hostPort for c in containers for p in c.ports] + assert all p in ports { + p in [0, Undefined, None] + } if ports, """Use of host ports is disallowed. The fields spec.containers[*].ports[*].hostPort, spec.initContainers[*].ports[*].hostPort, and spec.ephemeralContainers[*].ports[*].hostPort must either be unset or set to `0` for ${item.kind}: ${item.metadata.name}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-host-ports/suite/bad.yaml b/disallow-host-ports/suite/bad.yaml new file mode 100644 index 00000000..26d638d5 --- /dev/null +++ b/disallow-host-ports/suite/bad.yaml @@ -0,0 +1,25 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-host-ports + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Access to host ports allows potential snooping of network traffic and should not be + allowed, or at minimum restricted to a known list. This policy ensures the `hostPort` + field is unset or set to `0`. +spec: + source: ./examples/validation/disallow-host-ports/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + hostPort: 80 diff --git a/disallow-host-ports/suite/good.yaml b/disallow-host-ports/suite/good.yaml new file mode 100644 index 00000000..f18b4fe6 --- /dev/null +++ b/disallow-host-ports/suite/good.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-host-ports + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Access to host ports allows potential snooping of network traffic and should not be + allowed, or at minimum restricted to a known list. This policy ensures the `hostPort` + field is unset or set to `0`. +spec: + source: ./examples/validation/disallow-host-ports/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + hostPort: 0 + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/disallow-ingress-wildcard/README.md b/disallow-ingress-wildcard/README.md new file mode 100644 index 00000000..a7325aa4 --- /dev/null +++ b/disallow-ingress-wildcard/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-ingress-wildcard) diff --git a/disallow-ingress-wildcard/kcl.mod b/disallow-ingress-wildcard/kcl.mod new file mode 100644 index 00000000..083e1a7c --- /dev/null +++ b/disallow-ingress-wildcard/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-ingress-wildcard" +version = "0.1.0" +description = "`disallow-ingress-wildcard` is a kcl validation package" diff --git a/disallow-ingress-wildcard/main.k b/disallow-ingress-wildcard/main.k new file mode 100644 index 00000000..c217611f --- /dev/null +++ b/disallow-ingress-wildcard/main.k @@ -0,0 +1,15 @@ +"""A validation that prevents the creation of Ingress resources with a blank or wildcard (*) hostname since +that would enable them to intercept traffic for other services in the cluster, even if they don't have +access to those services. +""" + +# Define the validation function +validate = lambda item { + if item.kind == "Ingress": + # Find the wildcard hostname list. + hostnames = [r.host for r in item.spec.rules if r.host and "*" in r.host] + assert not hostnames, "Hostnames '{}' is not allowed since it counts as a wildcard, which can be used to intercept traffic from other applications.".format(hostnames) + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-ingress-wildcard/suite/bad.yaml b/disallow-ingress-wildcard/suite/bad.yaml new file mode 100644 index 00000000..9e6d1a76 --- /dev/null +++ b/disallow-ingress-wildcard/suite/bad.yaml @@ -0,0 +1,40 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-ingress-wildcard + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + A validation that prevents the creation of Ingress resources with a blank or wildcard (*) hostname since + that would enable them to intercept traffic for other services in the cluster, even if they don't have + access to those services. +spec: + source: ./examples/validation/disallow-ingress-wildcard/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: wildcard-ingress +spec: + rules: + - host: '*.example.com' + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: example + port: + number: 80 + - host: 'valid.example.com' + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: example + port: + number: 80 diff --git a/disallow-ingress-wildcard/suite/good.yaml b/disallow-ingress-wildcard/suite/good.yaml new file mode 100644 index 00000000..8c78ef3d --- /dev/null +++ b/disallow-ingress-wildcard/suite/good.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-ingress-wildcard + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + A validation that prevents the creation of Ingress resources with a blank or wildcard (*) hostname since + that would enable them to intercept traffic for other services in the cluster, even if they don't have + access to those services. +spec: + source: ./examples/validation/disallow-ingress-wildcard/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: non-wildcard-ingress +spec: + rules: + - host: 'myservice.example.com' + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: example + port: + number: 80 diff --git a/disallow-privileged-containers/README.md b/disallow-privileged-containers/README.md new file mode 100644 index 00000000..5f66e2ca --- /dev/null +++ b/disallow-privileged-containers/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-privileged-containers) diff --git a/disallow-privileged-containers/kcl.mod b/disallow-privileged-containers/kcl.mod new file mode 100644 index 00000000..67a996da --- /dev/null +++ b/disallow-privileged-containers/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "disallow-privileged-containers" +edition = "*" +version = "0.1.0" +description = "`disallow-privileged-containers` is a kcl validation package" diff --git a/disallow-privileged-containers/main.k b/disallow-privileged-containers/main.k new file mode 100644 index 00000000..9aa9dbdd --- /dev/null +++ b/disallow-privileged-containers/main.k @@ -0,0 +1,11 @@ +# Define the validation function +validate = lambda item { + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.phemeralContainers or []) + (item.spec.initContainers or []) + assert all c in containers { + c.securityContext?.privileged in ["false", Undefined, None] + } if containers, "Privileged mode is disallowed. The fields spec.containers[*].securityContext.privileged and spec.initContainers[*].securityContext.privileged must be unset or set to `false`. for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-privileged-containers/suite/bad.yaml b/disallow-privileged-containers/suite/bad.yaml new file mode 100644 index 00000000..2f75f846 --- /dev/null +++ b/disallow-privileged-containers/suite/bad.yaml @@ -0,0 +1,27 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-privileged-containers + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Privileged mode disables most security mechanisms and must not be allowed. This policy + ensures Pods do not call for privileged mode. Privileged mode is disallowed. + The fields spec.containers[*].securityContext.privileged + and spec.initContainers[*].securityContext.privileged must be unset or set to `false`. +spec: + source: ./examples/validation/disallow-privileged-containers/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + securityContext: + privileged: "true" diff --git a/disallow-privileged-containers/suite/good.yaml b/disallow-privileged-containers/suite/good.yaml new file mode 100644 index 00000000..b7946749 --- /dev/null +++ b/disallow-privileged-containers/suite/good.yaml @@ -0,0 +1,31 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-privileged-containers + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Privileged mode disables most security mechanisms and must not be allowed. This policy + ensures Pods do not call for privileged mode. Privileged mode is disallowed. + The fields spec.containers[*].securityContext.privileged + and spec.initContainers[*].securityContext.privileged must be unset or set to `false`. +spec: + source: ./examples/validation/disallow-privileged-containers/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + securityContext: + privileged: "false" + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/disallow-svc-lb/README.md b/disallow-svc-lb/README.md new file mode 100644 index 00000000..d4a48eeb --- /dev/null +++ b/disallow-svc-lb/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-svc-lb) diff --git a/disallow-svc-lb/kcl.mod b/disallow-svc-lb/kcl.mod new file mode 100644 index 00000000..2c922487 --- /dev/null +++ b/disallow-svc-lb/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-svc-lb" +version = "0.1.0" +description = "`disallow-svc-lb` is a kcl validation package" diff --git a/disallow-svc-lb/main.k b/disallow-svc-lb/main.k new file mode 100644 index 00000000..604e6c13 --- /dev/null +++ b/disallow-svc-lb/main.k @@ -0,0 +1,12 @@ +"""A validation that prevents the creation of Service resources of type `LoadBalancer` +""" + +# Define the validation function +validate = lambda item { + if item.kind == "Service": + svc_ty = item.spec.type or "" + assert svc_ty != "LoadBalancer", """A validation that prevents the creation of Service resources of type `LoadBalancer`, for ${item.kind}: ${item.metadata.name}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-svc-lb/suite/bad.yaml b/disallow-svc-lb/suite/bad.yaml new file mode 100644 index 00000000..5818a945 --- /dev/null +++ b/disallow-svc-lb/suite/bad.yaml @@ -0,0 +1,19 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-svc-lb +spec: + source: oci://ghcr.io/kcl-lang/disallow-svc-lb +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app.kubernetes.io/name: MyApp + ports: + - name: http + protocol: TCP + port: 80 + type: LoadBalancer # 错误地设置了 LoadBalancer diff --git a/disallow-svc-lb/suite/good.yaml b/disallow-svc-lb/suite/good.yaml new file mode 100644 index 00000000..d21d2f3a --- /dev/null +++ b/disallow-svc-lb/suite/good.yaml @@ -0,0 +1,23 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-svc-lb + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + A validation that prevents the creation of Service resources of type `LoadBalancer` +spec: + source: ./examples/validation/disallow-svc-lb/main.k +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app.kubernetes.io/name: MyApp + ports: + - name: http + protocol: TCP + port: 80 diff --git a/disallow-svc-node-port/README.md b/disallow-svc-node-port/README.md new file mode 100644 index 00000000..804385d7 --- /dev/null +++ b/disallow-svc-node-port/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-svc-node-port) diff --git a/disallow-svc-node-port/kcl.mod b/disallow-svc-node-port/kcl.mod new file mode 100644 index 00000000..c6b0e3e9 --- /dev/null +++ b/disallow-svc-node-port/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-svc-node-port" +version = "0.1.0" +description = "`disallow-svc-node-port` is a kcl validation package" diff --git a/disallow-svc-node-port/main.k b/disallow-svc-node-port/main.k new file mode 100644 index 00000000..9e22f1e3 --- /dev/null +++ b/disallow-svc-node-port/main.k @@ -0,0 +1,12 @@ +"""A validation that prevents the creation of Service resources of type `NodePort` +""" + +# Define the validation function +validate = lambda item { + if item.kind == "Service": + svc_ty = item.spec.type or "" + assert svc_ty != "NodePort", """A validation that prevents the creation of Service resources of type `NodePort`, for ${item.kind}: ${item.metadata.name}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-svc-node-port/suite/bad.yaml b/disallow-svc-node-port/suite/bad.yaml new file mode 100644 index 00000000..84611b3d --- /dev/null +++ b/disallow-svc-node-port/suite/bad.yaml @@ -0,0 +1,24 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-svc-node-port + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + A validation that prevents the creation of Service resources of type `NodePort` +spec: + source: ./examples/validation/disallow-svc-node-port/main.k +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app.kubernetes.io/name: MyApp + ports: + - name: http + protocol: TCP + port: 80 + type: NodePort diff --git a/disallow-svc-node-port/suite/good.yaml b/disallow-svc-node-port/suite/good.yaml new file mode 100644 index 00000000..7087ee60 --- /dev/null +++ b/disallow-svc-node-port/suite/good.yaml @@ -0,0 +1,23 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallow-svc-lb + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + A validation that prevents the creation of Service resources of type `NodePort` +spec: + source: ./examples/validation/disallow-svc-node-port/main.k +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app.kubernetes.io/name: MyApp + ports: + - name: http + protocol: TCP + port: 80 diff --git a/disallowed-image-repos/README.md b/disallowed-image-repos/README.md new file mode 100644 index 00000000..ea99f66d --- /dev/null +++ b/disallowed-image-repos/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallowed-image-repos) diff --git a/disallowed-image-repos/kcl.mod b/disallowed-image-repos/kcl.mod new file mode 100644 index 00000000..a3f69973 --- /dev/null +++ b/disallowed-image-repos/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallowed-image-repos" +version = "0.1.0" +description = "`disallowed-image-repos` is a kcl validation package" diff --git a/disallowed-image-repos/main.k b/disallowed-image-repos/main.k new file mode 100644 index 00000000..45428e43 --- /dev/null +++ b/disallowed-image-repos/main.k @@ -0,0 +1,23 @@ +"""Disallowed container repositories that begin with a string from the specified list. +""" + +# The list of prefixes a container image is allowed to have. +repos: [str] = option("params").repos or [] + +# Define the validation function +validate = lambda item { + containers = [] + if item.kind == "Pod" and repos: + containers = (item.spec.containers or []) + (item.spec.phemeralContainers or []) + (item.spec.initContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.phemeralContainers or []) + (item.spec.template.spec.initContainers or []) + images: [str] = [c.image for c in containers] + assert all image in images { + all repo in repos { + not image.startswith(repo) + } + } if images and repos, """Use of image is disallowed for ${item.kind}: ${item.metadata.name}, valid repos ${repos}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallowed-image-repos/suite/bad.yaml b/disallowed-image-repos/suite/bad.yaml new file mode 100644 index 00000000..73fa6093 --- /dev/null +++ b/disallowed-image-repos/suite/bad.yaml @@ -0,0 +1,28 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallowed-image-repos + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Disallowed container repositories that begin with a string from the specified list. +spec: + params: + repos: + - "k8s.gcr.io/" + source: ./examples/validation/disallowed-image-repos/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod +spec: + containers: + - name: kcl + image: k8s.gcr.io/kcl + args: + - "kcl" + ephemeralContainers: + - name: kcl + image: k8s.gcr.io/kcl diff --git a/disallowed-image-repos/suite/good.yaml b/disallowed-image-repos/suite/good.yaml new file mode 100644 index 00000000..c5f07d22 --- /dev/null +++ b/disallowed-image-repos/suite/good.yaml @@ -0,0 +1,28 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: disallowed-image-repos + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Disallowed container repositories that begin with a string from the specified list. +spec: + params: + repos: + - "k8s.gcr.io/" + source: ./examples/validation/disallowed-image-repos/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod +spec: + containers: + - name: kcl + image: kcllang/kcl + args: + - "kcl" + ephemeralContainers: + - name: kcl + image: kcllang/kcl diff --git a/external-ips/README.md b/external-ips/README.md new file mode 100644 index 00000000..a6298d0a --- /dev/null +++ b/external-ips/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/external-ips) diff --git a/external-ips/kcl.mod b/external-ips/kcl.mod new file mode 100644 index 00000000..9fc43f57 --- /dev/null +++ b/external-ips/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "external-ips" +edition = "*" +version = "0.1.0" +description = "`external-ips` is a kcl validation package" diff --git a/external-ips/main.k b/external-ips/main.k new file mode 100644 index 00000000..4b8b671b --- /dev/null +++ b/external-ips/main.k @@ -0,0 +1,10 @@ +# Define the validation function +validate_external_ips = lambda item, allowedIps: [str] { + if allowedIps and item.kind == "Service" and item.spec.externalIPs: + assert all ip in item.spec.externalIPs { + ip in allowedIps + }, "Service external IPs must be in ${allowedIps} for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate_external_ips(i, option("params")?.allowedIps or []) for i in option("items")] diff --git a/external-ips/suite/bad.yaml b/external-ips/suite/bad.yaml new file mode 100644 index 00000000..d0a0c689 --- /dev/null +++ b/external-ips/suite/bad.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: external-ips + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Restricts Service externalIPs to an allowed list of IP addresses. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips +spec: + params: + allowedIps: ["198.51.100.32"] + source: ./examples/validation/external-ips/main.k +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app.kubernetes.io/name: MyApp + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 49152 + externalIPs: + - 127.0.0.1 diff --git a/external-ips/suite/config.yaml b/external-ips/suite/config.yaml new file mode 100644 index 00000000..91d05339 --- /dev/null +++ b/external-ips/suite/config.yaml @@ -0,0 +1,14 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: external-ips + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Restricts Service externalIPs to an allowed list of IP addresses. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips +spec: + params: + allowedIps: ["198.51.100.32"] + source: oci://ghcr.io/kcl-lang/external-ips diff --git a/external-ips/suite/good.yaml b/external-ips/suite/good.yaml new file mode 100644 index 00000000..7cfba3fc --- /dev/null +++ b/external-ips/suite/good.yaml @@ -0,0 +1,29 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: external-ips + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Restricts Service externalIPs to an allowed list of IP addresses. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips +spec: + params: + allowedIps: ["198.51.100.32"] + source: ./examples/validation/external-ips/main.k +--- +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app.kubernetes.io/name: MyApp + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 49152 + externalIPs: + - 198.51.100.32 diff --git a/helloworld/kcl.mod b/helloworld/kcl.mod index bef7e7f7..d71c4440 100644 --- a/helloworld/kcl.mod +++ b/helloworld/kcl.mod @@ -1,5 +1,5 @@ [package] name = "helloworld" -edition = "0.0.1" -version = "0.0.1" +edition = "*" +version = "0.1.0" diff --git a/horizontal-pod-auto-scaler/README.md b/horizontal-pod-auto-scaler/README.md new file mode 100644 index 00000000..951f12e8 --- /dev/null +++ b/horizontal-pod-auto-scaler/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/horizontal-pod-auto-scaler) diff --git a/horizontal-pod-auto-scaler/kcl.mod b/horizontal-pod-auto-scaler/kcl.mod new file mode 100644 index 00000000..869fd15e --- /dev/null +++ b/horizontal-pod-auto-scaler/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "horizontal-pod-auto-scaler" +version = "0.1.0" +description = "`horizontal-pod-auto-scaler` is a kcl mutation package" diff --git a/horizontal-pod-auto-scaler/main.k b/horizontal-pod-auto-scaler/main.k new file mode 100644 index 00000000..75a4f984 --- /dev/null +++ b/horizontal-pod-auto-scaler/main.k @@ -0,0 +1,35 @@ +"""Disallow the following scenarios when deploying `HorizontalPodAutoscalers` +1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint +2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread` +3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet). +""" + +schema Params: + minimumReplicaSpread: int = 0 + ranges: [Range] + + check: + minimumReplicaSpread >= 0 + len(ranges) > 0 + +schema Range: + min_replicas: int + max_replicas: int + + check: + 0 <= min_replicas < max_replicas + +params: Params = option("params") + +# Define the validation function +validate = lambda item { + containers = [] + if item.kind == "HorizontalPodAutoscaler": + assert item.spec.maxReplicas - item.spec.minReplicas >= params.minimumReplicaSpread, "The {} <{}> minReplicas {} or maxReplicas {} is not allowed. Allowed ranges: {}".format(item.kind, item.metadata.name, item.spec.minReplicas, item.spec.maxReplicas, params.ranges) + assert all r in params.ranges { + item.spec.minReplicas >= r.min_replicas and item.spec.maxReplicas <= r.max_replicas + }, "The {} <{}> minReplicas {} or maxReplicas {} is not allowed. Allowed ranges: {}".format(item.kind, item.metadata.name, item.spec.minReplicas, item.spec.maxReplicas, params.ranges) + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/horizontal-pod-auto-scaler/suite/bad.yaml b/horizontal-pod-auto-scaler/suite/bad.yaml new file mode 100644 index 00000000..0f662d3e --- /dev/null +++ b/horizontal-pod-auto-scaler/suite/bad.yaml @@ -0,0 +1,40 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: horizontal-pod-auto-scaler + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Disallow the following scenarios when deploying `HorizontalPodAutoscalers` + 1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint + 2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread` + 3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet). +spec: + params: + minimumReplicaSpread: 1 + ranges: + - min_replicas: 3 + max_replicas: 6 + source: ./examples/validation/horizontal-pod-auto-scaler/main.k +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: nginx-hpa-disallowed-replicas + namespace: default +spec: + minReplicas: 2 + maxReplicas: 7 + metrics: + - resource: + name: cpu + target: + averageUtilization: 900 + type: Utilization + type: Resource + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: nginx-deployment + diff --git a/horizontal-pod-auto-scaler/suite/good.yaml b/horizontal-pod-auto-scaler/suite/good.yaml new file mode 100644 index 00000000..72dd1b3f --- /dev/null +++ b/horizontal-pod-auto-scaler/suite/good.yaml @@ -0,0 +1,39 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: horizontal-pod-auto-scaler + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Disallow the following scenarios when deploying `HorizontalPodAutoscalers` + 1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint + 2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread` + 3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet). +spec: + params: + minimumReplicaSpread: 1 + ranges: + - min_replicas: 3 + max_replicas: 6 + source: ./examples/validation/horizontal-pod-auto-scaler/main.k +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: nginx-hpa-allowed + namespace: default +spec: + minReplicas: 3 + maxReplicas: 6 + metrics: + - resource: + name: cpu + target: + averageUtilization: 900 + type: Utilization + type: Resource + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: nginx-deployment diff --git a/https-only/README.md b/https-only/README.md new file mode 100644 index 00000000..4964ee94 --- /dev/null +++ b/https-only/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/https-only) diff --git a/https-only/kcl.mod b/https-only/kcl.mod new file mode 100644 index 00000000..f6059a90 --- /dev/null +++ b/https-only/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "https-only" +edition = "*" +version = "0.1.0" +description = "`https-only` is a kcl validation package" diff --git a/https-only/main.k b/https-only/main.k new file mode 100644 index 00000000..88c56abf --- /dev/null +++ b/https-only/main.k @@ -0,0 +1,9 @@ +params = option("params") +# Define the validation function +validate_https_only = lambda item { + if item.kind == "Ingress" and item.spec.tls: + assert item.metadata.annotations["kubernetes.io/ingress.allow-http"] == "false", "Ingress should be https. The `kubernetes.io/ingress.allow-http: \"false\"` annotation is required for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate_https_only(i) for i in option("items")] diff --git a/https-only/suite/bad.yaml b/https-only/suite/bad.yaml new file mode 100644 index 00000000..2969badd --- /dev/null +++ b/https-only/suite/bad.yaml @@ -0,0 +1,28 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: https-only +spec: + source: oci://ghcr.io/kcl-lang/https-only +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + # Required the annotation kubernetes.io/ingress.allow-http: "false" + name: tls-example-ingress +spec: + tls: + - hosts: + - https-example.foo.com + secretName: testsecret-tls + rules: + - host: https-example.foo.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: service1 + port: + number: 80 diff --git a/https-only/suite/config.yaml b/https-only/suite/config.yaml new file mode 100644 index 00000000..cf2eeb66 --- /dev/null +++ b/https-only/suite/config.yaml @@ -0,0 +1,15 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: https-only + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires Ingress resources to be HTTPS only. Ingress resources must + include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. + By default a valid TLS {} configuration is required, this can be made + optional by setting the `tlsOptional` parameter to `true`. + More info: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls +spec: + source: oci://ghcr.io/kcl-lang/https-only diff --git a/https-only/suite/good.yaml b/https-only/suite/good.yaml new file mode 100644 index 00000000..888f5f53 --- /dev/null +++ b/https-only/suite/good.yaml @@ -0,0 +1,38 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: https-only + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires Ingress resources to be HTTPS only. Ingress resources must + include the `kubernetes.io/ingress.allow-http` annotation, set to `false`. + By default a valid TLS {} configuration is required, this can be made + optional by setting the `tlsOptional` parameter to `true`. + More info: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls +spec: + source: ./examples/validation/https-only/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: tls-example-ingress + annotations: + kubernetes.io/ingress.allow-http: "false" +spec: + tls: + - hosts: + - https-example.foo.com + secretName: testsecret-tls + rules: + - host: https-example.foo.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: service1 + port: + number: 80 diff --git a/insert-pod-antiaffinity/README.md b/insert-pod-antiaffinity/README.md new file mode 100644 index 00000000..28f6b5b5 --- /dev/null +++ b/insert-pod-antiaffinity/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/insert-pod-antiaffinity) diff --git a/insert-pod-antiaffinity/kcl.mod b/insert-pod-antiaffinity/kcl.mod new file mode 100644 index 00000000..c0ffb682 --- /dev/null +++ b/insert-pod-antiaffinity/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "insert-pod-antiaffinity" +edition = "*" +version = "0.1.0" +description = "`insert-pod-antiaffinity` is a kcl mutation package" diff --git a/insert-pod-antiaffinity/main.k b/insert-pod-antiaffinity/main.k new file mode 100644 index 00000000..b145f3e3 --- /dev/null +++ b/insert-pod-antiaffinity/main.k @@ -0,0 +1,12 @@ +items = [item | { + if item.kind == "Deployment" and item?.spec?.template?.metadata?.labels?.app: + spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution += [{ + weight = 1 + podAffinityTerm.topologyKey = "kubernetes.io/hostname" + labelSelector.matchExpressions += [{ + key: "app" + operator: "In" + values: [item.spec.template.metadata.labels.app] + }] + }] +} for item in option("items") or []] diff --git a/insert-pod-antiaffinity/suite/good.yaml b/insert-pod-antiaffinity/suite/good.yaml new file mode 100644 index 00000000..811a838e --- /dev/null +++ b/insert-pod-antiaffinity/suite/good.yaml @@ -0,0 +1,36 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: insert-pod-antiaffinity + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Applications may involve multiple replicas of the same Pod for availability as well as scale + purposes, yet Kubernetes does not by default provide a solution for availability. This policy + sets a Pod anti-affinity configuration on Deployments which contain an `app` label if it is + not already present. +spec: + source: ./examples/mutation/insert-pod-antiaffinity/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/k8s_manifests_containers/README.md b/k8s_manifests_containers/README.md new file mode 100644 index 00000000..7c561101 --- /dev/null +++ b/k8s_manifests_containers/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/k8s_manifests_containers) diff --git a/k8s_manifests_containers/kcl.mod b/k8s_manifests_containers/kcl.mod new file mode 100644 index 00000000..2d82dc75 --- /dev/null +++ b/k8s_manifests_containers/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "k8s_manifests_containers" +version = "0.1.0" +description = "`k8s_manifests_containers` can be used to get all containers resources in a Pod resource." diff --git a/k8s_manifests_containers/main.k b/k8s_manifests_containers/main.k new file mode 100644 index 00000000..9b8ee25e --- /dev/null +++ b/k8s_manifests_containers/main.k @@ -0,0 +1,19 @@ +# Judge a image in a container config is exempt +is_exempt = lambda image: str, exemptImages: [str] = [] -> bool { + result = False + if exemptImages: + result = any exempt_image in exemptImages { + (image.startswith(exempt_image.removesuffix("*")) if exempt_image.endswith("*") else exempt_image == image) + } + result +} + +# Get Containers from the input resource item. +get_containers = lambda item, exemptImages = [] -> [] { + containers = [] + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + (item.spec.ephemeralContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + (item.spec.template.spec.ephemeralContainers or []) + containers = [c for c in containers if not is_exempt(c.image, exemptImages)] +} diff --git a/merge/README.md b/merge/README.md new file mode 100644 index 00000000..a4d4cc63 --- /dev/null +++ b/merge/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/merge) diff --git a/merge/kcl.mod b/merge/kcl.mod new file mode 100644 index 00000000..5a67cca9 --- /dev/null +++ b/merge/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "merge" +edition = "*" +version = "0.1.0" +description = "`merge` offers some merge functions for kcl values." diff --git a/merge/main.k b/merge/main.k new file mode 100644 index 00000000..f255e562 --- /dev/null +++ b/merge/main.k @@ -0,0 +1,41 @@ +schema UnionAll[data, n]: + value?: {str:} = ((UnionAll(data=data, n=n - 1) {}).value | data[n] if n > 0 else data[0]) if data else {} + +schema MergeList[data]: + """Merge all elements in a list + + [{"key1": "value1"}, {"key2": "value2"}, {"key3": "value3"}] -> {"key1": "value1", "key2": "value2", "key3": "value3"} + """ + value?: {str:} = (UnionAll(data=data, n=len(data) - 1) {}).value if data else {} + +schema MergeAppend[a, b]: + """ + MergeAppend( + {"a": 1, "b": {"c": 2, "d": 3}, "e": [4, 5]} + {"a": 6, "b": {"c": 7, "f": 8}, "e": [6, 7]} + ).value => {"a": 6, "b": {"c": 7, "d": 3, "f": 8}, "e": [4, 5, 6, 7]} + """ + value?: {str:} = { + k: [*v, *b[k]] if typeof(v) == "list" and typeof(b[k]) == "list" else v | b[k] \ + if typeof(v) == typeof(b[k]) and typeof(v) not in ["str", "bool", "int", "float"] else b[k] or v \ + for k, v in a + } | {k: v for k, v in b if not a[k]} + +schema MergeAppendList[data: []]: + """Merge Append list + + MergeAppendList( + [ + {"a": [1]}, + {"a": [2,3]}, + {"a": [4]}, + ] + ).value => {"a": [1,2,3,4]} + """ + value?: {str:} + if not data: + value = None + elif len(data) == 1: + value = data[0] + else: + value = MergeAppend(data[0], MergeAppendList(data[1:]).value).value diff --git a/nginx-ingress/README.md b/nginx-ingress/README.md new file mode 100644 index 00000000..4eed3749 --- /dev/null +++ b/nginx-ingress/README.md @@ -0,0 +1 @@ ++ Reference: https://github.com/kyverno/policies/tree/main/nginx-ingress diff --git a/nginx-ingress/restrict-ingress-annotations/README.md b/nginx-ingress/restrict-ingress-annotations/README.md new file mode 100644 index 00000000..99b38b95 --- /dev/null +++ b/nginx-ingress/restrict-ingress-annotations/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/nginx-ingress/restrict-ingress-annotations) diff --git a/nginx-ingress/restrict-ingress-annotations/kcl.mod b/nginx-ingress/restrict-ingress-annotations/kcl.mod new file mode 100644 index 00000000..791198e1 --- /dev/null +++ b/nginx-ingress/restrict-ingress-annotations/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "restrict-ingress-annotations" +edition = "*" +version = "0.1.0" +description = "`restrict-ingress-annotations` is a kcl validation package" diff --git a/nginx-ingress/restrict-ingress-annotations/main.k b/nginx-ingress/restrict-ingress-annotations/main.k new file mode 100644 index 00000000..7ec91777 --- /dev/null +++ b/nginx-ingress/restrict-ingress-annotations/main.k @@ -0,0 +1,24 @@ +""" +This policy mitigates CVE-2021-25746 by restricting `metadata.annotations` to safe values. +See: https://github.com/kubernetes/ingress-nginx/blame/main/internal/ingress/inspector/rules.go. +This issue has been fixed in NGINX Ingress v1.2.0. For NGINX Ingress version 1.0.5+ the +"annotation-value-word-blocklist" configuration setting is also recommended. +Please refer to the CVE for details. +""" +import regex + +invalid_anno_value_patterns = ["\\s*alias\\s*.*;", "\\s*root\\s*.*;", "/etc/(passwd|shadow|group|nginx|ingress-controller)", "/var/run/secrets", ".*_by_lua.*"] +msg = "spec.metadata.annotations.values, invalid annotation value patterns ${invalid_anno_value_patterns}" +validate_restrict_ingress_paths = lambda item { + if item.kind == "Ingress": + values = [v for _, v in item.metadata.annotations] + if values: + assert all v in values { + not any pattern in invalid_anno_value_patterns { + regex.match(v, pattern) + } + }, msg + item +} +# Validate All resource +items = [validate_restrict_ingress_paths(i) for i in option("items")] diff --git a/nginx-ingress/restrict-ingress-annotations/suite/bad.yaml b/nginx-ingress/restrict-ingress-annotations/suite/bad.yaml new file mode 100644 index 00000000..a9015db1 --- /dev/null +++ b/nginx-ingress/restrict-ingress-annotations/suite/bad.yaml @@ -0,0 +1,145 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: restrict-ingress-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + This policy mitigates CVE-2021-25746 by restricting `metadata.annotations` to safe values. + See: https://github.com/kubernetes/ingress-nginx/blame/main/internal/ingress/inspector/rules.go. + This issue has been fixed in NGINX Ingress v1.2.0. For NGINX Ingress version 1.0.5+ the + "annotation-value-word-blocklist" configuration setting is also recommended. + Please refer to the CVE for details. +spec: + source: ./examples/validation/nginx-ingress/restrict-ingress-annotations/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cafe-ingress-with-snippets + annotations: + nginx.org/bad: "alias; " +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cafe-ingress-with-snippets + annotations: + nginx.org/bad: " root ;" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: etc-passwd + annotations: + nginx.org/bad: "/etc/passwd" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: var-run-secrets + annotations: + nginx.org/bad: "/var/run/secrets" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: lua + annotations: + nginx.org/bad: "*! _by_lua 8010-191091" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 diff --git a/nginx-ingress/restrict-ingress-annotations/suite/good.yaml b/nginx-ingress/restrict-ingress-annotations/suite/good.yaml new file mode 100644 index 00000000..1f47dbc0 --- /dev/null +++ b/nginx-ingress/restrict-ingress-annotations/suite/good.yaml @@ -0,0 +1,65 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: restrict-ingress-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + This policy mitigates CVE-2021-25746 by restricting `metadata.annotations` to safe values. + See: https://github.com/kubernetes/ingress-nginx/blame/main/internal/ingress/inspector/rules.go. + This issue has been fixed in NGINX Ingress v1.2.0. For NGINX Ingress version 1.0.5+ the + "annotation-value-word-blocklist" configuration setting is also recommended. + Please refer to the CVE for details. +spec: + source: ./examples/validation/nginx-ingress/restrict-ingress-annotations/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cafe-ingress-with-snippets + annotations: + nginx.org/good: "value" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cafe-ingress +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 diff --git a/nginx-ingress/restrict-ingress-paths/README.md b/nginx-ingress/restrict-ingress-paths/README.md new file mode 100644 index 00000000..a28fa8ae --- /dev/null +++ b/nginx-ingress/restrict-ingress-paths/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/nginx-ingress/restrict-ingress-paths) diff --git a/nginx-ingress/restrict-ingress-paths/kcl.mod b/nginx-ingress/restrict-ingress-paths/kcl.mod new file mode 100644 index 00000000..462d7acd --- /dev/null +++ b/nginx-ingress/restrict-ingress-paths/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "restrict-ingress-paths" +edition = "*" +version = "0.1.0" +description = "`restrict-ingress-paths` is a kcl validation package" diff --git a/nginx-ingress/restrict-ingress-paths/main.k b/nginx-ingress/restrict-ingress-paths/main.k new file mode 100644 index 00000000..0dad0b04 --- /dev/null +++ b/nginx-ingress/restrict-ingress-paths/main.k @@ -0,0 +1,18 @@ +""" +This policy mitigates CVE-2021-25745 by restricting `spec.rules[].http.paths[].path` to safe values. +Additional paths can be added as required. This issue has been fixed in NGINX Ingress v1.2.0. +Please refer to the CVE for details. +""" +invalid_paths = ["/etc", "/var/run/secrets", "/root", "/var/run/kubernetes/serviceaccount", "/etc/kubernetes/admin.conf"] +msg = "spec.rules[].http.paths[].path value is not allowed, invalid values ${invalid_paths}" +validate_restrict_ingress_paths = lambda item { + if item.kind == "Ingress": + paths = [p.path for r in item.spec.rules for p in r.http.paths] + if paths: + assert all path in paths { + path not in invalid_paths + }, msg + item +} +# Validate All resource +items = [validate_restrict_ingress_paths(i) for i in option("items")] diff --git a/nginx-ingress/restrict-ingress-paths/suite/bad.yaml b/nginx-ingress/restrict-ingress-paths/suite/bad.yaml new file mode 100644 index 00000000..e6444c76 --- /dev/null +++ b/nginx-ingress/restrict-ingress-paths/suite/bad.yaml @@ -0,0 +1,81 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: restrict-ingress-paths + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + This policy mitigates CVE-2021-25745 by restricting `spec.rules[].http.paths[].path` to safe values. + Additional paths can be added as required. This issue has been fixed in NGINX Ingress v1.2.0. + Please refer to the CVE for details. +spec: + source: ./examples/validation/nginx-ingress/restrict-ingress-paths/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bad-path-root +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /root + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bad-path-secrets +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /var/run/secrets + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bad-path-etc +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /etc/kubernetes/admin.conf + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bad-path-serviceaccount +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /var/run/kubernetes/serviceaccount + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 diff --git a/nginx-ingress/restrict-ingress-paths/suite/good.yaml b/nginx-ingress/restrict-ingress-paths/suite/good.yaml new file mode 100644 index 00000000..43532e30 --- /dev/null +++ b/nginx-ingress/restrict-ingress-paths/suite/good.yaml @@ -0,0 +1,37 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: restrict-ingress-paths + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + This policy mitigates CVE-2021-25745 by restricting `spec.rules[].http.paths[].path` to safe values. + Additional paths can be added as required. This issue has been fixed in NGINX Ingress v1.2.0. + Please refer to the CVE for details. +spec: + source: ./examples/validation/nginx-ingress/restrict-ingress-paths/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: good-paths +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 diff --git a/pod-security-policy/selinux/README.md b/pod-security-policy/selinux/README.md new file mode 100644 index 00000000..1857f105 --- /dev/null +++ b/pod-security-policy/selinux/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/pod-security-policy/selinux) diff --git a/pod-security-policy/selinux/kcl.mod b/pod-security-policy/selinux/kcl.mod new file mode 100644 index 00000000..d3f31012 --- /dev/null +++ b/pod-security-policy/selinux/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "selinux" +edition = "*" +version = "0.1.0" +description = "`selinux` is a kcl validation package" diff --git a/pod-security-policy/selinux/main.k b/pod-security-policy/selinux/main.k new file mode 100644 index 00000000..2ce70f0f --- /dev/null +++ b/pod-security-policy/selinux/main.k @@ -0,0 +1,13 @@ +schema Params: + level?: str = "s1:c234,c567" + user?: str = "sysadm_u" + role?: str = "sysadm_r" + $type: str = "svirt_lxc_net_t" + +params: Params = option("params") +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + securityContext.seLinuxOptions = params + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/pod-security-policy/selinux/suite/good.yaml b/pod-security-policy/selinux/suite/good.yaml new file mode 100644 index 00000000..c028583c --- /dev/null +++ b/pod-security-policy/selinux/suite/good.yaml @@ -0,0 +1,22 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: selinux + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Pod Secirity Policy (PSP) selinux +spec: + source: ./examples/mutation/pod-security-policy/selinux/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-default-selinux + labels: + app: nginx-default-selinux +spec: + containers: + - name: nginx + image: nginx diff --git a/psp-allow-privilege-escalation/README.md b/psp-allow-privilege-escalation/README.md new file mode 100644 index 00000000..4a21a564 --- /dev/null +++ b/psp-allow-privilege-escalation/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/psp-allow-privilege-escalation) diff --git a/psp-allow-privilege-escalation/kcl.mod b/psp-allow-privilege-escalation/kcl.mod new file mode 100644 index 00000000..b807cfec --- /dev/null +++ b/psp-allow-privilege-escalation/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "psp-allow-privilege-escalation" +version = "0.1.0" +description = "`psp-allow-privilege-escalation` is a kcl validation package" diff --git a/psp-allow-privilege-escalation/main.k b/psp-allow-privilege-escalation/main.k new file mode 100644 index 00000000..4de5bc46 --- /dev/null +++ b/psp-allow-privilege-escalation/main.k @@ -0,0 +1,39 @@ +"""Controls restricting escalation to root privileges. Corresponds to the +`allowPrivilegeEscalation` field in a PodSecurityPolicy. For more +information, see +https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation +""" +import regex + +schema Params: + exemptImages?: [str] + +params: Params = option("params") + +is_exempt = lambda image: str -> bool { + result = False + if params.exemptImages: + result = any exempt_image in params.exemptImages { + (image.startswith(exempt_image.removesuffix("*")) if exempt_image.endswith("*") else exempt_image == image) + } + result +} + +# Define the validation function +validate = lambda item { + cpu = "" + memory = "" + containers = [] + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + (item.spec.ephemeralContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + (item.spec.template.spec.ephemeralContainers or []) + if containers: + containers = [c for c in containers if not is_exempt(c.image)] + container_list_disallow_privilege_escalation = [c.name for c in containers if c.securityContext?.allowPrivilegeEscalation == True] + assert len(container_list_disallow_privilege_escalation) == 0, "Privilege escalation containers ${container_list_disallow_privilege_escalation} are not allowed for ${item.kind} <${item.metadata.name}>" + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/psp-allow-privilege-escalation/suite/bad.yaml b/psp-allow-privilege-escalation/suite/bad.yaml new file mode 100644 index 00000000..0b0b0013 --- /dev/null +++ b/psp-allow-privilege-escalation/suite/bad.yaml @@ -0,0 +1,27 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-allow-privilege-escalation + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls restricting escalation to root privileges. Corresponds to the + `allowPrivilegeEscalation` field in a PodSecurityPolicy. For more + information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation +spec: + source: ./examples/validation/psp-allow-privilege-escalation/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-privilege-escalation-disallowed + labels: + app: nginx-privilege-escalation +spec: + ephemeralContainers: + - name: nginx + image: nginx + securityContext: + allowPrivilegeEscalation: true diff --git a/psp-allow-privilege-escalation/suite/good.yaml b/psp-allow-privilege-escalation/suite/good.yaml new file mode 100644 index 00000000..adf7a675 --- /dev/null +++ b/psp-allow-privilege-escalation/suite/good.yaml @@ -0,0 +1,27 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-allow-privilege-escalation + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls restricting escalation to root privileges. Corresponds to the + `allowPrivilegeEscalation` field in a PodSecurityPolicy. For more + information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation +spec: + source: ./examples/validation/psp-allow-privilege-escalation/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-privilege-escalation-allowed + labels: + app: nginx-privilege-escalation +spec: + containers: + - name: nginx + image: nginx + securityContext: + allowPrivilegeEscalation: false diff --git a/psp-app-armor/README.md b/psp-app-armor/README.md new file mode 100644 index 00000000..4a21a564 --- /dev/null +++ b/psp-app-armor/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/psp-allow-privilege-escalation) diff --git a/psp-app-armor/kcl.mod b/psp-app-armor/kcl.mod new file mode 100644 index 00000000..930f5f06 --- /dev/null +++ b/psp-app-armor/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "psp-app-armor" +version = "0.1.0" +description = "`psp-app-armor` is a kcl validation package" diff --git a/psp-app-armor/main.k b/psp-app-armor/main.k new file mode 100644 index 00000000..4e8424d0 --- /dev/null +++ b/psp-app-armor/main.k @@ -0,0 +1,47 @@ +"""Configures an allow-list of AppArmor profiles for use by containers. +This corresponds to specific annotations applied to a PodSecurityPolicy. +For information on AppArmor, see +https://kubernetes.io/docs/tutorials/clusters/apparmor/ +""" +import regex + +schema Params: + exemptImages?: [str] + allowedProfiles?: [str] + +params: Params = option("params") + +# Judge a image in a container config is exempt +is_exempt = lambda image: str -> bool { + result = False + if params.exemptImages: + result = any exempt_image in params.exemptImages { + (image.startswith(exempt_image.removesuffix("*")) if exempt_image.endswith("*") else exempt_image == image) + } + result +} + +# Get Containers from the input resource item. +get_containers = lambda item { + containers = [] + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + (item.spec.ephemeralContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + (item.spec.template.spec.ephemeralContainers or []) + containers = [c for c in containers if not is_exempt(c.image)] +} + +# Define the validation function +validate = lambda item { + containers = get_containers(item) + if containers: + container_list_disallow = [ + c.name for c in containers\ + if (item.metadata.annotations?["container.apparmor.security.beta.kubernetes.io/${c.name}"] or "runtime/default") not in (params.allowedProfiles or []) + ] + assert len(container_list_disallow) == 0, "AppArmor profile is not allowed, pod: {}, containers: {}. Allowed profiles: {}".format(item.metadata.name, container_list_disallow, params.allowedProfiles) + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/psp-app-armor/suite/bad.yaml b/psp-app-armor/suite/bad.yaml new file mode 100644 index 00000000..a8400c8c --- /dev/null +++ b/psp-app-armor/suite/bad.yaml @@ -0,0 +1,31 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-app-armor + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Configures an allow-list of AppArmor profiles for use by containers. + This corresponds to specific annotations applied to a PodSecurityPolicy. + For information on AppArmor, see + https://kubernetes.io/docs/tutorials/clusters/apparmor/ +spec: + params: + allowedProfiles: + - runtime/default + source: ./examples/validation/psp-app-armor/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-apparmor-disallowed + annotations: + # apparmor.security.beta.kubernetes.io/pod: unconfined # runtime/default + container.apparmor.security.beta.kubernetes.io/nginx: unconfined + labels: + app: nginx-apparmor +spec: + ephemeralContainers: + - name: nginx + image: nginx diff --git a/psp-app-armor/suite/good.yaml b/psp-app-armor/suite/good.yaml new file mode 100644 index 00000000..12fb0e7c --- /dev/null +++ b/psp-app-armor/suite/good.yaml @@ -0,0 +1,31 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-app-armor + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Configures an allow-list of AppArmor profiles for use by containers. + This corresponds to specific annotations applied to a PodSecurityPolicy. + For information on AppArmor, see + https://kubernetes.io/docs/tutorials/clusters/apparmor/ +spec: + params: + allowedProfiles: + - runtime/default + source: ./examples/validation/psp-app-armor/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-apparmor-allowed + annotations: + # apparmor.security.beta.kubernetes.io/pod: unconfined # runtime/default + container.apparmor.security.beta.kubernetes.io/nginx: runtime/default + labels: + app: nginx-apparmor +spec: + containers: + - name: nginx + image: nginx diff --git a/psp-capabilities/README.md b/psp-capabilities/README.md new file mode 100644 index 00000000..e59e27ad --- /dev/null +++ b/psp-capabilities/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/psp-capabilities) diff --git a/psp-capabilities/kcl.mod b/psp-capabilities/kcl.mod new file mode 100644 index 00000000..822a438f --- /dev/null +++ b/psp-capabilities/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "psp-capabilities" +version = "0.1.0" +description = "`psp-capabilities` is a kcl validation package" diff --git a/psp-capabilities/main.k b/psp-capabilities/main.k new file mode 100644 index 00000000..071392ab --- /dev/null +++ b/psp-capabilities/main.k @@ -0,0 +1,61 @@ +"""Controls Linux capabilities on containers. Corresponds to the +`allowedCapabilities` and `requiredDropCapabilities` fields in a +PodSecurityPolicy. For more information, see +https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities +""" +import regex + +schema Params: + exemptImages?: [str] + allowedCapabilities?: [str] + requiredDropCapabilities?: [str] + +params: Params = option("params") + +# Judge a image in a container config is exempt +is_exempt = lambda image: str -> bool { + result = False + if params.exemptImages: + result = any exempt_image in params.exemptImages { + (image.startswith(exempt_image.removesuffix("*")) if exempt_image.endswith("*") else exempt_image == image) + } + result +} + +# Get Containers from the input resource item. +get_containers = lambda item { + containers = [] + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + (item.spec.ephemeralContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + (item.spec.template.spec.ephemeralContainers or []) + containers = [c for c in containers if not is_exempt(c.image)] +} + +missing_drop_capabilities = lambda container -> bool { + drop_list = container.securityContext?.capabilities?.drop or [] + all drop in drop_list { + drop in (params.requiredDropCapabilities or []) + } +} + +has_disallowed_capabilities = lambda container -> bool { + add_list = container.securityContext?.capabilities?.add or [] + any add in add_list { + add not in (params.allowedCapabilities or []) + } +} + +# Define the validation function +validate = lambda item { + containers = get_containers(item) + if containers: + container_missing_drop_capabilities = [c.name for c in containers if missing_drop_capabilities(c)] + assert len(container_missing_drop_capabilities) == 0, "containers <{}> is not dropping all required capabilities. Container must drop all of {} or \"ALL\"".format(container_missing_drop_capabilities, params.requiredDropCapabilities) + container_has_disallowed_capabilities = [c.name for c in containers if has_disallowed_capabilities(c)] + assert len(container_has_disallowed_capabilities) == 0, "containers <{}> has a disallowed capability. Allowed capabilities are {}".format(container_has_disallowed_capabilities, params.allowedCapabilities) + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] \ No newline at end of file diff --git a/psp-capabilities/suite/bad.yaml b/psp-capabilities/suite/bad.yaml new file mode 100644 index 00000000..7b295c6f --- /dev/null +++ b/psp-capabilities/suite/bad.yaml @@ -0,0 +1,35 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-capabilities + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls Linux capabilities on containers. Corresponds to the + `allowedCapabilities` and `requiredDropCapabilities` fields in a + PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities +spec: + params: + allowedCapabilities: ["something"] + requiredDropCapabilities: ["must_drop"] + source: ./examples/validation/psp-capabilities/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: disallowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: kcl + image: kcllang/kcl + securityContext: + capabilities: + add: ["disallowedcapability"] + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/psp-capabilities/suite/good.yaml b/psp-capabilities/suite/good.yaml new file mode 100644 index 00000000..4bebd688 --- /dev/null +++ b/psp-capabilities/suite/good.yaml @@ -0,0 +1,36 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-capabilities + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls Linux capabilities on containers. Corresponds to the + `allowedCapabilities` and `requiredDropCapabilities` fields in a + PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#capabilities +spec: + params: + allowedCapabilities: ["something"] + requiredDropCapabilities: ["must_drop"] + source: ./examples/validation/psp-capabilities/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: allowed + labels: + owner: me.agilebank.demo +spec: + containers: + - name: kcl + image: kcllang/kcl + securityContext: + capabilities: + add: ["something"] + drop: ["must_drop", "another_one"] + resources: + limits: + cpu: "100m" + memory: "30Mi" diff --git a/psp-flexvolume-drivers/README.md b/psp-flexvolume-drivers/README.md new file mode 100644 index 00000000..46efedc2 --- /dev/null +++ b/psp-flexvolume-drivers/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/psp-flexvolume-drivers) diff --git a/psp-flexvolume-drivers/kcl.mod b/psp-flexvolume-drivers/kcl.mod new file mode 100644 index 00000000..3ea40098 --- /dev/null +++ b/psp-flexvolume-drivers/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "psp-flexvolume-drivers" +version = "0.1.0" +description = "`psp-flexvolume-drivers` is a kcl validation package" diff --git a/psp-flexvolume-drivers/main.k b/psp-flexvolume-drivers/main.k new file mode 100644 index 00000000..ccc77442 --- /dev/null +++ b/psp-flexvolume-drivers/main.k @@ -0,0 +1,27 @@ +"""Controls the allowlist of FlexVolume drivers. Corresponds to the +`allowedFlexVolumes` field in PodSecurityPolicy. For more information, +see +https://kubernetes.io/docs/concepts/policy/pod-security-policy/#flexvolume-drivers +""" + +schema Params: + allowedFlexVolumes?: [AllowedFlexVolume] + +schema AllowedFlexVolume: + driver: str + +params: Params = option("params") + +# Define the validation function +validate = lambda item { + if item.kind == "Pod": + input_volumes = [v for v in item.spec.volumes if "flexVolume" in v] + drivers = [v.driver for v in params.allowedFlexVolumes] + assert all v in input_volumes { + v.flexVolume.driver in drivers + }, "FlexVolumes is not allowed, pod: {}. Allowed drivers: {}".format(item.metadata.name, drivers) + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/psp-flexvolume-drivers/suite/bad.yaml b/psp-flexvolume-drivers/suite/bad.yaml new file mode 100644 index 00000000..66247c99 --- /dev/null +++ b/psp-flexvolume-drivers/suite/bad.yaml @@ -0,0 +1,37 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-flexvolume-drivers + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls the allowlist of FlexVolume drivers. Corresponds to the + `allowedFlexVolumes` field in PodSecurityPolicy. For more information, + see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#flexvolume-drivers +spec: + params: + allowedFlexVolumes: #[] + - driver: "example/lvm" + - driver: "example/cifs" + source: ./examples/validation/psp-flexvolume-drivers/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-flexvolume-driver-disallowed + labels: + app: nginx-flexvolume-driver +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /test + name: test-volume + readOnly: true + volumes: + - name: test-volume + flexVolume: + driver: "example/testdriver" #"example/lvm" diff --git a/psp-flexvolume-drivers/suite/good.yaml b/psp-flexvolume-drivers/suite/good.yaml new file mode 100644 index 00000000..51c973ea --- /dev/null +++ b/psp-flexvolume-drivers/suite/good.yaml @@ -0,0 +1,37 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: psp-flexvolume-drivers + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls the allowlist of FlexVolume drivers. Corresponds to the + `allowedFlexVolumes` field in PodSecurityPolicy. For more information, + see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#flexvolume-drivers +spec: + params: + allowedFlexVolumes: #[] + - driver: "example/lvm" + - driver: "example/cifs" + source: ./examples/validation/psp-flexvolume-drivers/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx-flexvolume-driver-allowed + labels: + app: nginx-flexvolume-driver +spec: + containers: + - name: nginx + image: nginx + volumeMounts: + - mountPath: /test + name: test-volume + readOnly: true + volumes: + - name: test-volume + flexVolume: + driver: "example/lvm" diff --git a/readonly-root-fs/README.md b/readonly-root-fs/README.md new file mode 100644 index 00000000..401658de --- /dev/null +++ b/readonly-root-fs/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/readonly-root-fs) diff --git a/readonly-root-fs/kcl.mod b/readonly-root-fs/kcl.mod new file mode 100644 index 00000000..b6808f59 --- /dev/null +++ b/readonly-root-fs/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "readonly-root-fs" +version = "0.1.0" +description = "`readonly-root-fs` is a kcl validation package" diff --git a/readonly-root-fs/main.k b/readonly-root-fs/main.k new file mode 100644 index 00000000..6574dc5f --- /dev/null +++ b/readonly-root-fs/main.k @@ -0,0 +1,9 @@ +schema Params: + +params: Params = option("params") +items = [item | { + if item.kind == "Pod": + spec.containers: [{ + securityContext.readOnlyRootFilesystem = True + } for container in item.spec.containers] +} for item in option("items") or []] diff --git a/readonly-root-fs/suite/good.yaml b/readonly-root-fs/suite/good.yaml new file mode 100644 index 00000000..a96ae103 --- /dev/null +++ b/readonly-root-fs/suite/good.yaml @@ -0,0 +1,22 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: readonly-root-fs + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Set read only root file system for containers +spec: + source: ./examples/mutation/readonly-root-fs/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/replica-limits/README.md b/replica-limits/README.md new file mode 100644 index 00000000..0fdcff06 --- /dev/null +++ b/replica-limits/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/replica-limits) diff --git a/replica-limits/kcl.mod b/replica-limits/kcl.mod new file mode 100644 index 00000000..75776cc0 --- /dev/null +++ b/replica-limits/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "replica-limits" +edition = "*" +version = "0.1.0" +description = "`replica-limits` is a kcl validation package" diff --git a/replica-limits/main.k b/replica-limits/main.k new file mode 100644 index 00000000..fd0962e7 --- /dev/null +++ b/replica-limits/main.k @@ -0,0 +1,13 @@ +# Construct resource and params +resource = option("resource_list") +params = option("params") +min_replicas: int = params.min_replicas or 0 +max_replicas: int = params.max_replicas or 99999 +# Define the validation function +validate_replica_limit = lambda item, min, max { + replicas = item.spec.replicas or 0 + assert min < replicas < max, "The provided number of replicas ${replicas} is not allowed for ${item.kind}: ${item.metadata.name}. Allowed range: ${min} - ${max}" + item +} +# Validate All resource +items = [validate_replica_limit(i, min_replicas, max_replicas) for i in resource.items] diff --git a/replica-limits/suite/bad.yaml b/replica-limits/suite/bad.yaml new file mode 100644 index 00000000..8291bc85 --- /dev/null +++ b/replica-limits/suite/bad.yaml @@ -0,0 +1,37 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: replica-limits + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires that objects with the field `spec.replicas` (Deployments, + ReplicaSets, etc.) specify a number of replicas within defined ranges. +spec: + params: + min_replicas: 0 + max_replicas: 5 + source: ./examples/validation/replica-limits/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 6 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/replica-limits/suite/config.yaml b/replica-limits/suite/config.yaml new file mode 100644 index 00000000..86eee46f --- /dev/null +++ b/replica-limits/suite/config.yaml @@ -0,0 +1,15 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: replica-limits + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires that objects with the field `spec.replicas` (Deployments, + ReplicaSets, etc.) specify a number of replicas within defined ranges. +spec: + params: + min_replicas: 0 + max_replicas: 5 + source: oci://ghcr.io/kcl-lang/replica-limits diff --git a/replica-limits/suite/good.yaml b/replica-limits/suite/good.yaml new file mode 100644 index 00000000..29eb4bd1 --- /dev/null +++ b/replica-limits/suite/good.yaml @@ -0,0 +1,37 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: replica-limits + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires that objects with the field `spec.replicas` (Deployments, + ReplicaSets, etc.) specify a number of replicas within defined ranges. +spec: + params: + min_replicas: 0 + max_replicas: 5 + source: ./examples/validation/replica-limits/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/required-annotations/README.md b/required-annotations/README.md new file mode 100644 index 00000000..db943839 --- /dev/null +++ b/required-annotations/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/required-annotations) diff --git a/required-annotations/kcl.mod b/required-annotations/kcl.mod new file mode 100644 index 00000000..8a909bb9 --- /dev/null +++ b/required-annotations/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "required-annotations" +edition = "*" +version = "0.1.0" +description = "`required-annotations` is a kcl validation package" diff --git a/required-annotations/main.k b/required-annotations/main.k new file mode 100644 index 00000000..d201e8a0 --- /dev/null +++ b/required-annotations/main.k @@ -0,0 +1,17 @@ +import regex + +resource = option("resource_list") +requires = option("params").requires or [] +# Define the validation function +validate_required_annotations = lambda item, requires { + if requires and item.kind != "KCLRun": + requires_map = {r.key: r.allowedRegex or "" for r in requires} + annotations = item.metadata.annotations or {} + if annotations: + assert all k, v in annotations { + regex.match(v, requires_map[k]) if requires_map[k] + }, "must provide annotations with the regex ${requires_map}, annotations ${annotations} is not allowed for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate_required_annotations(i, requires) for i in option("items")] diff --git a/required-annotations/suite/bad.yaml b/required-annotations/suite/bad.yaml new file mode 100644 index 00000000..ae36ca51 --- /dev/null +++ b/required-annotations/suite/bad.yaml @@ -0,0 +1,35 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires resources to contain specified annotations, with values matching provided regular expressions. +spec: + params: + requires: + - key: config.kubernetes.io/local-config + # Optional: If specified, a regular expression the annotation's value must match. + allowedRegex: "true" + source: ./examples/validation/required-annotations/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bad-required-annotations + annotations: + config.kubernetes.io/local-config: "false" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /root + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 diff --git a/required-annotations/suite/config.yaml b/required-annotations/suite/config.yaml new file mode 100644 index 00000000..dd51f3f5 --- /dev/null +++ b/required-annotations/suite/config.yaml @@ -0,0 +1,16 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires resources to contain specified annotations, with values matching provided regular expressions. +spec: + params: + requires: + - key: config.kubernetes.io/local-config + # Optional: If specified, a regular expression the annotation's value must match. + allowedRegex: "true" + source: oci://ghcr.io/kcl-lang/required-annotations diff --git a/required-annotations/suite/good.yaml b/required-annotations/suite/good.yaml new file mode 100644 index 00000000..82e93860 --- /dev/null +++ b/required-annotations/suite/good.yaml @@ -0,0 +1,42 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-annotations + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires resources to contain specified annotations, with values matching provided regular expressions. +spec: + params: + requires: + - key: config.kubernetes.io/local-config + # Optional: If specified, a regular expression the annotation's value must match. + allowedRegex: "true" + source: ./examples/validation/required-annotations/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: good-required-annotations + annotations: + config.kubernetes.io/local-config: "true" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 diff --git a/required-image-digests/README.md b/required-image-digests/README.md new file mode 100644 index 00000000..513a1317 --- /dev/null +++ b/required-image-digests/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/required-image-digests) diff --git a/required-image-digests/kcl.mod b/required-image-digests/kcl.mod new file mode 100644 index 00000000..c783b23f --- /dev/null +++ b/required-image-digests/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "required-image-digests" +version = "0.1.0" +description = "`required-image-digests` is a kcl validation package" diff --git a/required-image-digests/main.k b/required-image-digests/main.k new file mode 100644 index 00000000..a3da1bcf --- /dev/null +++ b/required-image-digests/main.k @@ -0,0 +1,39 @@ +"""Requires containers to have memory and CPU requests set and constrains +requests to be within the specified maximum values. + +https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +""" +import regex + +schema Params: + exemptImages?: [str] + +params: Params = option("params") + +is_exempt = lambda image: str -> bool { + result = False + if params.exemptImages: + result = any exempt_image in params.exemptImages { + (image.startswith(exempt_image.removesuffix("*")) if exempt_image.endswith("*") else exempt_image == image) + } + result +} + +# Define the validation function +validate = lambda item { + cpu = "" + memory = "" + containers = [] + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + (item.spec.ephemeralContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + (item.spec.template.spec.ephemeralContainers or []) + if containers: + images: [str] = [c.image for c in containers if not is_exempt(c.image)] + image_list_without_digest: [str] = [image for image in images if not regex.match(image, "@[a-z0-9]+([+._-][a-z0-9]+)*:[a-zA-Z0-9=_-]+")] + assert len(image_list_without_digest) == 0, "images ${image_list_without_digest} without a digest" + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/required-image-digests/suite/bad.yaml b/required-image-digests/suite/bad.yaml new file mode 100644 index 00000000..4d768d45 --- /dev/null +++ b/required-image-digests/suite/bad.yaml @@ -0,0 +1,22 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-image-digests + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires container images to contain a digest. + + https://kubernetes.io/docs/concepts/containers/images/ +spec: + source: ./examples/validation/required-image-digests/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: bad-suite +spec: + containers: + - name: kcl + image: kcllang/kcl:0.6.0 diff --git a/required-image-digests/suite/good.yaml b/required-image-digests/suite/good.yaml new file mode 100644 index 00000000..0dd7feae --- /dev/null +++ b/required-image-digests/suite/good.yaml @@ -0,0 +1,22 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-image-digests + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires container images to contain a digest. + + https://kubernetes.io/docs/concepts/containers/images/ +spec: + source: ./examples/validation/required-image-digests/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: good-suite +spec: + containers: + - name: kcl + image: kcllang/kcl:0.6.0@sha256:04ff8fce2afd1a3bc26260348e5b290e8d945b1fad4b4c16d22834c2f3a1814a diff --git a/required-labels/README.md b/required-labels/README.md new file mode 100644 index 00000000..b64c8920 --- /dev/null +++ b/required-labels/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/required-labels) diff --git a/required-labels/kcl.mod b/required-labels/kcl.mod new file mode 100644 index 00000000..d67ca3e4 --- /dev/null +++ b/required-labels/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "required-labels" +edition = "*" +version = "0.1.0" +description = "`required-labels` is a kcl validation package" diff --git a/required-labels/main.k b/required-labels/main.k new file mode 100644 index 00000000..746bb572 --- /dev/null +++ b/required-labels/main.k @@ -0,0 +1,16 @@ +import regex + +requires = option("params").requires or [] +# Define the validation function +validate_required_labels = lambda item, requires { + if requires: + requires_map = {r.key: r.allowedRegex or "" for r in requires} + labels = item.metadata.labels or {} + if labels: + assert all k, v in labels { + regex.match(v, requires_map[k]) if requires_map[k] + }, "must provide labels with the regex ${requires_map}" + item +} +# Validate All resource +items = [validate_required_labels(i, requires) for i in option("items")] diff --git a/required-labels/suite/bad.yaml b/required-labels/suite/bad.yaml new file mode 100644 index 00000000..393c1d0c --- /dev/null +++ b/required-labels/suite/bad.yaml @@ -0,0 +1,35 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires resources to contain specified labels, with values matching provided regular expressions. +spec: + params: + requires: + - key: config.kubernetes.io/local-config + # Optional: If specified, a regular expression the annotation's value must match. + allowedRegex: "true" + source: ./examples/validation/required-labels/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bad-required-labels + labels: + config.kubernetes.io/local-config: "false" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /root + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 diff --git a/required-labels/suite/config.yaml b/required-labels/suite/config.yaml new file mode 100644 index 00000000..08ef9c8c --- /dev/null +++ b/required-labels/suite/config.yaml @@ -0,0 +1,16 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires resources to contain specified labels, with values matching provided regular expressions. +spec: + params: + requires: + - key: config.kubernetes.io/local-config + # Optional: If specified, a regular expression the annotation's value must match. + allowedRegex: "true" + source: oci://ghcr.io/kcl-lang/required-labels diff --git a/required-labels/suite/good.yaml b/required-labels/suite/good.yaml new file mode 100644 index 00000000..a996bb81 --- /dev/null +++ b/required-labels/suite/good.yaml @@ -0,0 +1,42 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires resources to contain specified labels, with values matching provided regular expressions. +spec: + params: + requires: + - key: config.kubernetes.io/local-config + # Optional: If specified, a regular expression the annotation's value must match. + allowedRegex: "true" + source: ./examples/validation/required-labels/main.k +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: good-required-labels + labels: + config.kubernetes.io/local-config: "true" +spec: + rules: + - host: cafe.example.com + http: + paths: + - path: /tea + pathType: Prefix + backend: + service: + name: tea-svc + port: + number: 80 + - path: /coffee + pathType: Prefix + backend: + service: + name: coffee-svc + port: + number: 80 diff --git a/required-probes/README.md b/required-probes/README.md new file mode 100644 index 00000000..206683ca --- /dev/null +++ b/required-probes/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/required-probes) diff --git a/required-probes/kcl.mod b/required-probes/kcl.mod new file mode 100644 index 00000000..1333f54e --- /dev/null +++ b/required-probes/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "required-probes" +version = "0.1.0" +description = "`required-probes` is a kcl validation package" diff --git a/required-probes/main.k b/required-probes/main.k new file mode 100644 index 00000000..a14d475f --- /dev/null +++ b/required-probes/main.k @@ -0,0 +1,39 @@ +"""Requires containers to have memory and CPU requests set and constrains +requests to be within the specified maximum values. + +https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +""" +import regex + +schema Params: + # A list of probes that are required (ex: `readinessProbe`) + probes?: [str] + # The probe must define a field listed in `probeType` in order to satisfy the constraint (ex. `tcpSocket` satisfies `['tcpSocket', 'exec']`) + probeTypes?: [str] + +params: Params = option("params") + +probe_is_missing = lambda container: {str:}, probe: str -> bool { + result = bool(container[probe]) + if result: + probe_fields = [key for key in container[probe]] + result = all field in probe_fields { + field not in params.probeTypes + } + result +} + +# Define the validation function +validate = lambda item { + if item.kind == "Pod": + containers = item.spec.containers + probes = params.probes + probe_is_missing_containers = [[c.name, probe] for c in containers for probe in probes if probe_is_missing(c, probe)] + if len(probe_is_missing_containers) > 0: + msg = "\n".join(["Container {} field {} is invalid".format(c[0], c[1]) for c in probe_is_missing_containers]) + assert False, msg + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/required-probes/suite/bad.yaml b/required-probes/suite/bad.yaml new file mode 100644 index 00000000..d620e863 --- /dev/null +++ b/required-probes/suite/bad.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-probes + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires Pods to have readiness and/or liveness probes. +spec: + params: + probes: ["readinessProbe", "livenessProbe"] + probeTypes: ["tcpSocket"] + source: ./examples/validation/required-probes/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: test-pod1 +spec: + containers: + - name: nginx-1 + image: nginx:1.7.9 + ports: + - containerPort: 80 + livenessProbe: + # tcpSocket: + # port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/required-probes/suite/good.yaml b/required-probes/suite/good.yaml new file mode 100644 index 00000000..135099b7 --- /dev/null +++ b/required-probes/suite/good.yaml @@ -0,0 +1,35 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: required-probes + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires Pods to have readiness and/or liveness probes. +spec: + params: + probes: ["readinessProbe", "livenessProbe"] + probeTypes: ["tcpSocket"] + source: ./examples/validation/required-probes/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: test-pod1 +spec: + containers: + - name: nginx-1 + image: nginx:1.7.9 + ports: + - containerPort: 80 + livenessProbe: + tcpSocket: + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/set-annotations/README.md b/set-annotations/README.md index e23b070a..e313d5d3 100644 --- a/set-annotations/README.md +++ b/set-annotations/README.md @@ -28,3 +28,7 @@ spec: config.kubernetes.io/local-config: "true" source: oci://ghcr.io/kcl-lang/set-annotations ``` + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/set-annotations) diff --git a/set-annotations/kcl.mod b/set-annotations/kcl.mod index e94d29f7..491e69a2 100644 --- a/set-annotations/kcl.mod +++ b/set-annotations/kcl.mod @@ -1,4 +1,4 @@ [package] name = "set-annotations" -version = "0.1.0" +version = "0.1.1" description = "`set-annotations` is a kcl mutation package, which can be used to add `metadata.annotations` attributes for the Kubernetes resources." diff --git a/set-labels/README.md b/set-labels/README.md new file mode 100644 index 00000000..87e342bb --- /dev/null +++ b/set-labels/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/set-labels) diff --git a/set-labels/kcl.mod b/set-labels/kcl.mod new file mode 100644 index 00000000..a1e315bf --- /dev/null +++ b/set-labels/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "set-labels" +edition = "*" +version = "0.1.0" +description = "`set-labels` is a kcl mutation package" diff --git a/set-labels/main.k b/set-labels/main.k new file mode 100644 index 00000000..9b146051 --- /dev/null +++ b/set-labels/main.k @@ -0,0 +1,6 @@ +params = option("params") or {} +# Use `k = v` to override existing labels +labels: {str:str} = {k = v for k, v in params.labels} +items = [item | { + metadata.labels: labels +} for item in option("items")] diff --git a/set-labels/suite/config.yaml b/set-labels/suite/config.yaml new file mode 100644 index 00000000..8a83f53e --- /dev/null +++ b/set-labels/suite/config.yaml @@ -0,0 +1,9 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-labels +spec: + params: + annotations: + config.kubernetes.io/local-config: "true" + source: oci://ghcr.io/kcl-lang/set-labels diff --git a/set-labels/suite/good.yaml b/set-labels/suite/good.yaml new file mode 100644 index 00000000..9a0209a5 --- /dev/null +++ b/set-labels/suite/good.yaml @@ -0,0 +1,25 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-labels + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: mutation + documentation: >- + Set labels +spec: + params: + labels: + config.kubernetes.io/local-config: "true" + source: ./examples/mutation/set-labels/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/set-replicas/README.md b/set-replicas/README.md new file mode 100644 index 00000000..f5385fa6 --- /dev/null +++ b/set-replicas/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/set-replicas) diff --git a/set-replicas/kcl.mod b/set-replicas/kcl.mod new file mode 100644 index 00000000..1d9fab4f --- /dev/null +++ b/set-replicas/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "set-replicas" +edition = "*" +version = "0.1.0" +description = "`set-replicas` is a kcl mutation package" diff --git a/set-replicas/main.k b/set-replicas/main.k new file mode 100644 index 00000000..6060e5ff --- /dev/null +++ b/set-replicas/main.k @@ -0,0 +1,7 @@ +setReplicas = lambda items: [], replicas: int { + [item | { + if item.kind == "Deployment": + spec.replicas = replicas + } for item in items] +} +items = setReplicas(option("items") or [], option("params").replicas) diff --git a/set-replicas/suite/config.yaml b/set-replicas/suite/config.yaml new file mode 100644 index 00000000..0f1ef88e --- /dev/null +++ b/set-replicas/suite/config.yaml @@ -0,0 +1,8 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-replicas +spec: + params: + replicas: 5 + source: oci://ghcr.io/kcl-lang/set-replicas diff --git a/set-replicas/suite/good.yaml b/set-replicas/suite/good.yaml new file mode 100644 index 00000000..014b8045 --- /dev/null +++ b/set-replicas/suite/good.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: set-replicas +spec: + params: + replicas: 5 + source: ./examples/mutation/set-replicas/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/validate-auto-mount-service-account-token/README.md b/validate-auto-mount-service-account-token/README.md new file mode 100644 index 00000000..a488cbbd --- /dev/null +++ b/validate-auto-mount-service-account-token/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/validate-auto-mount-service-account-token) diff --git a/validate-auto-mount-service-account-token/kcl.mod b/validate-auto-mount-service-account-token/kcl.mod new file mode 100644 index 00000000..7278d4e4 --- /dev/null +++ b/validate-auto-mount-service-account-token/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "validate-auto-mount-service-account-token" +version = "0.1.0" +description = "`validate-auto-mount-service-account-token` is a kcl validation package" diff --git a/validate-auto-mount-service-account-token/main.k b/validate-auto-mount-service-account-token/main.k new file mode 100644 index 00000000..92d77db1 --- /dev/null +++ b/validate-auto-mount-service-account-token/main.k @@ -0,0 +1,29 @@ +"""Requires container images to begin with a string from the specified list. + +Ref: https://github.com/open-policy-agent/gatekeeper-library/blob/master/src/general/allowedrepos/constraint.tmpl +""" + +# The list of prefixes a container image is allowed to have. +repos: [str] = option("params").repos or [] + +# Define the validation function +validate = lambda item { + containers = [] + automountServiceAccountToken = False + if item.kind == "Pod" and repos: + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + automountServiceAccountToken = item.spec.automountServiceAccountToken + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + automountServiceAccountToken = item.spec.template.spec.automountServiceAccountToken + if automountServiceAccountToken == True: + assert all c in containers { + all m in c.volumeMounts { + m.mountPath == "/var/run/secrets/kubernetes.io/serviceaccount" + } + }, """Automounting service account token is disallowed for ${item.kind}: ${item.metadata.name}""" + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/validate-auto-mount-service-account-token/suite/bad.yaml b/validate-auto-mount-service-account-token/suite/bad.yaml new file mode 100644 index 00000000..1351d4f1 --- /dev/null +++ b/validate-auto-mount-service-account-token/suite/bad.yaml @@ -0,0 +1,38 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-auto-mount-service-account-token + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires container images to begin with a string from the specified list. + + Ref: https://github.com/open-policy-agent/gatekeeper-library/blob/master/src/general/automount-serviceaccount-token/constraint.tmpl +spec: + source: ./examples/validation/validate-auto-mount-service-account-token/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deploy + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + automountServiceAccountToken: true + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + volumeMounts: + - mountPath: /var/run/secrets/kubernetes.io/error_serviceaccount diff --git a/validate-auto-mount-service-account-token/suite/good.yaml b/validate-auto-mount-service-account-token/suite/good.yaml new file mode 100644 index 00000000..4a550da9 --- /dev/null +++ b/validate-auto-mount-service-account-token/suite/good.yaml @@ -0,0 +1,38 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-auto-mount-service-account-token + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Controls the ability of any Pod to enable automountServiceAccountToken. + + Ref: https://github.com/open-policy-agent/gatekeeper-library/blob/master/src/general/automount-serviceaccount-token/constraint.tmpl +spec: + source: ./examples/validation/validate-auto-mount-service-account-token/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deploy + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + automountServiceAccountToken: true + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + volumeMounts: + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount diff --git a/validate-container-limits/README.md b/validate-container-limits/README.md new file mode 100644 index 00000000..126047ce --- /dev/null +++ b/validate-container-limits/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/validate-container-limits) diff --git a/validate-container-limits/kcl.mod b/validate-container-limits/kcl.mod new file mode 100644 index 00000000..173ef1d2 --- /dev/null +++ b/validate-container-limits/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "validate-container-limits" +version = "0.1.0" +description = "`validate-container-limits` is a kcl validation package" diff --git a/validate-container-limits/main.k b/validate-container-limits/main.k new file mode 100644 index 00000000..f808c552 --- /dev/null +++ b/validate-container-limits/main.k @@ -0,0 +1,44 @@ +"""Requires containers to have memory and CPU limits set and constrains +limits to be within the specified maximum values. + +https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +""" + +schema Params: + cpu?: str + memory?: str + +params: Params = option("params") + +canonify_cpu = lambda cpu: str -> float { + result = 0 + if cpu: + if cpu[-1] == "m": + result = int(cpu[:-1]) + else: + result = int(cpu) * 1000 + result +} + +# Define the validation function +validate = lambda item { + cpu = "" + memory = "" + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + if containers: + cpu_list: [str] = [c.resources.limits.cpu for c in containers if c?.resources?.limits?.cpu] + memory_list: [str] = [c.resources.limits.memory for c in containers if c?.resources?.limits?.memory] + if params.cpu: + disallowed_cpu_list = [cpu for cpu in cpu_list if canonify_cpu(cpu) > canonify_cpu(params.cpu)] + assert not disallowed_cpu_list, "container cpu limit list '${disallowed_cpu_list}' is higher than the maximum allowed of ${params.cpu}" + if params.memory: + disallowed_memory_list = [memory for memory in memory_list if int(memory) > int(params.memory)] + assert not disallowed_memory_list, "container memory limit list '${disallowed_memory_list}' is higher than the maximum allowed of ${params.memory}" + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/validate-container-limits/suite/bad.yaml b/validate-container-limits/suite/bad.yaml new file mode 100644 index 00000000..7161ecf3 --- /dev/null +++ b/validate-container-limits/suite/bad.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-container-limits + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires containers to have memory and CPU limits set and constrains + limits to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + params: + cpu: "200m" + memory: "1Gi" + source: ./examples/validation/validate-container-limits/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: allowed +spec: + containers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "2Gi" diff --git a/validate-container-limits/suite/good.yaml b/validate-container-limits/suite/good.yaml new file mode 100644 index 00000000..a18fdf51 --- /dev/null +++ b/validate-container-limits/suite/good.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-container-limits + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires containers to have memory and CPU limits set and constrains + limits to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + params: + cpu: "200m" + memory: "1Gi" + source: ./examples/validation/validate-container-limits/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: allowed +spec: + containers: + - name: nginx + image: nginx + resources: + limits: + cpu: "100m" + memory: "1Gi" diff --git a/validate-container-requests/README.md b/validate-container-requests/README.md new file mode 100644 index 00000000..4019bfad --- /dev/null +++ b/validate-container-requests/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/validate-container-requests) diff --git a/validate-container-requests/kcl.mod b/validate-container-requests/kcl.mod new file mode 100644 index 00000000..0c98dcac --- /dev/null +++ b/validate-container-requests/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "validate-container-requests" +version = "0.1.0" +description = "`validate-container-requests` is a kcl validation package" diff --git a/validate-container-requests/main.k b/validate-container-requests/main.k new file mode 100644 index 00000000..31b79194 --- /dev/null +++ b/validate-container-requests/main.k @@ -0,0 +1,44 @@ +"""Requires containers to have memory and CPU requests set and constrains +requests to be within the specified maximum values. + +https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +""" + +schema Params: + cpu?: str + memory?: str + +params: Params = option("params") + +canonify_cpu = lambda cpu: str -> float { + result = 0 + if cpu: + if cpu[-1] == "m": + result = int(cpu[:-1]) + else: + result = int(cpu) * 1000 + result +} + +# Define the validation function +validate = lambda item { + cpu = "" + memory = "" + if item.kind == "Pod": + containers = (item.spec.containers or []) + (item.spec.initContainers or []) + elif item.kind == "Deployment": + containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + if containers: + cpu_list: [str] = [c.resources.requests.cpu for c in containers if c?.resources?.requests?.cpu] + memory_list: [str] = [c.resources.requests.memory for c in containers if c?.resources?.requests?.memory] + if params.cpu: + disallowed_cpu_list = [cpu for cpu in cpu_list if canonify_cpu(cpu) > canonify_cpu(params.cpu)] + assert not disallowed_cpu_list, "container cpu limit list '${disallowed_cpu_list}' is higher than the maximum allowed of ${params.cpu}" + if params.memory: + disallowed_memory_list = [memory for memory in memory_list if int(memory) > int(params.memory)] + assert not disallowed_memory_list, "container memory limit list '${disallowed_memory_list}' is higher than the maximum allowed of ${params.memory}" + # Return the resource + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/validate-container-requests/suite/bad.yaml b/validate-container-requests/suite/bad.yaml new file mode 100644 index 00000000..29db87b3 --- /dev/null +++ b/validate-container-requests/suite/bad.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-container-requests + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires containers to have memory and CPU requests set and constrains + requests to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + params: + cpu: "200m" + memory: "1Gi" + source: ./examples/validation/validate-container-requests/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: allowed +spec: + containers: + - name: nginx + image: nginx + resources: + requests: + cpu: "100m" + memory: "2Gi" diff --git a/validate-container-requests/suite/good.yaml b/validate-container-requests/suite/good.yaml new file mode 100644 index 00000000..6b1809a6 --- /dev/null +++ b/validate-container-requests/suite/good.yaml @@ -0,0 +1,30 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-container-requests + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Requires containers to have memory and CPU requests set and constrains + requests to be within the specified maximum values. + + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +spec: + params: + cpu: "200m" + memory: "1Gi" + source: ./examples/validation/validate-container-requests/main.k +--- +apiVersion: v1 +kind: Pod +metadata: + name: allowed +spec: + containers: + - name: nginx + image: nginx + resources: + requests: + cpu: "100m" + memory: "1Gi" diff --git a/validate-deprecated-api/README.md b/validate-deprecated-api/README.md new file mode 100644 index 00000000..e57d41a0 --- /dev/null +++ b/validate-deprecated-api/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/validate-deprecated-api) diff --git a/validate-deprecated-api/kcl.mod b/validate-deprecated-api/kcl.mod new file mode 100644 index 00000000..5d456d67 --- /dev/null +++ b/validate-deprecated-api/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "validate-deprecated-api" +version = "0.1.0" +description = "`validate-deprecated-api` is a kcl validation package" diff --git a/validate-deprecated-api/main.k b/validate-deprecated-api/main.k new file mode 100644 index 00000000..04e0f619 --- /dev/null +++ b/validate-deprecated-api/main.k @@ -0,0 +1,29 @@ +"""Verifies deprecated Kubernetes APIs to ensure all the API versions are up to date. +This template does not apply to audit as audit looks at the resources which are already +present in the cluster with non-deprecated API versions. +Ref: https://open-policy-agent.github.io/gatekeeper-library/website/validation/verifydeprecatedapi +""" + +schema Params: + kvs: [KV] + k8sVersion: int | float | str + +schema KV: + deprecatedAPI: str + kinds: [str] + targetAPI: str + +params: Params = option("params") + +# Define the validation function +validate = lambda item { + if params.kvs: + [lambda item, kv: KV { + if item.kind in kv.kinds: + assert item.apiVersion != kv.deprecatedAPI, "API {} for {} is deprecated in Kubernetes version {}, please use {} instead".format(item.kind, item.apiVersion, params.k8sVersion, kv.targetAPI) + kv + }(item, kv) for kv in params.kvs] + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/validate-deprecated-api/suite/bad.yaml b/validate-deprecated-api/suite/bad.yaml new file mode 100644 index 00000000..84ea4f11 --- /dev/null +++ b/validate-deprecated-api/suite/bad.yaml @@ -0,0 +1,54 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-deprecated-api + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Verifies deprecated Kubernetes APIs to ensure all the API versions are up to date. + This template does not apply to audit as audit looks at the resources which are already + present in the cluster with non-deprecated API versions. + Ref: https://open-policy-agent.github.io/gatekeeper-library/website/validation/verifydeprecatedapi +spec: + params: + kvs: + - deprecatedAPI: "apps/v1beta1" + kinds: ["Deployment", "ReplicaSet", "StatefulSet"] + targetAPI: "apps/v1" + - deprecatedAPI: "extensions/v1beta1" + kinds: ["ReplicaSet", "Deployment", "DaemonSet"] + targetAPI: "apps/v1" + - deprecatedAPI: "extensions/v1beta1" + kinds: ["PodSecurityPolicy"] + targetAPI: "policy/v1beta1" + - deprecatedAPI: "apps/v1beta2" + kinds: ["ReplicaSet", "StatefulSet", "Deployment", "DaemonSet"] + targetAPI: "apps/v1" + - deprecatedAPI: "extensions/v1beta1" + kinds: ["NetworkPolicy"] + targetAPI: "networking.k8s.io/v1" + k8sVersion: 1.16 + source: ./examples/validation/validate-deprecated-api/main.k +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: disallowed-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/validate-deprecated-api/suite/good.yaml b/validate-deprecated-api/suite/good.yaml new file mode 100644 index 00000000..7aea699e --- /dev/null +++ b/validate-deprecated-api/suite/good.yaml @@ -0,0 +1,54 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-deprecated-api + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Verifies deprecated Kubernetes APIs to ensure all the API versions are up to date. + This template does not apply to audit as audit looks at the resources which are already + present in the cluster with non-deprecated API versions. + Ref: https://open-policy-agent.github.io/gatekeeper-library/website/validation/verifydeprecatedapi +spec: + params: + kvs: + - deprecatedAPI: "apps/v1beta1" + kinds: ["Deployment", "ReplicaSet", "StatefulSet"] + targetAPI: "apps/v1" + - deprecatedAPI: "extensions/v1beta1" + kinds: ["ReplicaSet", "Deployment", "DaemonSet"] + targetAPI: "apps/v1" + - deprecatedAPI: "extensions/v1beta1" + kinds: ["PodSecurityPolicy"] + targetAPI: "policy/v1beta1" + - deprecatedAPI: "apps/v1beta2" + kinds: ["ReplicaSet", "StatefulSet", "Deployment", "DaemonSet"] + targetAPI: "apps/v1" + - deprecatedAPI: "extensions/v1beta1" + kinds: ["NetworkPolicy"] + targetAPI: "networking.k8s.io/v1" + k8sVersion: 1.16 + source: ./examples/validation/validate-deprecated-api/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: disallowed-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 diff --git a/validate-probes/README.md b/validate-probes/README.md new file mode 100644 index 00000000..4bebeb96 --- /dev/null +++ b/validate-probes/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/validate-probes) diff --git a/validate-probes/kcl.mod b/validate-probes/kcl.mod new file mode 100644 index 00000000..63c95f90 --- /dev/null +++ b/validate-probes/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "validate-probes" +edition = "*" +version = "0.1.0" +description = "`validate-probes` is a kcl validation package" diff --git a/validate-probes/main.k b/validate-probes/main.k new file mode 100644 index 00000000..cd49ecb0 --- /dev/null +++ b/validate-probes/main.k @@ -0,0 +1,12 @@ +# Define the validation function +kinds = ["Deployment", "DaemonSet", "StatefulSet"] +validate = lambda item { + if item.kind in kinds: + containers = item.spec.template.spec.containers or [] + assert all c in containers { + (c?.readinessProbe or {}) != (c?.livenessProbe or {}) + } if containers, "Liveness and readiness probes cannot be the same for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/validate-probes/suite/bad.yaml b/validate-probes/suite/bad.yaml new file mode 100644 index 00000000..2e7b8088 --- /dev/null +++ b/validate-probes/suite/bad.yaml @@ -0,0 +1,58 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-probes + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Liveness and readiness probes accomplish different goals, and setting both to the same + is an anti-pattern and often results in app problems in the future. This policy + checks that liveness and readiness probes are not equal. Keep in mind that if both the + probes are not set, they are considered to be equal and hence fails the check. +spec: + source: ./examples/validation/validate-probes/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - /bin/sh + - -c + - echo livenessProbe + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 10 + readinessProbe: + exec: + command: + - /bin/sh + - -c + - echo livenessProbe + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 10 diff --git a/validate-probes/suite/good.yaml b/validate-probes/suite/good.yaml new file mode 100644 index 00000000..7f0ee64f --- /dev/null +++ b/validate-probes/suite/good.yaml @@ -0,0 +1,58 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: validate-probes + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: validation + documentation: >- + Liveness and readiness probes accomplish different goals, and setting both to the same + is an anti-pattern and often results in app problems in the future. This policy + checks that liveness and readiness probes are not equal. Keep in mind that if both the + probes are not set, they are considered to be equal and hence fails the check. +spec: + source: ./examples/validation/validate-probes/main.k +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 + livenessProbe: + exec: + command: + - /bin/sh + - -c + - echo livenessProbe + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 10 + readinessProbe: + exec: + command: + - /bin/sh + - -c + - echo readinessProbe + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 2 + timeoutSeconds: 10 diff --git a/web-service/README.md b/web-service/README.md new file mode 100644 index 00000000..6c637908 --- /dev/null +++ b/web-service/README.md @@ -0,0 +1,84 @@ +## Introduction + +`web-service` is a abstraction application model for Kubernetes resources. + +## How to Use + +```yaml +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +spec: + params: + name: app + containers: + ngnix: + image: ngnix + ports: + - containerPort: 80 + service: + ports: + - port: 80 + labels: + name: app + source: oci://ghcr.io/kcl-lang/web-service +``` + +The application definition is as follows: + +```python +schema App: + """The application model.""" + name: str + replicas: int = 1 + labels?: {str:str} = {app = name} + service?: Service + containers?: {str: Container} + +schema Service: + """The service model.""" + $type?: str + ports: [Port] + +schema Port: + """The port model.""" + port: int + protocol: "TCP" | "UDP" | "SCTP" = "TCP" + targetPort?: int | str + +schema Container: + """The container model.""" + image: str + command?: [str] + args?: [str] + env?: [Env] + volumes?: [Volume] + resources?: Resource + ports: [ContainerPort] + +schema ContainerPort: + """The container port model.""" + name?: str + protocol: "TCP" | "UDP" | "SCTP" = "TCP" + containerPort: int + + check: + 1 <= containerPort <= 65535, "containerPort must be between 1 and 65535, inclusive" + +schema Env: + name: str + value: str + +schema Volume: + source: str + path: str + target: str + readOnly?: bool = False + +schema Resource: + limits?: {str:} + requests?: {str:} +``` + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/validate-probes) diff --git a/web-service/kcl.mod b/web-service/kcl.mod new file mode 100644 index 00000000..17cba278 --- /dev/null +++ b/web-service/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "web-service" +edition = "*" +version = "0.1.0" +description = "`web-service` is a kcl abstraction package" diff --git a/web-service/main.k b/web-service/main.k new file mode 100644 index 00000000..d45a4a8e --- /dev/null +++ b/web-service/main.k @@ -0,0 +1,96 @@ +schema App: + """The application model.""" + name: str + replicas: int = 1 + labels?: {str:str} = {app = name} + service?: Service + containers?: {str: Container} + +schema Service: + """The service model.""" + $type?: str + ports: [Port] + +schema Port: + """The port model.""" + port: int + protocol: "TCP" | "UDP" | "SCTP" = "TCP" + targetPort?: int | str + +schema Container: + """The container model.""" + image: str + command?: [str] + args?: [str] + env?: [Env] + volumes?: [Volume] + resources?: Resource + ports: [ContainerPort] + +schema ContainerPort: + """The container port model.""" + name?: str + protocol: "TCP" | "UDP" | "SCTP" = "TCP" + containerPort: int + + check: + 1 <= containerPort <= 65535, "containerPort must be between 1 and 65535, inclusive" + +schema Env: + name: str + value: str + +schema Volume: + source: str + path: str + target: str + readOnly?: bool = False + +schema Resource: + limits?: {str:} + requests?: {str:} + +# Convert the `App` model into Kubernetes Deployment and Service Manifests +kubernetesRender = lambda a: App { + # Construct the deployment manifest. + deployment = { + apiVersion = "apps/v1" + kind = "Deployment" + metadata.name = a.name + metadata.labels = a.labels + spec = { + replicas = a.replicas + selector.matchLabels = a.labels + template.metadata.labels = a.labels + template.spec.containers = [ + { + name = name + image = c.image + command = c.command + args = c.args + env = c.env + volumeMounts = c.volumes + resources: c.resources + ports = c.ports + } for name, c in a.containers + ] + } + } + # Construct the service manifest. + service = { + apiVersion = "v1" + kind = "Service" + metadata.name = a.name + metadata.labels = a.labels + spec = { + type = a.service?.$type + selector = a.labels + ports = a.service?.ports + } + } + # Returns Kubernetes manifests + [deployment, if a.service: service] +} + +params: App = option("params") +items = kubernetesRender(params) diff --git a/web-service/suite/config.yaml b/web-service/suite/config.yaml new file mode 100644 index 00000000..6aaf2e3a --- /dev/null +++ b/web-service/suite/config.yaml @@ -0,0 +1,20 @@ +apiVersion: config.kubernetes.io/v1 +kind: ResourceList +items: +functionConfig: + apiVersion: krm.kcl.dev/v1alpha1 + kind: KCLRun + spec: + params: + name: app + containers: + ngnix: + image: ngnix + ports: + - containerPort: 80 + service: + ports: + - port: 80 + labels: + name: app + source: oci://ghcr.io/kcl-lang/web-service diff --git a/web-service/suite/good.yaml b/web-service/suite/good.yaml new file mode 100644 index 00000000..01945d79 --- /dev/null +++ b/web-service/suite/good.yaml @@ -0,0 +1,23 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: web-service + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: abstraction + documentation: >- + Web service application abstraction +spec: + params: + name: app + containers: + ngnix: + image: ngnix + ports: + - containerPort: 80 + service: + ports: + - port: 80 + labels: + name: app + source: ./examples/abstraction/web-service/main.k diff --git a/whoami-yaml/README.md b/whoami-yaml/README.md new file mode 100644 index 00000000..584428f7 --- /dev/null +++ b/whoami-yaml/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/whoami-yaml) diff --git a/whoami-yaml/kcl.mod b/whoami-yaml/kcl.mod new file mode 100644 index 00000000..ab24a35c --- /dev/null +++ b/whoami-yaml/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "whoami-yaml" +edition = "*" +version = "0.1.0" +description = "`whoami-yaml` is a kcl application package written by KCL and YAML" diff --git a/whoami-yaml/main.k b/whoami-yaml/main.k new file mode 100644 index 00000000..f3abd404 --- /dev/null +++ b/whoami-yaml/main.k @@ -0,0 +1,42 @@ +import yaml +deployment = yaml.decode("""\ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: whoami + namespace: kube-system +spec: + replicas: 2 + selector: + matchLabels: + app: whoami + template: + metadata: + labels: + app: whoami + spec: + containers: + - name: whoami + image: containous/whoami + ports: + - containerPort: 80 + name: http +""") +service = yaml.decode("""\ +apiVersion: v1 +kind: Service +metadata: + name: whoami + namespace: kube-system +spec: + ports: + - protocol: TCP + port: 80 + targetPort: http + selector: + app: whoami +""") +items = [ + deployment + service +] diff --git a/whoami-yaml/suite/good.yaml b/whoami-yaml/suite/good.yaml new file mode 100644 index 00000000..737c531d --- /dev/null +++ b/whoami-yaml/suite/good.yaml @@ -0,0 +1,11 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: whoami-yaml + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: abstraction + documentation: >- + whoami application abstraction written by YAML +spec: + source: ./examples/abstraction/whoami-yaml/main.k diff --git a/whoami/README.md b/whoami/README.md new file mode 100644 index 00000000..b19c9f5f --- /dev/null +++ b/whoami/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/whoami) diff --git a/whoami/kcl.mod b/whoami/kcl.mod new file mode 100644 index 00000000..93101932 --- /dev/null +++ b/whoami/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "whoami" +edition = "*" +version = "0.1.0" +description = "`whoami` is a kcl application package" diff --git a/whoami/main.k b/whoami/main.k new file mode 100644 index 00000000..be29b5e8 --- /dev/null +++ b/whoami/main.k @@ -0,0 +1,40 @@ +name = "whoami" +namespace = "kube-system" +deployment = { + apiVersion = "apps/v1" + kind = "Deployment" + metadata = { + name = name + namespace = namespace + labels.app = name + } + spec = { + replicas = 2 + selector.matchLabels = metadata.labels + template.metadata.labels = metadata.labels + template.spec.containers = [ + { + name = name + image = "containous/whoami" + ports = [{ name = "http", containerPort = 80 }] + } + ] + } +} + +service = { + apiVersion = "v1" + kind = "Service" + metadata = deployment.metadata + spec.ports = [{ + protocal = "TCP" + port = 80 + targetPort = "http" + }] + selector = deployment.spec.selector +} + +items = [ + deployment + service +] diff --git a/whoami/suite/good.yaml b/whoami/suite/good.yaml new file mode 100644 index 00000000..19163903 --- /dev/null +++ b/whoami/suite/good.yaml @@ -0,0 +1,11 @@ +apiVersion: krm.kcl.dev/v1alpha1 +kind: KCLRun +metadata: + name: whoami + annotations: + krm.kcl.dev/version: 0.0.1 + krm.kcl.dev/type: abstraction + documentation: >- + whoami application abstraction +spec: + source: ./examples/abstraction/whoami/main.k