#!/usr/bin/env bash # ============================================================================= # 02 - Installation du cluster k3s (app-01) # ============================================================================= # Prerequis : 00-bootstrap-common.sh app deja execute sur ce serveur. # # sudo K3S_VERSION=v1.31.5+k3s1 PUBLIC_IP= bash 02-setup-k3s-server.sh # # Choix structurants et pourquoi : # --secrets-encryption les Secrets sont chiffres au repos dans la base # d'etat de k3s. Sans ce drapeau, un acces disque # (snapshot, vol de volume) livre tous les secrets. # --protect-kernel-defaults refuse de demarrer si les sysctl attendus par # kubelet ne sont pas poses : echec bruyant plutot # que derive silencieuse. # audit-log journal d'audit de l'API : indispensable pour # repondre a "qui a supprime ce deploiement". # Traefik est CONSERVE (celui livre par k3s) et reconfigure via # HelmChartConfig : entrypoints, en-tetes de # securite, IPs de confiance Cloudflare. set -euo pipefail [[ "$EUID" -eq 0 ]] || { echo "Executer en root (sudo)." >&2; exit 1; } K3S_VERSION="${K3S_VERSION:-v1.31.5+k3s1}" PUBLIC_IP="${PUBLIC_IP:-$(curl -s --max-time 5 https://ifconfig.me || true)}" PRIVATE_IP="${PRIVATE_IP:-10.10.1.10}" MANIFEST_DIR=/var/lib/rancher/k3s/server/manifests log() { printf '\n>>> %s\n' "$*"; } [[ -n "$PUBLIC_IP" ]] || { echo "PUBLIC_IP introuvable, passez-la en variable." >&2; exit 1; } # --- 1. Prerequis noyau ------------------------------------------------------ log "Parametres noyau exiges par kubelet (--protect-kernel-defaults)" cat > /etc/sysctl.d/90-kubelet.conf <<'CONF' vm.panic_on_oom=0 vm.overcommit_memory=1 kernel.panic=10 kernel.panic_on_oops=1 CONF sysctl --system >/dev/null log "Desactivation du swap (exige par kubelet)" swapoff -a || true sed -i '/\sswap\s/s/^/#/' /etc/fstab || true # --- 2. Politique d'audit de l'API Kubernetes ------------------------------- log "Politique d'audit" mkdir -p /var/lib/rancher/k3s/server /var/log/k3s cat > /var/lib/rancher/k3s/server/audit-policy.yaml <<'YAML' apiVersion: audit.k8s.io/v1 kind: Policy # Ne jamais journaliser le contenu des Secrets : le journal d'audit deviendrait # lui-meme un coffre-fort en clair. omitStages: - RequestReceived rules: - level: None resources: - group: "" resources: ["secrets", "configmaps"] verbs: ["get", "list", "watch"] # Bruit de fond : sondes et lectures d'etat. - level: None users: ["system:kube-proxy", "system:apiserver"] verbs: ["watch", "list"] - level: None nonResourceURLs: ["/healthz*", "/readyz*", "/livez*", "/version", "/metrics"] # Toute ecriture est tracee avec ses metadonnees (qui, quoi, quand). - level: Metadata verbs: ["create", "update", "patch", "delete", "deletecollection"] # Acces aux Secrets : trace, sans le contenu. - level: Metadata resources: - group: "" resources: ["secrets"] # Escalades de privileges : trace complet cote requete. - level: Request resources: - group: "rbac.authorization.k8s.io" resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"] - level: Metadata YAML chmod 600 /var/lib/rancher/k3s/server/audit-policy.yaml # --- 3. Configuration Traefik (avant l'installation : k3s l'applique au boot) - log "Configuration Traefik (HelmChartConfig)" mkdir -p "$MANIFEST_DIR" cat > "${MANIFEST_DIR}/traefik-config.yaml" <<'YAML' apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: traefik namespace: kube-system spec: valuesContent: |- # Les vraies IP des visiteurs arrivent dans X-Forwarded-For, pose par # Cloudflare. Sans cette liste de confiance, la limitation de debit et les # audit_logs verraient tous l'IP de Cloudflare : inexploitable. # Rafraichir avec scripts/refresh-cloudflare-ips.sh. additionalArguments: - "--entrypoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32" - "--entrypoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32" # Tout le trafic HTTP est redirige en HTTPS au niveau de l'entrypoint : # aucun Ingress ne peut oublier de le faire. - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--entrypoints.web.http.redirections.entryPoint.scheme=https" - "--entrypoints.web.http.redirections.entryPoint.permanent=true" # Delais de garde : borne les connexions lentes (slowloris). - "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=60s" - "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0s" - "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=180s" - "--serversTransport.maxIdleConnsPerHost=100" # WebSocket (Socket.IO) : pas de timeout d'ecriture, sinon les # notifications temps reel sont coupees toutes les 60 s. - "--metrics.prometheus=true" - "--metrics.prometheus.addEntryPointsLabels=true" - "--metrics.prometheus.addServicesLabels=true" - "--accesslog=true" - "--accesslog.format=json" - "--accesslog.fields.headers.defaultMode=drop" - "--accesslog.fields.headers.names.User-Agent=keep" - "--accesslog.fields.headers.names.Cf-Connecting-Ip=keep" - "--ping=true" # Le tableau de bord Traefik n'est jamais expose. ingressRoute: dashboard: enabled: false logs: general: level: WARN access: enabled: true # Le service est en LoadBalancer (klipper-lb de k3s) : il ecoute # directement sur les ports 80/443 de l'hote, filtres par le firewall # Hetzner qui n'accepte que les IP Cloudflare. service: spec: externalTrafficPolicy: Local resources: requests: cpu: 100m memory: 128Mi limits: memory: 512Mi YAML # --- 4. Installation de k3s -------------------------------------------------- if ! command -v k3s >/dev/null; then log "Installation de k3s ${K3S_VERSION}" curl -sfL https://get.k3s.io | \ INSTALL_K3S_VERSION="${K3S_VERSION}" \ INSTALL_K3S_EXEC="server \ --node-name=xpeditis-prod-app-01 \ --node-ip=${PRIVATE_IP} \ --advertise-address=${PRIVATE_IP} \ --tls-san=${PUBLIC_IP} \ --tls-san=${PRIVATE_IP} \ --write-kubeconfig-mode=0600 \ --secrets-encryption \ --protect-kernel-defaults \ --kube-apiserver-arg=audit-log-path=/var/log/k3s/audit.log \ --kube-apiserver-arg=audit-policy-file=/var/lib/rancher/k3s/server/audit-policy.yaml \ --kube-apiserver-arg=audit-log-maxage=30 \ --kube-apiserver-arg=audit-log-maxbackup=10 \ --kube-apiserver-arg=audit-log-maxsize=100 \ --kube-apiserver-arg=request-timeout=300s \ --kubelet-arg=streaming-connection-idle-timeout=5m \ --kubelet-arg=event-qps=0 \ --etcd-expose-metrics=false" \ sh - else log "k3s deja installe : $(k3s --version | head -1)" fi systemctl enable --now k3s log "Attente de la disponibilite du noeud" for _ in $(seq 1 60); do k3s kubectl get node >/dev/null 2>&1 && break sleep 5 done k3s kubectl get node -o wide # --- 5. kubectl pour l'utilisateur deploy ----------------------------------- log "Configuration de kubectl pour l'utilisateur deploy" DEPLOY_USER="${DEPLOY_USER:-deploy}" install -d -m 700 -o "$DEPLOY_USER" -g "$DEPLOY_USER" "/home/${DEPLOY_USER}/.kube" install -m 600 -o "$DEPLOY_USER" -g "$DEPLOY_USER" \ /etc/rancher/k3s/k3s.yaml "/home/${DEPLOY_USER}/.kube/config" grep -q 'KUBECONFIG' "/home/${DEPLOY_USER}/.bashrc" || \ echo 'export KUBECONFIG=$HOME/.kube/config' >> "/home/${DEPLOY_USER}/.bashrc" # `k3s kubectl` reste reserve a root ; deploy passe par son kubeconfig. ln -sf /usr/local/bin/k3s /usr/local/bin/kubectl # --- 6. Rotation des journaux d'audit --------------------------------------- cat > /etc/logrotate.d/k3s-audit <<'CONF' /var/log/k3s/audit.log { daily rotate 30 compress delaycompress missingok notifempty copytruncate su root root } CONF # --- 7. Verifications -------------------------------------------------------- log "Etat du cluster" k3s kubectl get nodes k3s kubectl -n kube-system get pods cat < ~/.kube/xpeditis-prod.yaml chmod 600 ~/.kube/xpeditis-prod.yaml export KUBECONFIG=~/.kube/xpeditis-prod.yaml kubectl get nodes Etape suivante : sudo bash 03-install-cluster-addons.sh ============================================================================= NEXT