La CKS, la sécurité avant tout !

La CKS, la sécurité avant tout !

Cet article a été mis à jour le 26 septembre 2023 suite à la prolongation de ma certification CKS pour deux ans supplémentaires. Plusieurs parties n'étaient plus forcément à jour, j'en ai profité pour les retravailler.

Qu'est-ce que cette certification ?

La Certified Kubernetes Security Specialist ou CKS est la troisième certification sur Kubernetes proposée par la Linux Foundation, elle a pour but d'évaluer vos connaissances sur la configuration d'un cluster et l'ensemble des bonnes pratiques associées, aussi bien au niveau de l'infrastructure que sur les objets Kubernetes, avec plusieurs grands thèmes fortement liés à la sécurité.

Cette certification est pour moi la plus dure des trois, de par la multitude des domaines couverts, mais aussi par le temps restreint pour terminer les différents exercices proposés.

De mon côté, que ce soit pour mon premier passage ou ma recertification, j'ai pu terminer l'ensemble des exercices (15-17 questions) sans forcément avoir le temps de tous les tester. Une fois les questions terminées, il ne me restait environ que cinq petites minutes. Coriace non ?

Pour réussir l'examen, vous devez avoir un taux de réussite de 67 % sur un panel de 15 à 20 questions.

Pour ceux qui ont l'habitude de se tester sur killer.sh, j'ai trouvé la certification assez proche du niveau de ce simulateur. Même si killer.sh creuse beaucoup plus certaines parties, je vous recommanderai d'avoir un "high score" pour passer l'examen sereinement.

Connaissances requises

Comme les certifications précédentes, plusieurs domaines sont évalués avec un poids associé qui représente la part de ce domaine dans l'examen.

  • Cluster setup (10%) : Mettre en place des NetworkPolicy, utiliser kube-bench pour sécuriser l'ensemble des composants d'un cluster ;
  • Cluster Hardening (15%) : Modifier l'accès à l'API, mettre en place le RBAC au niveau cluster et utilisateurs, gestion des services accounts ainsi que la mise à jour du cluster ;
  • System Hardening (15%) : Utilisation de Seccomp ou AppArmor en utilisant des profiles pour restreindre l'exécution d'un conteneur ;
  • Minimize Microservice Vulnerabilities (20%) : Utiliser Open Policy Agent (OPA) pour implémenter des règles de contrôle au sein d'un cluster, gérer les Secrets et les monter au sein d'un Pod, mettre en place une RuntimeClass avec gvisor et savoir créer un conteneur proxy au sein d'un Pod pour implémenter le mTLS ;
  • Supply Chain Security (20%) : Connaître les bonnes pratiques à mettre en oeuvre au sein d'un Dockerfile, mettre en place un ImagePolicyWebhook pour la vérification des images, scanner ces dernières afin de repérer les dernières failles critiques avec trivy ;
  • Monitoring, Logging and Runtime Security (20%) : Savoir identifier un processus qui s'exécute dans un conteneur, rendre un conteneur immuable, savoir utiliser falco pour détecter les comportements suspects de conteneurs et implémenter de nouvelles règles.

La difficulté de cette certification réside aussi dans le fait qu'il y a beaucoup d'outils tiers à connaître et à savoir manipuler. Par exemple, vous aurez besoin de trivy pour analyser vos images et savoir ou non si celle-ci contient des vulnérabilités (CVE). Lors de l'examen vous avez le droit à la documentation officielle des outils concernés, néanmoins, une maîtrise basique de l'outil est recommandée pour ne pas perdre de temps, si ce n'est en gagner !

Inutile de préciser aussi que les domaines couverts par la CKAD et CKA vous seront toujours utiles dans l'ensemble des exercices de l'examen.

Interface de l'examen

Depuis mon premier passage en 2021, l'interface de l'examen a bien changée. En effet, l'examen officiel se déroule dans un environnement de bureau à distance sur une machine virtuelle Ubuntu avec comme interface graphique XFCE, c'est le cas aussi de la plateforme killer.sh dont je vous parlerai plus tard.

Cette nouvelle interface d'examen est un peu déroutante pour les utilisateurs macOS et Windows, en effet, les copier-coller sur le Terminal se font avec les touches CTRL+MAJ C et CTRL+MAJ V. De plus, j'ai remarqué qu'il y a beaucoup de latences au niveau de la souris et du clavier, ce qui n'était pas du tout à mon avantage.

Ce guide utilisateur permet de répertorier toutes les informations à connaître sur cette nouvelle interface baptisée ExmanUI. À consulter obligatoirement pour éviter les mauvaises surprises !

Bonne nouvelle cependant, l'alias k pour kubectl et la complétion des commandes sont déjà configurés tout comme vim qui bénéficie qu'une configuration par défaut pour les tabulations.

Ce que j'ai utilisé au niveau des ressources

Si vous souhaitez passer cette certification, je ne peux que vous conseiller ce cours Udemy par Kim Wüstkamp (le créateur de killer.sh et killercoda.com) : Kubernetes CKS 2023 Complete Course - Theory - Practice. Il vous aidera à balayer l'ensemble des chapitres de l'examen tout en vous faisant pratiquer soit sur un cluster Kubeadm à installer chez vous ou sur la plateforme killercoda.

Une fois que vous avez terminé ce cours, il est recommandé de s'entraîner dans un premier temps sur killercoda afin de résoudre les exercices le plus rapidement possible, n'hésitez pas à utiliser le Playground pour pratiquer sur des parties qui ne sont pas couvertes par cette plateforme, c'est le cas de Seccomp par exemple.

Une fois l'ensemble des scénarios maitrisés, vous pouvez vous lancer sur le simulateur killer.sh dans le but d'évaluer votre niveau, sachant que vous avez deux tentatives réunissant les mêmes exercices, et que chaque essai donne le droit à une session de 36 heures sur le simulateur.

Une fois vos deux tentatives expirées, vous pouvez toujours consulter les énoncés et les corrections associés pour reproduire les exercices sur votre cluster Kubernetes dans l'objectif d'être totalement prêt.

N'hésitez pas à faire et refaire les exercices, ainsi que les questions bonus pour couvrir un maximum de domaines. Comme dit plus haut, l'examen final est une vraie course de rapidité, il vous faudra savoir résoudre les exercices sans perdre votre temps !

Les domaines de l'examen

Le but de cette partie est de lister l'ensemble des commandes et concepts à avoir en tête ainsi que la documentation à consulter pour gagner en rapidité lors de l'examen final.

N'hésitez pas non plus à lire les articles sur la CKAD et CKA qui contiennent aussi plein de petites astuces qui ne seront pas reprises ici.

Les domaines tels que la mise à jour d'un cluster, la gestion des rôles et permissions (RBAC) et la création et l'analyse des Secrets ne seront pas listés ici.

CertificateSigningRequest

Pour générer un certificat qui permettra à un utilisateur de s'authentifier à travers le kube-apiserver, il y a plusieurs étapes à suivre. Je vous recommande cette partie de la documentation qui vous donne la totalité des commandes pour réaliser cette opération.

OPA Gatekeeper

Open Policy Agent (OPA) Gatekeeper permettra de mettre en œuvre des stratégies (Policies) au sein de votre cluster Kubernetes pour renforcer la conformité et la sécurité de ce dernier.

Un exemple de stratégie est disponible ici, sachant que vous n'aurez probablement pas à en créer, mais plutôt à modifier quelques valeurs.

N'hésitez pas non plus à consulter le lien GitHub du projet permettant de centraliser la documentation et les liens utiles.

NetworkPolicy

Pour ce qui est des NetworkPolicy, je vous conseille de vous baser sur le squelette de la documentation qui permet de résoudre les différents cas d'usage (ipBlock, namespaceSelector, podSelector).

Généralement, il vous sera demandé de créer une règle qui interdit les flux aussi bien ingress que egress, rien de plus simple, la documentation fournit un exemple déjà tout préparé.

Enfin, pour tester qu'une connexion est bien bloquée vers une IP ou un domaine donné, vous pouvez utiliser cette ligne de commande :

kubectl exec pod -- curl -m 1 <IP ou nom de domaine>

Le -m ou --connect-timeout permet de définir le temps maximum avant que la requête tombe en timeout, ce qui évite d'attendre trop longtemps (surtout quand le temps est compté !).

kube-bench

Si vous devez sécuriser votre cluster, il vous sera demandé d'utiliser la commande kube-bench qui va vous faire des recommandations sur les manoeuvres à effectuer sur différents composants du cluster.

Il est possible que l'on vous demande de résoudre quelques règles sur le controlplane ou un worker spécifique avec le numéro de la règle (1.1.2), la description de celle-ci ou le paramètre particulier à modifier (Ensure that the --profiling argument is set to false).

Pour cela, vous pouvez faire dans le cas du controlplane :

kube-bench controlplane | grep "1.1.2" -A10 # 1.1.2 est la règle à rechercher

kube-bench va charger les règles du controplane, le grep va récupérer la règle et le -A10 va afficher les dix prochaines lignes qui suivent le résultat du grep, ce qui permet d'avoir le contexte et la solution pour corriger ce qui a été demandé et ainsi avoir PASS.

AppArmor

La documentation Kubernetes contient l'ensemble des informations nécessaires à la mise en place d'AppArmor sur un Pod. Néanmoins, quelques commandes pratiques :

# Sur le worker
# Charger un profil
mv <mon_profil> /etc/apparmor.d/
apparmor_parser -q /etc/apparmor.d/<mon_profil>

# Vérifier que le profil est bien chargé
cat /sys/kernel/security/apparmor/profiles
# ou
aa-status | grep <mon_profil>

Et voici l'annotation à mettre au niveau du Pod (j'insiste là-dessus !), faites très attention surtout si vous faites un Deployment !

container.apparmor.security.beta.kubernetes.io/<mon_conteneur>: <mon_profil>

Seccomp

Pour Seccomp, là aussi, la documentation permet d'avoir un aperçu afin de configurer un Pod.

Depuis quelques versions, le seccompProfile se place dans un securityContext, comme ceci :

apiVersion: v1
kind: Pod
metadata:
  name: audit-pod
  labels:
    app: audit-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/audit.json

Pour terminer, avant de créer votre Pod avec sa configuration Seccomp associée, il est nécessaire d'installer le profil dans le chemin /var/lib/kubelet/seccomp/profiles/ au sein de chaque nœud du cluster.

RuntimeClass

Pour créer une classe d'exécution spécifique (RuntimeClass), comme c'est généralement demandé pour gvisor qui permet d'isoler et de limiter les appels système, basez-vous sur ce guide.

Dans l'ordre des choses, vous devrez :

  • Installer gvisor sur les nœuds du cluster
  • Créer un objet RuntimeClass
kind: RuntimeClass
metadata:
  name: gvisor 
handler: runsc
  • Ajouter le champ runtimeClassName: gvisor au sein de votre Pod

Pour tester que gvisor est correctement utilisé au sein de votre Pod, vous pouvez utiliser la commande dmseg comme ceci :

$ kubectl exec sec -- dmesg
[   0.000000] Starting gVisor...
[   0.447244] Verifying that no non-zero bytes made their way into /dev/zero...
[   0.675412] Synthesizing system calls...
[   0.837421] Preparing for the zombie uprising...
[   0.893032] Waiting for children...
[   1.087694] Constructing home...
[   1.318251] Reticulating splines...
[   1.750988] Recruiting cron-ies...
[   1.921829] Singleplexing /dev/ptmx...
[   2.298970] Feeding the init monster...
[   2.382319] Moving files to filing cabinet...
[   2.513948] Ready!

Le message Starting gVisor... nous indique que le conteneur est exécuté avec runsc.

Trivy

Trivy est un outil open source qui permet de scanner les images et de fournir un tableau avec les vulnérabilités (CVE) relevées tout en affichant pour chacune, leur criticité.

On vous demandera, lors de l'examen, de regarder si une ou plusieurs images contiennent ou non certaines vulnérabilités avec un numéro spécifique (CVE-*). Pour réaliser cette opération, celle ligne de commande peut être utile :

trivy image <mon image> | grep <numéro vulnérabilité>
# ou
trivy i <mon image> | grep <numéro vulnérabilité> # plus rapide

Falco

Lorsque Falco est installé sur la machine et se sera probablement le cas lors de l'examen, il écrit par défaut dans le fichier /var/log/syslog, à vous d'utiliser la commande grep pour récupérer les informations souhaitées :

grep falco /var/log/syslog | grep <information à chercher>

Il arrive souvent que l'on vous propose de modifier le message affiché dans les logs d'une règle, par exemple pour ajouter un ou plusieurs champs et/ou modifier la structure de celui-ci.

Dans le cas où vous devez ajouter des champs sur le message associé à une règle par défaut de Falco, vous pouvez retrouver via ce lien l'ensemble des paramètres, on vous demande dans la plupart des cas d'ajouter un timestamp en début de message (evt.time).

Dans le but de ne pas écraser la configuration de Falco, récupérez la règle à modifier dans le fichier /etc/falco/falco_rules.yaml puis venez copier le bloc de code dans le fichier /etc/falco/falco_rules.local.yaml pour ensuite apporter les modifications.

Enfin, un redémarrage du service est nécessaire pour prendre en compte les modifications : systemctl restart falco si systemctl status falco est au statut active (running), sinon exécutez la commande falco pour exécuter falco directement.

EncryptionConfiguration et etcd

Pour chiffrer les secrets et autres informations au sein d'etcd, vous aurez besoin d'une EncryptionConfiguration, un exemple est donné ici.

Dans la majorité des cas, on vous demandera de chiffrer les secrets uniquement, c'est pourquoi il est nécessaire d'épurer cette configuration pour la faire ressembler à celle-ci :

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aesgcm:
          keys:
            - name: key1
              secret: c2VjcmV0IGlzIHNlY3VyZQ==
      - identity: {} # Permet de lire les secrets en clair

J'ai inversé au niveau des providers aesgcm et identity pour chiffrer par défaut.

De plus, le paramètre --encryption-provider-config est à ajouter au niveau du kube-apiserver en le faisant pointer sur ce fichier. N'oubliez pas non plus de monter via un volume cette configuration comme indiqué dans l'étape 3 de cette documentation.

Enfin, pour récupérer la valeur d'un secret depuis etcd, vous pouvez utiliser cette commande :

ETCDCTL_API=3 etcdctl --cert <cert> --key <key> --cacert <ca> get secrets /registry/secrets/<namespace>/<nom du secret>

Audit

Comme toujours, la documentation Kubernetes donne un très bon exemple de fichier de configuration d'audit, vous pouvez vous en inspirer et l'adapter en fonction de l'énoncé.

N'oubliez pas le paramètre --audit-policy-file avec l'endroit où se trouve votre fichier au niveau du kube-apiserver ainsi que le montage de volume pour votre fichier de configuration. Vous pouvez retrouver l'ensemble des différents paramètres un peu plus loin dans la documentation.

Enfin, redémarrez le kube-apiserver pour que la configuration soit prise en compte en modifiant la place du fichier YAML du Pod statique :

cd /etc/kubernetes/manifests/
mv kube-apiserver.yaml ..
mv ../kube-apiserver.yaml .

ImagePolicyWebhook

La mise en place de ImagePolicyWebhook au sein du kube-apiserver est bien expliquée dans cette partie de la documentation en se basant sur le squelette ci-dessous :

apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ImagePolicyWebhook
  configuration:
    imagePolicy:
      kubeConfigFile: <path-to-kubeconfig-file>
      allowTTL: 50
      denyTTL: 50
      retryBackoff: 500
      defaultAllow: true # Mettre à false pour tester la bonne mise en place de l'ImagePolicyWebhook

Comme pour la configuration de l'audit, il est important de vérifier que ce fichier est bien monté au niveau d'un volume du kube-apiserver, mettre le paramètre --admission-control-config-file, et en plus, ajouter ImagePolicyWebhook dans les admission-plugins :

apiVersion: v1
kind: Pod
metadata:
[...]
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=172.30.1.2
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction # ImagePolicyWebhook à ajouter

Comme ceci :

- --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook

N'oubliez pas de redémarrer le kube-apiserver comme expliqué dans la partie Audit.

SecurityContext

Le SecurityContext ou contexte de sécurité permet de définir le contexte d'exécution d'un Pod ou d'un conteneur au sein d'un Pod. L'objectif est souvent de restreindre des privilèges ou configurer un utilisateur spécifique pour exécuter un conteneur.

Cette documentation permet de regrouper la plupart des cas de figure et d'exposer quelques bouts de code réutilisables.

Point important : S'il y a au sein d'un même Pod, une définition d'un SecurityContext au niveau du Pod mais aussi au niveau conteneur, le SecurityContext du conteneur écrase celui du Pod pour les clés identiques. C'est ce que l'on vous explique ici.

Tuer un processus qui écoute sur un port spécifique

Pour identifier un processus selon un port donné, vous pouvez utiliser la commande netstat.

Celle-ci est bien souvent installée, si ce n'est pas le cas, vous pouvez excécuter cette commande :

apt-get install net-tools

Pour repérer un processus en question et l'identifier, rien de plus simple :

netstat -plantu | grep <port>

Cette commande devrait vous retourner quelque chose sous cette forme :

tcp        0      0 0.0.0.0:660            0.0.0.0:*               LISTEN      20987/malware

20987 étant l'identifiant du processus (PID) et malware le nom de l'exécutable

Dernière chose importante, tuer le processus et supprimer le binaire malveillant :

# Identifier le chemin du binaire
$ ls -l /proc/20987/exe
lrwxrwxrwx 1 root root 0 Sep 23 15:49 /proc/20987/exe -> /usr/local/bin/malware
# Tuer le processus
$ kill -9 20987
# Supprimer le binaire
$ rm /usr/local/bin/malware

La CKS, la certification le plus difficile ?

La CKS, comme dit plus haut, est un condensé en termes de difficulté des deux premiers examens (CKAD et CKA), son périmètre est très large et le temps est vraiment très très précieux !

Entraînez-vous, essayez d'avoir de bons réflexes avec la documentation pour savoir où chercher, mais surtout, ne paniquez pas ! Si une question se révèle trop difficile ou que vos tests ne fonctionnent pas, mettez-la de côté et essayez d'y revenir un peu plus tard s'il vous reste du temps.

Et comme toujours, bonne chance à celles et ceux qui souhaitent passer cette certification ! :-)