Sécuriser Kubernetes n’est pas une démarche optionnelle : il s’agit d’un impératif opérationnel. Les clusters contiennent souvent des secrets, gèrent l’exécution d’applications critiques et sont connectés aux pipelines CI/CD — autant de vecteurs qui rendent une compromission coûteuse.
L’étendue de la surface d’attaque Kubernetes
Composants exposés et points d’entrée
Un cluster Kubernetes présente plusieurs interfaces potentiellement vulnérables :
Plan de contrôle :
- API server (port 6443) - point d’entrée principal
- etcd (port 2379/2380) - base de données du cluster
- Controller manager et scheduler
Noeuds worker :
- kubelet (port 10250) - API locale des noeuds
- kube-proxy - gestion du réseau
- Runtime de conteneurs (Docker/containerd)
Applications et services :
- Services LoadBalancer exposés sur Internet
- Ingress controllers
- Dashboards et interfaces d’administration
# Audit rapide des ports exposés
#!/bin/bash
echo "=== Services exposés publiquement ==="
kubectl get services -A --field-selector spec.type=LoadBalancer
kubectl get services -A --field-selector spec.type=NodePort
echo "\n=== Ingress exposés ==="
kubectl get ingress -A
echo "\n=== Ports ouverts sur les noeuds ==="
# À exécuter sur chaque noeud
# netstat -tlnp | grep -E ':(6443|10250|2379|2380)\b'
echo "\n=== Dashboards potentiellement exposés ==="
kubectl get pods -A | grep -i dashboard
kubectl get services -A | grep -i dashboard
Identités et permissions : l’escalade silencieuse
Les erreurs RBAC sont particulièrement pernicieuses car elles permettent une escalade progressive :
# Exemple de permissions problématiques (NE PAS FAIRE)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dangerous-binding
subjects:
- kind: ServiceAccount
name: default # ⚠️ ServiceAccount par défaut
namespace: default
roleRef:
kind: ClusterRole
name: cluster-admin # ⚠️ Permissions administrateur
apiGroup: rbac.authorization.k8s.io
# Détection des permissions excessives
echo "=== Bindings dangereux ==="
kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name == "cluster-admin") | .metadata.name'
echo "\n=== ServiceAccounts avec accès aux secrets ==="
kubectl get roles,clusterroles -A -o json | \
jq -r '.items[] | select(.rules[]? | .resources[]? == "secrets" and (.verbs[]? | IN("get", "list", "*"))) | "\(.metadata.namespace // "cluster")/\(.metadata.name)"'
echo "\n=== Tokens ServiceAccount non expirés ==="
kubectl get secrets -A -o json | \
jq -r '.items[] | select(.type == "kubernetes.io/service-account-token") | "\(.metadata.namespace)/\(.metadata.name)"'
Scénarios d’incidents concrets et réels
Cas 1 : Tesla - Cryptominage via cluster Kubernetes non sécurisé (2018)
Vecteur d’attaque : Dashboard Kubernetes exposé sans authentification
Impact : Mining de cryptomonnaie, accès aux credentials AWS
Leçons :
- Toujours authentifier les interfaces d’administration
- Surveiller l’usage CPU anormal
- Limiter l’accès des pods aux métadonnées cloud
# Protection contre l'accès aux métadonnées AWS/Azure
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-metadata-access
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# Bloquer l'accès aux métadonnées
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.169.254/32 # AWS metadata
- 168.63.129.16/32 # Azure metadata
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
Cas 2 : Exfiltration via ServiceAccount sur-privilégié
Scénario type :
- Pod applicatif compromis (vulnérabilité web)
- ServiceAccount avec permissions de lecture sur tous les secrets
- Exfiltration des credentials de base de données et API keys
# Simulation d'attaque depuis un pod compromis
# Ces commandes montrent ce qu'un attaquant peut faire
# 1. Découverte de l'environnement
cat /var/run/secrets/kubernetes.io/serviceaccount/token
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
# 2. Test des permissions
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
curl -k -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/secrets
# 3. Exfiltration si permissions insuffisantes
curl -k -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/secrets | jq '.items[].data'
Contre-mesures :
# ServiceAccount avec permissions minimales
apiVersion: v1
kind: ServiceAccount
metadata:
name: restricted-app
namespace: production
automountServiceAccountToken: false # Désactiver le token auto
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: app-minimal
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get"]
resourceNames: ["app-config"] # Seulement cette ConfigMap
Cas 3 : Compromission de la chaîne CI/CD
Vecteur : Repository compromis -> image malveillante -> déploiement automatique
Impact : Backdoor dans tous les environnements, escalade vers l’infrastructure
# Policy d'admission pour empêcher les images non signées
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: enforce
background: false
rules:
- name: check-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- image: "registry.company.com/*"
key: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----
Quantification des risques et priorités
Métriques de sécurité Kubernetes
#!/bin/bash
# Script de calcul d'un "score de sécurité" basique
SCORE=100
echo "=== Évaluation de sécurité Kubernetes ==="
# Vérifier les bindings cluster-admin (-20 points chacun)
ADMIN_BINDINGS=$(kubectl get clusterrolebindings -o json | jq '[.items[] | select(.roleRef.name == "cluster-admin")] | length')
SCORE=$((SCORE - ADMIN_BINDINGS * 20))
echo "ClusterRoleBindings cluster-admin: $ADMIN_BINDINGS (-$((ADMIN_BINDINGS * 20)) points)"
# Vérifier les pods privilégiés (-15 points chacun)
PRIV_PODS=$(kubectl get pods -A -o json | jq '[.items[] | select(.spec.securityContext.privileged == true)] | length')
SCORE=$((SCORE - PRIV_PODS * 15))
echo "Pods privilégiés: $PRIV_PODS (-$((PRIV_PODS * 15)) points)"
# Vérifier les NetworkPolicies (+10 points si présentes)
NETWORK_POLICIES=$(kubectl get networkpolicies -A --no-headers 2>/dev/null | wc -l)
if [ "$NETWORK_POLICIES" -gt 0 ]; then
SCORE=$((SCORE + 10))
echo "NetworkPolicies présentes: $NETWORK_POLICIES (+10 points)"
else
SCORE=$((SCORE - 30))
echo "Aucune NetworkPolicy (-30 points)"
fi
# Services LoadBalancer exposés (-10 points chacun)
LB_SERVICES=$(kubectl get services -A --field-selector spec.type=LoadBalancer --no-headers | wc -l)
SCORE=$((SCORE - LB_SERVICES * 10))
echo "Services LoadBalancer: $LB_SERVICES (-$((LB_SERVICES * 10)) points)"
echo "\n=== Score final: $SCORE/100 ==="
if [ "$SCORE" -ge 80 ]; then
echo "Status: EXCELLENT ✅"
elif [ "$SCORE" -ge 60 ]; then
echo "Status: BON ✅"
elif [ "$SCORE" -ge 40 ]; then
echo "Status: AMÉLIORABLE ⚠️"
else
echo "Status: CRITIQUE ❌"
fi
Coût de la non-sécurité
Estimation des impacts business :
| Scénario | Probabilité | Impact financier | Temps réparation | Coût réputation |
|---|---|---|---|---|
| Fuite de secrets | Haute | 50k-500k€ | 1-3 jours | Moyen |
| Cryptominage | Moyenne | 5k-50k€ | Quelques heures | Faible |
| Ransom/DoS | Faible | 100k-1M€ | 1 semaine | Élevé |
| Compromission client | Très faible | 1M€+ | Plusieurs mois | Critique |
KPIs de sécurité recommandés :
# Script de monitoring des KPIs sécurité
#!/bin/bash
echo "Date,Pods_Privilegies,Services_LoadBalancer,Bindings_ClusterAdmin,NetworkPolicies" > security_metrics.csv
while true; do
DATE=$(date +"%Y-%m-%d %H:%M")
PRIV=$(kubectl get pods -A -o json | jq '[.items[] | select(.spec.securityContext.privileged == true)] | length')
LB=$(kubectl get svc -A --field-selector spec.type=LoadBalancer --no-headers | wc -l)
ADMIN=$(kubectl get clusterrolebindings -o json | jq '[.items[] | select(.roleRef.name == "cluster-admin")] | length')
NP=$(kubectl get networkpolicies -A --no-headers | wc -l)
echo "$DATE,$PRIV,$LB,$ADMIN,$NP" >> security_metrics.csv
sleep 3600 # Chaque heure
done
Priorités d’action pour les équipes
Matrice de priorité (Impact vs Effort)
Actions à faire immédiatement (Fort impact, Faible effort) :
- Désactiver le ServiceAccount
default - Ajouter des NetworkPolicies de base (deny-all)
- Scanner les images avec Trivy
- Auditer les ClusterRoleBindings
Actions à planifier (Fort impact, Effort moyen) :
- Implémenter des admission controllers
- Chiffrer etcd au repos
- Configurer l’audit logging
- Déployer Falco pour la surveillance runtime
Actions long terme (Impact variable, Effort élevé) :
- Migration vers des runtimes sécurisés (gVisor, Kata)
- Implémentation de l’identité workload (SPIFFE/SPIRE)
- Zero-trust networking complet
- Automatisation complète des audits
# Checklist d'actions rapides (< 30 minutes)
#!/bin/bash
echo "=== Actions immédiates de sécurité Kubernetes ==="
# 1. Désactiver automount des tokens par défaut
kubectl patch serviceaccount default -p '{"automountServiceAccountToken":false}'
# 2. Créer une NetworkPolicy deny-all basique
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
# 3. Scanner une image critique
# trivy image nginx:latest
# 4. Audit rapide RBAC
echo "\n=== Bindings à vérifier ==="
kubectl get clusterrolebindings -o json | \
jq -r '.items[] | select(.roleRef.name | IN("cluster-admin", "admin")) | .metadata.name'
echo "\nActions terminées. Vérifiez les résultats et planifiez les actions suivantes."
Ressources pour l’évaluation des risques
Frameworks et méthodologies :
- NIST Cybersecurity Framework
- ISO 27001 - Information Security Management
- OWASP Top 10 for Kubernetes
Outils d’évaluation :
- kube-bench - CIS Kubernetes Benchmark
- kube-hunter - Penetration testing
- Polaris - Best practices validation
La sécurité Kubernetes n’est pas un état mais un processus continu. En comprenant les enjeux financiers et opérationnels, vous pourrez justifier les investissements nécessaires et prioriser efficacement vos actions. Le prochain article détaillera les risques spécifiques à surveiller.