diff --git a/kubernetes/datree/README.md b/kubernetes/datree/README.md index f2f52c7..00366d3 100644 --- a/kubernetes/datree/README.md +++ b/kubernetes/datree/README.md @@ -117,9 +117,112 @@ Let's test my latest Kubernetes tutorial that contains a Wordpress + MySQL + Ing datree test kubernetes/tutorials/basics/yaml/* ``` +# Policies + +We can log into the Datree UI to get a view of the policy management screens + +``` +datree config set token +``` + +Now that we have a token set, lets run a `datree test` command to see how `datree` checks our YAML against policies and provides us a UI for the output + +``` +datree test ./kubernetes/deployments/deployment.yaml +``` + +We can then review this test on the [Datree UI](https://hub.datree.io/) + # CI/CD examples We can even run datree in GitHub Actions and various [CI/CD integrations](https://hub.datree.io/cicd-examples).
+# Admission Controller +So far, `datree` helps us detect misconfigurations on our local machine as well as at our CI level.
+But what about the things that don't flow via our CI ?
+ +When folks deploy stuff directly to our clusters via `kubectl` or `helm`.
+Datree now allows us to not only detect but prevent misconfigurations being applied using a new admission controller feature.
+ +The admission controller is available [here](https://github.com/datreeio/admission-webhook-datree) + +## Create a Kubernetes cluster + +Let's start by creating a local `kind` [cluster](https://kind.sigs.k8s.io/) + +Note that we create a Kubernetes 1.24 cluster.
+So we want to use `datree` to validate and ensure our manifests comply with that version of Kubernetes.
+ +``` +kind create cluster --name datree --image kindest/node:v1.24.2 +``` + +We'll need a `datree` token so our admission controller can read our policies + +``` +DATREE_TOKEN=[your-token] + +``` + +## Installation + +Let's grab the `datree` manifests +``` +curl -L https://get.datree.io/admission-webhook -o datree.sh +chmod +x datree.sh +bash datree.sh +``` + +With the admission controller now deployed, `datree` will validate things coming into the cluster.
+For example, if we bypass our CI/CD, `datree` will catch our deployment and run our policy checks + + +``` +kubectl apply -f kubernetes/deployments/deployment.yaml +``` + +Output: + +``` +Error from server: error when creating "kubernetes/deployments/deployment.yaml": admission webhook "webhook-server.datree.svc" denied the request: +--- +webhook-example-deploy-Deployment.tmp.yaml + +[V] YAML validation +[V] Kubernetes schema validation + +[X] Policy check + +āŒ Ensure each container has a configured liveness probe [1 occurrence] + - metadata.name: example-deploy (kind: Deployment) +šŸ’” Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks + +āŒ Ensure each container has a configured readiness probe [1 occurrence] + - metadata.name: example-deploy (kind: Deployment) +šŸ’” Missing property object `readinessProbe` - add a properly configured readinessProbe to notify kubelet your Pods are ready for traffic + +āŒ Prevent workload from using the default namespace [1 occurrence] + - metadata.name: example-deploy (kind: Deployment) +šŸ’” Incorrect value for key `namespace` - use an explicit namespace instead of the default one (`default`) + + +(Summary) + +- Passing YAML validation: 1/1 + +- Passing Kubernetes (v1.24.2) schema validation: 1/1 + +- Passing policy check: 0/1 ++-----------------------------------+-----------------------+ +| Enabled rules in policy "Default" | 21 | +| Configs tested against policy | 1 | +| Total rules evaluated | 21 | +| Total rules skipped | 0 | +| Total rules failed | 3 | +| Total rules passed | 18 | +| See all rules in policy | https://app.datree.io | ++-----------------------------------+-----------------------+ + +``` diff --git a/kubernetes/datree/datree.sh b/kubernetes/datree/datree.sh new file mode 100755 index 0000000..9d8589e --- /dev/null +++ b/kubernetes/datree/datree.sh @@ -0,0 +1,174 @@ +#!/bin/sh + +# Sets up the environment for the admission controller webhook in the active cluster. +# check that user have kubectl installed and openssl +# generate TLS keys +generate_keys () { + printf "šŸ”‘ Generating TLS keys...\n" + + chmod 0700 "${keydir}" + cd "${keydir}" + + cat >server.conf < /dev/null;then + printf '%s\n' "openssl doesn't exist, please install openssl" + exit 1 + fi + + if ! command -v kubectl &> /dev/null;then + printf '%s\n' "kubectl doesn't exist, please install kubectl" + exit 1 + fi +} + +verify_datree_namespace_not_existing () { + local namespace_exists + namespace_exists="$(kubectl get namespace/datree --ignore-not-found)" + + if [ -n "${namespace_exists}" ] ; + then + printf '%s\n' "datree namespace already exists" + exit 1 + fi +} + +verify_webhook_resources_not_existing () { + local validating_webhook_exists + validating_webhook_exists="$(kubectl get validatingwebhookconfiguration.admissionregistration.k8s.io/webhook-datree --ignore-not-found)" + + if [ -n "${validating_webhook_exists}" ] ; + then + printf '%s\n' "datree validating webhook already exists" + exit 1 + fi +} + +are_you_sure () { + read -p "Are you sure you want to run as anonymous user? (y/n) " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo true + else + echo false + fi +} + +verify_correct_token_regex () { + if ! [[ $datree_token =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ + || $datree_token =~ ^[0-9a-zA-Z]{22}$ + || $datree_token =~ ^[0-9a-zA-Z]{20}$ ]] ; then + echo "🚫 Invalid token format" + exit 1 + fi +} + +verify_datree_namespace_not_existing + +verify_webhook_resources_not_existing + +verify_prerequisites + +set -eo pipefail + +# Create Temporary directory for TLS keys +keydir="$(mktemp -d)" + +# Generate keys into a temporary directory. +generate_keys + +basedir="$(pwd)/deployment" + +# Create the `datree` namespace. This cannot be part of the YAML file as we first need to create the TLS secret, +# which would fail otherwise. +printf "\nšŸ  Creating datree namespace...\n" +kubectl create namespace datree + +# Label datree namespace to avoid deadlocks in self hosted webhooks +# https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#avoiding-deadlocks-in-self-hosted-webhooks +kubectl label namespaces datree admission.datree/validate=skip + +# label kube-system namespace to avoid operating on the kube-system namespace +# https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#avoiding-operating-on-the-kube-system-namespace +kubectl label namespaces kube-system admission.datree/validate=skip + +# Override DATREE_TOKEN env +if [ -z "$DATREE_TOKEN" ] ; +then + echo + echo ===================================== + echo === Finish setting up the webhook === + echo ===================================== + + token_set=false + while [ "$token_set" = false ]; do + echo "šŸ‘‰ Insert token (available at https://app.datree.io/settings/token-management)" + echo "ā„¹ļø The token is used to connect the webhook with your account." + read datree_token + token_set=true + + if [ -z "$datree_token" ]; then + is_sure=$(are_you_sure) + if [ $is_sure = false ]; then + token_set=false + fi + fi + done +else + datree_token=$DATREE_TOKEN +fi + +verify_correct_token_regex + +# Create the TLS secret for the generated keys. +kubectl -n datree create secret tls webhook-server-tls \ + --cert "${keydir}/webhook-server-tls.crt" \ + --key "${keydir}/webhook-server-tls.key" + +printf "\nšŸ”— Creating webhook resources...\n" + +# Read the PEM-encoded CA certificate, base64 encode it, and replace the `${CA_PEM_B64}` placeholder in the YAML +# template with it. Then, create the Kubernetes resources. +ca_pem_b64="$(openssl base64 -A <"${keydir}/ca.crt")" +curl "https://raw.githubusercontent.com/datreeio/admission-webhook-datree/main/deployment/admission-webhook-datree.yaml" | sed -e 's@${CA_PEM_B64}@'"$ca_pem_b64"'@g' \ + | sed 's@${DATREE_TOKEN}@'"$datree_token"'@g' \ + | kubectl create -f - + +# Delete the key directory to prevent abuse (DO NOT USE THESE KEYS ANYWHERE ELSE). +rm -rf "${keydir}" + +# Wait for deployment rollout +rolloutExitCode=0 +(kubectl rollout status deployment webhook-server -n datree --timeout=180s) || rolloutExitCode=$? + +if [ "$rolloutExitCode" != "0" ]; then + printf "\nāŒ datree webhook rollout failed, please try again. If this keeps happening please contact us: https://github.com/datreeio/admission-webhook-datree/issues\n" +else + printf "\nšŸŽ‰ DONE! The webhook server is now deployed and configured\n" +fi