Runbook de validation EKS â fastapi-eks-project
Tests de validation pour le cluster EKS, organisĂ©s par catĂ©gorie. Principe directeur : valider par la preuve (test), pas par l'intention (le manifest). Chaque contrĂŽle de sĂ©curitĂ© ou de rĂ©silience se valide par un test positif (ce qui doit passer) ET un test nĂ©gatif (ce qui doit ĂȘtre bloquĂ©).
Table des catégories
- NetworkPolicy (enforcement réseau)
- HPA / Autoscaling
- TLS / cert-manager
- Pod Security Admission (PSA)
- Probes / Health
- Connectivité / Smoke tests
- BoĂźte Ă outils
1. NetworkPolicy
Prérequis pour que ce soit enforced sur EKS : vpc-cni déclaré en addon EKS managé avec
enableNetworkPolicy = "true". En self-managed, les NetworkPolicy sont dans etcd mais INERTES (INC-046).
Vérifier que l'addon est bien managé et actif :
aws eks list-addons --cluster-name fastapi-eks-cluster
# Doit lister "vpc-cni" (et pas renvoyer [])
kubectl get pods -n kube-system -l k8s-app=aws-node
Test négatif (le deny fonctionne)
Depuis un pod soumis Ă une politique egress restrictive, tenter une sortie NON autorisĂ©e. La policy fastapi autorise seulement 5432 (RDS), 443 (AWS), 53 (DNS). Le port 80 doit ĂȘtre bloquĂ©.
kubectl exec -it -n fastapi deployment/fastapi -- sh
# dans le pod :
curl -m 5 http://example.com
Attendu : curl: (28) Connection timed out after 5001 milliseconds
Si la page HTML s'affiche : policies INERTES (addon pas managé ou enableNetworkPolicy absent).
Test positif (les allow rules passent)
Valider que le trafic autorisé fonctionne toujours. /healthz/ready fait un SELECT 1 sur RDS,
donc il exerce DNS (port 53, résolution du hostname RDS) + port 5432 (connexion TCP).
curl -s https://api.devopsyouss.com/healthz/ready
Attendu : {"status":"ok"} (HTTP 200)
Si 503 : une rĂšgle allow (DNS ou 5432) bloque Ă tort.
Test inter-pods (optionnel)
Vérifier qu'un pod hors allowlist ne joint pas un pod protégé.
# pod témoin dans un autre namespace, tente de joindre le service fastapi
kubectl run probe --image=curlimages/curl -n default --restart=Never --rm -it -- \
curl -m 5 http://fastapi.fastapi.svc.cluster.local/
Selon les rÚgles ingress, attendu = réponse OK (ingress 8080 sans from) ou timeout.
2. HPA / Autoscaling
Prérequis : metrics-server installé (via bootstrap Ansible) + HPA défini (min:1 max:5, cpu:70%).
Ătape 1 â metrics-server remonte des mĂ©triques
kubectl top nodes
kubectl top pods -n fastapi
Attendu : des valeurs chiffrées (ex 3m 60Mi). Si error: Metrics API not available, metrics-server KO.
Ătape 2 â le HPA lit les mĂ©triques
kubectl get hpa -n fastapi
Attendu : cpu: 5%/70% (un pourcentage réel).
PiĂšge classique EKS : cpu: <unknown>/70% = metrics-server ne remonte pas, HPA aveugle.
Ătape 3 â dĂ©clencher le scale-up par la charge
Méthode recommandée : charge DEPUIS l'intérieur du cluster (pas de limite de bande passante internet). La charge externe depuis le homelab plafonne à ~46 req/s (latence ~1s/req), insuffisant pour saturer le CPU.
# Terminal 1 â observation
watch -n 2 kubectl get hpa,pods -n fastapi
# Terminal 2 â charge interne via fortio (namespace default, sans NetworkPolicy)
kubectl run loadgen --image=fortio/fortio --restart=Never --rm -it -n default -- \
load -c 150 -qps 0 -t 120s http://fastapi.fastapi.svc.cluster.local/
- viser
/(JSON statique, CPU-bound) et NON/healthz/ready(I/O-bound sur la DB, ne fait pas monter le CPU) -qps 0= débit max,-c 150= 150 connexions concurrentes
Calcul HPA : cible = ramener le CPU moyen Ă 70%. Ă 194% sur 1 replica â ceil(1 Ă 194/70) = 3 replicas.
Comme la CPU limit (500m) vaut 200% de la request (250m), le CPU moyen reste > 70% â scale jusqu'Ă maxReplicas (5).
Ătape 4 â observer le scale-down
Ă l'arrĂȘt de la charge, le scale-down N'EST PAS immĂ©diat : fenĂȘtre de stabilisation par dĂ©faut de 5 min (anti-flapping). Les replicas restent hauts puis redescendent vers min (1). Normal, pas un bug.
Charge externe (alternative, avec réserve)
# apache2-utils (ab) ou hey ; limité par la bande passante homelab -> AWS
ab -t 120 -n 1000000 -c 200 https://api.devopsyouss.com/
Bon pour un smoke test HTTPS, insuffisant pour saturer le CPU (cf 46 req/s observé).
3. TLS / cert-manager
Vérifier les ClusterIssuers
kubectl get clusterissuers
Attendu : letsencrypt-staging et letsencrypt-prod, READY: True.
Vérifier le certificat
kubectl get certificate -n fastapi
kubectl describe certificate fastapi-tls -n fastapi
Attendu : READY: True, et dans les events The certificate has been successfully issued.
La colonne / le champ de renouvellement confirme que cert-manager gĂšre le cycle de vie (renouvellement ~30j avant expiration).
Vérifier la chaßne TLS cÎté client
# Voir l'émetteur et la validité
curl -vI https://api.devopsyouss.com 2>&1 | grep -Ei "issuer|subject|expire"
# Ou inspection complĂšte
echo | openssl s_client -connect api.devopsyouss.com:443 -servername api.devopsyouss.com 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates
Staging : issuer (STAGING) Let's Encrypt, NON trusté navigateur (normal).
Prod : issuer Let's Encrypt, cadenas vert.
Bascule staging -> prod
- Ăditer
certificate.yaml:issuerRef.name: letsencrypt-staging->letsencrypt-prod kubectl apply -f certificate.yamlkubectl delete secret fastapi-tls -n fastapi(force la ré-émission)- Surveiller
kubectl describe certificate fastapi-tls -n fastapi
4. Pod Security Admission (PSA)
Prérequis : namespace fastapi labellisé pod-security.kubernetes.io/enforce: restricted
(posé par le bootstrap Ansible, INC-045).
Vérifier les labels du namespace
kubectl get ns fastapi --show-labels
Attendu : pod-security.kubernetes.io/enforce=restricted.
Test négatif (pod non conforme rejeté)
kubectl run nginx-test --image=nginx -n fastapi
Attendu : rejet Ă l'admission (violates PodSecurity "restricted": runAsNonRoot, seccompProfile, etc.).
Si le pod est créé : PSA non enforced.
Test positif (pod conforme admis)
Le pod fastapi (runAsNonRoot, seccomp RuntimeDefault, capabilities drop ALL, readOnlyRootFilesystem)
doit ĂȘtre admis et passer Running 1/1.
kubectl get pods -n fastapi
5. Probes / Health
L'app expose deux endpoints dédiés (issue #47) :
- /healthz/live : le process répond (liveness)
- /healthz/ready : SELECT 1 sur la DB, renvoie 503 si la DB est injoignable (readiness)
# Direct sur un pod (port 8080)
kubectl exec -n fastapi deployment/fastapi -- wget -qO- http://localhost:8080/healthz/live
kubectl exec -n fastapi deployment/fastapi -- wget -qO- http://localhost:8080/healthz/ready
# Via l'URL publique
curl -s https://api.devopsyouss.com/healthz/ready
Note : /healthz seul renvoie 404, ce n'est pas une route. Les routes sont /healthz/live et /healthz/ready.
6. Connectivité / Smoke tests
# Nodes prĂȘts
kubectl get nodes
# Tout le namespace applicatif
kubectl get all -n fastapi
# DNS interne (depuis un pod autorisé)
kubectl exec -n fastapi deployment/fastapi -- nslookup kubernetes.default
# Endpoint public de bout en bout
curl -s https://api.devopsyouss.com/ # {"message":"Hello all the World"}
curl -s https://api.devopsyouss.com/docs # Swagger UI
# Hostname de l'ELB (pour le CNAME Cloudflare)
kubectl get svc -n envoy-gateway-system
# Logs applicatifs
kubectl logs -n fastapi -l app=fastapi -f
7. BoĂźte Ă outils
| Outil | Usage | Note |
|---|---|---|
kubectl top |
CPU/mémoire pods et nodes | nécessite metrics-server |
fortio |
charge interne (HPA) | image fortio/fortio, Ă lancer en pod dans le cluster |
ab (apache2-utils) |
charge externe / smoke HTTPS | limité par la bande passante homelab |
hey |
charge externe (alternative Ă ab) | binaire Go unique |
openssl s_client |
inspection chaĂźne TLS | issuer, dates, SAN |
curl -vI |
headers HTTP + infos TLS rapides | |
nslookup / dig |
résolution DNS | tester la rÚgle egress 53 |
aws eks list-addons |
vérifier les addons managés | clé pour l'enforcement NetworkPolicy |
Rappel des deux tests qui ferment la boucle sécurité
| ContrÎle | Test négatif (deny) | Test positif (allow) |
|---|---|---|
| NetworkPolicy | curl http://example.com dans le pod -> timeout |
/healthz/ready -> 200 (DNS+5432 OK) |
| PSA | kubectl run nginx dans fastapi -> rejeté |
pod fastapi -> Running 1/1 |
| HPA | (n/a) | charge fortio -> scale 1 vers 5, puis scale-down |
| TLS | cert staging non trusté navigateur | cert prod -> cadenas vert |