#!/bin/bash # Partie 1 - Pré-requis et installation des composants Kubernetes # À exécuter sur TOUS les nœuds (master + workers) # Compatible CentOS Stream 10 set -e # --- Détermination du rôle du nœud --- NODE_ROLE="" usage() { echo "Usage: $0 [--role master|worker] | [master|worker]" echo " --role master|worker : forcer le rôle explicitement" echo " master|worker : argument positionnel (compatibilité)" echo " (aucun argument) : autodetect via hostname (*master*, *control* → master)" exit 1 } while [[ $# -gt 0 ]]; do case "$1" in --role) shift case "$1" in master|worker) NODE_ROLE="$1" ;; *) echo "Erreur: --role attend 'master' ou 'worker', reçu '$1'"; usage ;; esac shift ;; master|worker) NODE_ROLE="$1" shift ;; -h|--help) usage ;; *) echo "Argument inconnu: $1"; usage ;; esac done if [[ -z "$NODE_ROLE" ]]; then if [[ "$(hostname)" == *"master"* ]] || [[ "$(hostname)" == *"control"* ]]; then NODE_ROLE="master" echo "Autodetect: rôle 'master' détecté via hostname ($(hostname))" else NODE_ROLE="worker" echo "Autodetect: rôle 'worker' (hostname: $(hostname))" fi else echo "Rôle: '$NODE_ROLE' (explicite)" fi echo "=== Installation des pré-requis Kubernetes sur CentOS 10 [rôle: $NODE_ROLE] ===" # Désactiver le swap (requis par Kubernetes) echo "Désactivation du swap..." sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab # Installer container-selinux AVANT containerd pour que les labels SELinux soient corrects # POURQUOI: container-selinux fournit la policy qui confine chaque container dans le label # container_t — un container compromis ne peut pas lire /etc/passwd ni écrire # dans les répertoires système de l'hôte, même en root dans le container. echo "Installation de container-selinux..." sudo dnf install -y container-selinux # Maintenir SELinux en mode enforcing # POURQUOI: Le mode permissive ne fait que logger les violations sans les bloquer — # c'est une fausse sécurité. En enforcing + container-selinux, les appels # système non autorisés depuis les containers sont bloqués au niveau kernel. echo "Vérification SELinux en mode enforcing..." sudo setenforce 1 || true SELINUX_CURRENT=$(getenforce 2>/dev/null || echo "Unknown") if [[ "$SELINUX_CURRENT" != "Enforcing" ]]; then echo "ATTENTION: SELinux n'est pas en mode Enforcing (actuel: $SELINUX_CURRENT)" echo "Vérifier /etc/selinux/config — SELINUX doit être 'enforcing'" fi # Charger les modules kernel nécessaires # overlay, br_netfilter : requis par containerd et le CNI # ip_vs, ip_vs_rr/rr/wrr/sh : requis par Cilium en mode kube-proxy replacement (IPVS) # nf_conntrack : suivi des connexions réseau (requis par iptables/eBPF) echo "Configuration des modules kernel..." cat </dev/null || sudo modprobe nf_conntrack_ipv4 2>/dev/null || true # Configuration sysctl # bridge-nf-call-iptables/ip6tables : trafic bridgé traité par iptables (requis CNI) # ip_forward : routage IP entre interfaces (requis pod-to-pod) # rp_filter=0 : Cilium eBPF requiert que le reverse path filtering soit désactivé # inotify params : requis par Cilium pour surveiller les changements de configuration echo "Configuration sysctl..." cat < /dev/null # Activer systemd cgroup driver (OBLIGATOIRE pour kubeadm) echo "Activation du driver cgroup systemd pour containerd..." sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml # Forcer le profil seccomp par défaut sur tous les containers # POURQUOI: Sans cette option, les pods démarrent en seccomp "Unconfined" — tous les # syscalls sont permis, y compris ceux utilisés pour l'évasion de container # (keyctl, add_key, bpf, perf_event_open, etc.). # Avec "runtime/default", containerd applique le profil seccomp standard # qui bloque ~50 syscalls dangereux. Un pod qui en a besoin doit explicitement # demander securityContext.seccompProfile.type=Unconfined (bloqué par PSA). echo "Configuration du profil seccomp par défaut dans containerd..." if ! grep -q 'unset_seccomp_profile' /etc/containerd/config.toml; then sudo sed -i '/\[plugins\."io\.containerd\.grpc\.v1\.cri"\]/a\ unset_seccomp_profile = "runtime/default"' /etc/containerd/config.toml fi sudo systemctl restart containerd sudo systemctl enable containerd # Installation des paquets Kubernetes echo "Configuration du repo Kubernetes..." cat </dev/null || true if [[ "$NODE_ROLE" == "master" ]]; then sudo dnf versionlock add kubelet kubeadm kubectl 2>/dev/null || echo "Note: versionlock non disponible" else sudo dnf versionlock add kubelet kubeadm 2>/dev/null || echo "Note: versionlock non disponible" fi # Installer Helm sur le master (requis pour Cilium, KubeArmor, Kyverno) if [[ "$NODE_ROLE" == "master" ]]; then if ! command -v helm &>/dev/null; then echo "Installation de Helm..." HELM_VERSION="v3.17.3" curl -L "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" -o /tmp/helm.tar.gz tar -xzf /tmp/helm.tar.gz -C /tmp sudo mv /tmp/linux-amd64/helm /usr/local/bin/helm rm -rf /tmp/linux-amd64 /tmp/helm.tar.gz echo " ✓ Helm ${HELM_VERSION} installé" else echo " ✓ Helm déjà installé: $(helm version --short)" fi fi sudo systemctl enable kubelet # Installation et configuration d'auditd # POURQUOI: Lors du Kube Battle, on veut savoir QUI a fait QUOI sur les VMs. # auditd trace les execve, l'écriture de fichiers sensibles, les changements # de configuration K8s. Indispensable pour le post-mortem et la détection # d'évasion de container (un syscall depuis l'hôte = trace). echo "Installation d'auditd..." sudo dnf install -y audit sudo systemctl enable --now auditd sudo tee /etc/audit/rules.d/k8s.rules > /dev/null <<'EOF' -w /etc/kubernetes/ -p wa -k k8s-config -w /var/lib/kubelet/ -p wa -k kubelet-data -w /var/lib/etcd/ -p wa -k etcd-data -w /etc/containerd/ -p wa -k containerd-config -w /usr/bin/kubectl -p x -k kubectl-exec -w /usr/bin/kubeadm -p x -k kubeadm-exec -w /usr/bin/crictl -p x -k crictl-exec -a always,exit -F arch=b64 -S execve -F euid=0 -k root-exec -a always,exit -F arch=b64 -S mount -k mount-syscall EOF sudo augenrules --load 2>/dev/null || sudo systemctl restart auditd echo " ✓ auditd configuré" # Durcissement des permissions sur les répertoires sensibles # POURQUOI: Les répertoires K8s contiennent les certificats, les kubeconfigs et les # données etcd. En mode 755 (défaut), tout utilisateur de la VM peut les lire. echo "Durcissement des permissions des répertoires Kubernetes..." sudo install -d -m 0700 /etc/kubernetes 2>/dev/null || sudo chmod 700 /etc/kubernetes 2>/dev/null || true sudo install -d -m 0700 /var/lib/kubelet 2>/dev/null || sudo chmod 700 /var/lib/kubelet 2>/dev/null || true if [[ "$NODE_ROLE" == "master" ]]; then sudo install -d -m 0700 /var/lib/etcd 2>/dev/null || sudo chmod 700 /var/lib/etcd 2>/dev/null || true fi echo " ✓ /etc/kubernetes, /var/lib/kubelet, /var/lib/etcd en mode 0700" echo "" echo "=== Vérifications ===" echo "Swap désactivé: $(free -h | grep Swap | awk '{print $2}') (doit être 0)" SELINUX_STATUS=$(getenforce 2>/dev/null || echo "Unknown") if [[ "$SELINUX_STATUS" == "Enforcing" ]]; then echo "SELinux: $SELINUX_STATUS ✓" else echo "SELinux: $SELINUX_STATUS ⚠ ATTENTION: doit être Enforcing" fi echo "Modules kernel: $(lsmod | grep -E 'overlay|br_netfilter|ip_vs|nf_conntrack' | wc -l)/7 chargés" echo "firewalld: $(systemctl is-active firewalld)" echo "auditd: $(systemctl is-active auditd)" echo "containerd: $(systemctl is-active containerd)" echo "SystemdCgroup: $(grep 'SystemdCgroup = true' /etc/containerd/config.toml > /dev/null && echo 'activé ✓' || echo 'ATTENTION: non activé!')" echo "seccomp default: $(grep 'unset_seccomp_profile' /etc/containerd/config.toml > /dev/null && echo 'runtime/default ✓' || echo 'ATTENTION: Unconfined!')" echo "kptr_restrict: $(sysctl -n kernel.kptr_restrict 2>/dev/null) (doit être 2)" echo "ptrace_scope: $(sysctl -n kernel.yama.ptrace_scope 2>/dev/null) (doit être 2)" echo "" echo "✓ Pré-requis installés avec succès!" echo "Version kubeadm: $(kubeadm version -o short)" echo "Version kubelet: $(kubelet --version)" if command -v kubectl &>/dev/null; then echo "Version kubectl: $(kubectl version --client -o yaml | grep gitVersion)" fi if command -v helm &>/dev/null; then echo "Version helm: $(helm version --short)" fi