diff --git a/add-castai-removal-disabled/README.md b/add-castai-removal-disabled/README.md new file mode 100644 index 00000000..63187a54 --- /dev/null +++ b/add-castai-removal-disabled/README.md @@ -0,0 +1,16 @@ +## Introduction + +`add-castai-removal-disabled` is a KCL mutation package. + +## How to Use + +Add the source to 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-castai-removal-disabled +spec: + source: oci://ghcr.io/kcl-lang/add-castai-removal-disabled +``` diff --git a/add-castai-removal-disabled/kcl.mod b/add-castai-removal-disabled/kcl.mod new file mode 100644 index 00000000..9bfd6df2 --- /dev/null +++ b/add-castai-removal-disabled/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-castai-removal-disabled" +edition = "*" +version = "0.1.0" +description = "`add-castai-removal-disabled` is a kcl mutation package." diff --git a/add-castai-removal-disabled/main.k b/add-castai-removal-disabled/main.k new file mode 100644 index 00000000..e8121e02 --- /dev/null +++ b/add-castai-removal-disabled/main.k @@ -0,0 +1,9 @@ +labels = option("labels") or { + "autoscaling.cast.ai/removal-disabled" = "true" +} +items = [item | { + if item.kind == "Job": + spec.template.metadata.labels: labels + elif item.kind == "CronJob": + jobTemplate.template.metadata.labels: labels +} for item in option("items") or []] diff --git a/add-network-policy-dns/README.md b/add-network-policy-dns/README.md new file mode 100644 index 00000000..71245d84 --- /dev/null +++ b/add-network-policy-dns/README.md @@ -0,0 +1,7 @@ +## Introduction + +`add-network-policy-dns` is a KCL mutation module + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/add-network-policy-dns) diff --git a/add-network-policy-dns/kcl.mod b/add-network-policy-dns/kcl.mod new file mode 100644 index 00000000..f2a9418f --- /dev/null +++ b/add-network-policy-dns/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "add-network-policy-dns" +edition = "*" +version = "0.1.0" +description = "`add-network-policy-dns` is a KCL mutation module" + diff --git a/add-network-policy-dns/kcl.mod.lock b/add-network-policy-dns/kcl.mod.lock new file mode 100644 index 00000000..e69de29b diff --git a/add-network-policy-dns/main.k b/add-network-policy-dns/main.k new file mode 100644 index 00000000..aa82dd4f --- /dev/null +++ b/add-network-policy-dns/main.k @@ -0,0 +1,21 @@ +ns_list = [item.metadata.name for item in option("items") or [] if item.kind == "Namespace"] +items = (option("items") or []) + [{ + apiVersion: "networking.k8s.io/v1" + kind: "NetworkPolicy" + name: "allow-dns" + namespace: "${ns.metadata.name}" + synchronize: False + data.spec: { + # select all pods in the namespace + podSelector.matchLabels: {} + # deny all traffic + policyTypes: ["Egress"] + egress: [{ + to: [{namespaceSelector.matchLabels.name = "kube-system"}] + ports: [{ + protocol: "UDP" + port = 53 + }] + }] + } +} for ns in ns_list] diff --git a/add-network-policy/README.md b/add-network-policy/README.md new file mode 100644 index 00000000..1d5f05ab --- /dev/null +++ b/add-network-policy/README.md @@ -0,0 +1,7 @@ +## Introduction + +`add-network-policy` is a KCL mutation module + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/add-network-policy) diff --git a/add-network-policy/kcl.mod b/add-network-policy/kcl.mod new file mode 100644 index 00000000..628b533d --- /dev/null +++ b/add-network-policy/kcl.mod @@ -0,0 +1,6 @@ +[package] +name = "add-network-policy" +edition = "*" +version = "0.1.0" +description = "`add-network-policy` is a KCL mutation module" + diff --git a/add-network-policy/kcl.mod.lock b/add-network-policy/kcl.mod.lock new file mode 100644 index 00000000..e69de29b diff --git a/add-network-policy/main.k b/add-network-policy/main.k new file mode 100644 index 00000000..81351665 --- /dev/null +++ b/add-network-policy/main.k @@ -0,0 +1,14 @@ +ns_list = [item.metadata.name for item in option("items") or [] if item.kind == "Namespace"] +items = (option("items") or []) + [{ + apiVersion: "networking.k8s.io/v1" + kind: "NetworkPolicy" + name: "default-deny" + namespace: "${ns.metadata.name}" + synchronize: True + data.spec: { + # select all pods in the namespace + podSelector: {} + # deny all traffic + policyTypes: ["Ingress", "Egress"] + } +} for ns in ns_list] diff --git a/add-safe-to-evict/README.md b/add-safe-to-evict/README.md new file mode 100644 index 00000000..54799990 --- /dev/null +++ b/add-safe-to-evict/README.md @@ -0,0 +1,7 @@ +## Introduction + +`add-safe-to-evict` is a KCL mutation module + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/add-safe-to-evict) diff --git a/add-safe-to-evict/kcl.mod b/add-safe-to-evict/kcl.mod new file mode 100644 index 00000000..1ace9072 --- /dev/null +++ b/add-safe-to-evict/kcl.mod @@ -0,0 +1,5 @@ +[package] +name = "add-safe-to-evict" +edition = "*" +version = "0.1.0" +description = "`add-safe-to-evict` is a KCL mutation module" diff --git a/add-safe-to-evict/main.k b/add-safe-to-evict/main.k new file mode 100644 index 00000000..3ecc7784 --- /dev/null +++ b/add-safe-to-evict/main.k @@ -0,0 +1,6 @@ +items = [item | { + if item.kind == "Pod": + metadata.annotations: { + "cluster-autoscaler.kubernetes.io/safe-to-evict": "true" + } +} for item in option("items") or []] diff --git a/cert-manager-limit-dns-names/README.md b/cert-manager-limit-dns-names/README.md new file mode 100644 index 00000000..930c79ca --- /dev/null +++ b/cert-manager-limit-dns-names/README.md @@ -0,0 +1,7 @@ +## Introduction + +`cert-manager-limit-dns-names` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/cert-manager-limit-dns-names) diff --git a/cert-manager-limit-dns-names/kcl.mod b/cert-manager-limit-dns-names/kcl.mod new file mode 100644 index 00000000..3ac54167 --- /dev/null +++ b/cert-manager-limit-dns-names/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "cert-manager-limit-dns-names" +version = "0.1.0" +description = "`cert-manager-limit-dns-names` is a KCL validation module" diff --git a/cert-manager-limit-dns-names/main.k b/cert-manager-limit-dns-names/main.k new file mode 100644 index 00000000..373b297e --- /dev/null +++ b/cert-manager-limit-dns-names/main.k @@ -0,0 +1,8 @@ +# Define the validation function +validate = lambda item { + if item.kind == "Certificate": + assert len(item?.spec?.dnsNames or []) <= 1, "Only one dnsNames entry allowed per certificate request." + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/cert-manager-limit-duration/README.md b/cert-manager-limit-duration/README.md new file mode 100644 index 00000000..80ac2020 --- /dev/null +++ b/cert-manager-limit-duration/README.md @@ -0,0 +1,7 @@ +## Introduction + +`cert-manager-limit-duration` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/cert-manager-limit-duration) diff --git a/cert-manager-limit-duration/kcl.mod b/cert-manager-limit-duration/kcl.mod new file mode 100644 index 00000000..4633ee0c --- /dev/null +++ b/cert-manager-limit-duration/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "cert-manager-limit-duration" +version = "0.1.0" +description = "`cert-manager-limit-duration` is a KCL validation module" diff --git a/cert-manager-limit-duration/main.k b/cert-manager-limit-duration/main.k new file mode 100644 index 00000000..94ce7668 --- /dev/null +++ b/cert-manager-limit-duration/main.k @@ -0,0 +1,11 @@ +import regex +# Define the validation function +validate = lambda item { + if item.kind == "Certificate": + if "letsencrypt" in item.spec.issuerRef.name and item.spec?.duration: + duration = int(regex.replace(item.spec?.duration, "h.*", "")) + assert 0 <= duration <= 2400, "certificate duration must be < than 2400h (100 days)" + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/cert-manager-restrict-issuer/README.md b/cert-manager-restrict-issuer/README.md new file mode 100644 index 00000000..3fc090ca --- /dev/null +++ b/cert-manager-restrict-issuer/README.md @@ -0,0 +1,7 @@ +## Introduction + +`cert-manager-restrict-issuer` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/cert-manager-restrict-issuer) diff --git a/cert-manager-restrict-issuer/kcl.mod b/cert-manager-restrict-issuer/kcl.mod new file mode 100644 index 00000000..054f0c39 --- /dev/null +++ b/cert-manager-restrict-issuer/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "cert-manager-restrict-issuer" +version = "0.1.0" +description = "`cert-manager-restrict-issuer` is a KCL validation module" diff --git a/cert-manager-restrict-issuer/main.k b/cert-manager-restrict-issuer/main.k new file mode 100644 index 00000000..117a5678 --- /dev/null +++ b/cert-manager-restrict-issuer/main.k @@ -0,0 +1,13 @@ +# Define the validation function +validate = lambda item { + if item.kind == "Certificate": + if any n in item.spec.dnsNames { + n.endswith(".corp.com") + }: + issuerRef = item.spec.issuerRef + condition = issuerRef.name == "our-corp-issuer" and issuerRef.kind == "ClusterIssuer" and issuerRef.group == "cert-manager.io" + assert condition, "When requesting a cert for this domain, you must use our corporate issuer." + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/consul-enforce-min-tls-version/README.md b/consul-enforce-min-tls-version/README.md new file mode 100644 index 00000000..c824d338 --- /dev/null +++ b/consul-enforce-min-tls-version/README.md @@ -0,0 +1,7 @@ +## Introduction + +`consul-enforce-min-tls-version` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/consul-enforce-min-tls-version) diff --git a/consul-enforce-min-tls-version/kcl.mod b/consul-enforce-min-tls-version/kcl.mod new file mode 100644 index 00000000..262dbdae --- /dev/null +++ b/consul-enforce-min-tls-version/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "consul-enforce-min-tls-version" +version = "0.1.0" +description = "`consul-enforce-min-tls-version` is a KCL validation module" diff --git a/consul-enforce-min-tls-version/main.k b/consul-enforce-min-tls-version/main.k new file mode 100644 index 00000000..4fa54019 --- /dev/null +++ b/consul-enforce-min-tls-version/main.k @@ -0,0 +1,8 @@ +# Define the validation function +validate = lambda item { + if item.kind == "Mesh": + assert item.spec.tls.incoming.tlsMinVersion == "TLSv1_2", "The minimum version of TLS is TLS v1_2" + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/disallow-cri-sock-mount/README.md b/disallow-cri-sock-mount/README.md new file mode 100644 index 00000000..0813b3b1 --- /dev/null +++ b/disallow-cri-sock-mount/README.md @@ -0,0 +1,7 @@ +## Introduction + +`disallow-cri-sock-mount` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-cri-sock-mount) diff --git a/disallow-cri-sock-mount/kcl.mod b/disallow-cri-sock-mount/kcl.mod new file mode 100644 index 00000000..6d61889c --- /dev/null +++ b/disallow-cri-sock-mount/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-cri-sock-mount" +version = "0.1.0" +description = "`disallow-cri-sock-mount` is a KCL validation module" diff --git a/disallow-cri-sock-mount/main.k b/disallow-cri-sock-mount/main.k new file mode 100644 index 00000000..0c973143 --- /dev/null +++ b/disallow-cri-sock-mount/main.k @@ -0,0 +1,22 @@ +"""Container daemon socket bind mounts allows access to the container engine on the +node. This access can be used for privilege escalation and to manage containers +outside of Kubernetes, and hence should not be allowed. This policy validates that +the sockets used for CRI engines Docker, Containerd, and CRI-O are not used. +""" + +# Define the validation function +validate = lambda item { + if item.kind == "Pod": + paths = [p.path for v in item?.spec?.volumes or [] for p in v.hostPath] + assert all p in paths { + p not in [ + "/var/run/docker.sock" + "/var/run/containerd.sock" + "/var/run/crio.sock" + "/var/run/cri-dockerd.sock" + ] + } if paths, "Use of the Docker Unix socket, Containerd Unix socket, CRI-O Unix socket and Docker CRI socket are not allowed." + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/disallow-default-namespace/README.md b/disallow-default-namespace/README.md new file mode 100644 index 00000000..da080fc8 --- /dev/null +++ b/disallow-default-namespace/README.md @@ -0,0 +1,7 @@ +## Introduction + +`disallow-default-namespace` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-default-namespace) diff --git a/disallow-default-namespace/kcl.mod b/disallow-default-namespace/kcl.mod new file mode 100644 index 00000000..c18bfe35 --- /dev/null +++ b/disallow-default-namespace/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-default-namespace" +version = "0.1.0" +description = "`disallow-default-namespace` is a KCL validation module" diff --git a/disallow-default-namespace/main.k b/disallow-default-namespace/main.k new file mode 100644 index 00000000..b5fe1869 --- /dev/null +++ b/disallow-default-namespace/main.k @@ -0,0 +1,17 @@ +kinds: [str] = option("params")?.kinds or option("kinds") or [ + "Pod" + "DaemonSet" + "Deployment" + "Job" + "StatefulSet" +] + +# Define the validation function +validate = lambda item { + if item.kind in kinds: + ns = item?.matadata?.namespace or "default" + assert ns != "Using 'default' namespace is not allowed for ${item.kind}: ${item.metadata.name}" + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/disallow-empty-ingress-host/README.md b/disallow-empty-ingress-host/README.md new file mode 100644 index 00000000..2283ff2b --- /dev/null +++ b/disallow-empty-ingress-host/README.md @@ -0,0 +1,7 @@ +## Introduction + +`disallow-empty-ingress-host` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-empty-ingress-host) diff --git a/disallow-empty-ingress-host/kcl.mod b/disallow-empty-ingress-host/kcl.mod new file mode 100644 index 00000000..9a23e965 --- /dev/null +++ b/disallow-empty-ingress-host/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-empty-ingress-host" +version = "0.1.0" +description = "`disallow-empty-ingress-host` is a KCL validation module" diff --git a/disallow-empty-ingress-host/main.k b/disallow-empty-ingress-host/main.k new file mode 100644 index 00000000..96261417 --- /dev/null +++ b/disallow-empty-ingress-host/main.k @@ -0,0 +1,14 @@ +"""An ingress resource needs to define an actual host name +in order to be valid. This policy ensures that there is a +hostname for each rule defined. +""" + +# Define the validation function +validate = lambda item { + if item.kind == "Ingress": + host_list = [r.host for r in item?.spec?.rules if not r.host] + assert len(host_list) == 0, "The Ingress host name must be defined, not empty." + item +} +# Validate All resource +items = [validate(i) for i in option("items") or []] diff --git a/disallow-helm-tiller/README.md b/disallow-helm-tiller/README.md new file mode 100644 index 00000000..8a2373cd --- /dev/null +++ b/disallow-helm-tiller/README.md @@ -0,0 +1,7 @@ +## Introduction + +`disallow-helm-tiller` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-helm-tiller) diff --git a/disallow-helm-tiller/kcl.mod b/disallow-helm-tiller/kcl.mod new file mode 100644 index 00000000..7a840bda --- /dev/null +++ b/disallow-helm-tiller/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-helm-tiller" +version = "0.1.0" +description = "`disallow-helm-tiller` is a KCL validation module" diff --git a/disallow-helm-tiller/main.k b/disallow-helm-tiller/main.k new file mode 100644 index 00000000..35e8ad30 --- /dev/null +++ b/disallow-helm-tiller/main.k @@ -0,0 +1,22 @@ +"""Tiller, found in Helm v2, has known security challenges. It requires administrative privileges and acts as a shared +resource accessible to any authenticated user. Tiller can lead to privilege escalation as +restricted users can impact other users. It is recommend to use Helm v3+ which does not contain +Tiller for these reasons. This policy validates that there is not an image +containing the name `tiller`. +""" + +# Define the validation function +validate = lambda item: {str:} { + containers: [{str:}] = [] + if item.kind == "Pod": + 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 { + "tiller" not in image + } if images, """Helm Tiller is not allowed for ${item.kind}: ${item.metadata.name}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")] diff --git a/disallow-image-repos/README.md b/disallow-image-repos/README.md new file mode 100644 index 00000000..8a3efd53 --- /dev/null +++ b/disallow-image-repos/README.md @@ -0,0 +1,5 @@ +## Introduction + +## Resource + +Code source and document is [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-image-repos) diff --git a/disallow-image-repos/kcl.mod b/disallow-image-repos/kcl.mod new file mode 100644 index 00000000..add117af --- /dev/null +++ b/disallow-image-repos/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-image-repos" +version = "0.1.0" +description = "`disallow-image-repos` is a kcl validation package" diff --git a/disallow-image-repos/main.k b/disallow-image-repos/main.k new file mode 100644 index 00000000..51281ff2 --- /dev/null +++ b/disallow-image-repos/main.k @@ -0,0 +1,23 @@ +"""Disallowed container image 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/disallow-latest-tag/README.md b/disallow-latest-tag/README.md new file mode 100644 index 00000000..4fa0c219 --- /dev/null +++ b/disallow-latest-tag/README.md @@ -0,0 +1,7 @@ +## Introduction + +`disallow-latest-tag` is a KCL validation module" + +## Resource + +The Code source and documents are [here](https://github.com/kcl-lang/artifacthub/tree/main/disallow-latest-tag) diff --git a/disallow-latest-tag/kcl.mod b/disallow-latest-tag/kcl.mod new file mode 100644 index 00000000..ed8797b0 --- /dev/null +++ b/disallow-latest-tag/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "disallow-latest-tag" +version = "0.1.0" +description = "`disallow-latest-tag` is a KCL validation module" diff --git a/disallow-latest-tag/main.k b/disallow-latest-tag/main.k new file mode 100644 index 00000000..13ceae9a --- /dev/null +++ b/disallow-latest-tag/main.k @@ -0,0 +1,18 @@ +"""Disallowed container image repositories that begin with a string from the specified list. +""" + +# Define the validation function +validate = lambda item { + containers = [] + if item.kind == "Pod": + 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 { + not image.endswith(":latest") + } if images, """Using a mutable image tag e.g. 'latest' is not allowed for ${item.kind}: ${item.metadata.name}""" + item +} +# Validate All resource +items = [validate(i) for i in option("items")]