Aller au contenu principal
SécuritéCloudZero TrustDevSecOps

mTLS et Service Mesh en pratique

30 min de lecture Sécurité Cloud — Chapitre 2

Implémente mTLS, déploie un Service Mesh (Istio/Linkerd), utilise Tailscale, et mets en place le Zero Trust progressivement sur Kubernetes.

Du TLS classique au mTLS : pourquoi l’authentification mutuelle change tout

Quand tu accèdes à un site en HTTPS, ton navigateur vérifie le certificat du serveur — c’est le TLS classique. Mais le serveur, lui, ne sait rien de toi. Il accepte n’importe quel client. Dans un environnement microservices, cette asymétrie est un problème de sécurité majeur : n’importe quel pod compromis peut appeler n’importe quel service interne.

Le mTLS (mutual TLS) résout ce problème en exigeant que les deux parties s’authentifient mutuellement. Le client présente un certificat au serveur, et le serveur présente un certificat au client. Les deux vérifient l’identité de l’autre avant d’établir la communication chiffrée. C’est le fondement technique du Zero Trust pour les communications service-to-service.

🔥 Cas réel : Chez Monzo (banque digitale UK), chaque microservice (plus de 2 500) communique exclusivement en mTLS via un service mesh. Quand un service de leur plateforme de paiement a été compromis lors d’un test de pénétration, le lateral movement a été impossible car le service compromis n’avait de certificats valides que pour ses dépendances directes. Sans mTLS, l’attaquant aurait pu atteindre la base de données clients en quelques sauts.

En production, personne ne gère les certificats mTLS manuellement. C’est là qu’intervient SPIFFE (Secure Production Identity Framework For Everyone), un standard CNCF qui attribue une identité cryptographique à chaque workload :

# Chaque workload reçoit une identité SPIFFE unique
# Format : spiffe://<trust-domain>/<path>
spiffe://cluster.local/ns/production/sa/payment-service
spiffe://cluster.local/ns/production/sa/checkout-service

# SPIRE (l'implémentation de référence) distribue automatiquement
# des certificats X.509 appelés SVIDs (SPIFFE Verifiable Identity Documents)
# Rotation automatique, durée de vie courte (1h par défaut)

# Vérifier l'identité d'un workload
spire-agent api fetch x509 -socketPath /run/spire/sockets/agent.sock

🧠 À retenir : Le mTLS seul authentifie l’identité, mais ne gère pas l’autorisation. Savoir qui appelle ne suffit pas — il faut aussi contrôler ce qu’il a le droit de faire. C’est pour ça qu’on combine mTLS avec des policies d’autorisation.

Service Mesh : le Zero Trust transparent pour les développeurs

Un service mesh implémente le mTLS et l’autorisation fine-grained de manière transparente — les développeurs n’ont pas à modifier leur code applicatif. Le mesh intercepte chaque requête via un sidecar proxy déployé à côté de chaque pod, gère les certificats automatiquement et applique les policies de sécurité.

L’architecture se divise en deux plans. Le control plane gère la configuration, distribue les certificats et centralise les policies. Le data plane est constitué des sidecar proxies qui interceptent le trafic, appliquent le mTLS et enforced les règles d’autorisation.

Istio : puissant mais complexe

Istio (Google, IBM, Lyft) est le service mesh le plus riche en fonctionnalités. Il utilise Envoy comme sidecar proxy. Voici comment activer le mTLS strict et définir une politique d’autorisation fine-grained :

# PeerAuthentication — Force le mTLS pour tout le namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: strict-mtls
  namespace: production
spec:
  mtls:
    mode: STRICT  # Refuse toute connexion non-mTLS

---
# AuthorizationPolicy — Seul checkout-service peut appeler payment-service
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payment-access
  namespace: production
spec:
  selector:
    matchLabels:
      app: payment-service
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/production/sa/checkout-service"
      to:
        - operation:
            methods: ["POST"]
            paths: ["/api/v1/charge"]

Ce manifest fait deux choses. La PeerAuthentication refuse toute connexion en clair dans le namespace production — si un service essaie d’appeler en HTTP au lieu de mTLS, la requête est rejetée. L’AuthorizationPolicy va plus loin : seul le service checkout-service peut faire un POST sur /api/v1/charge du payment-service. Tout autre service, même avec un certificat mTLS valide, sera bloqué.

Linkerd : léger et pragmatique

Linkerd est l’alternative pour les équipes qui veulent le mTLS sans la complexité d’Istio. Écrit en Rust, son proxy est significativement plus léger qu’Envoy :

# Installation complète en 3 commandes
curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install | sh
linkerd install --crds | kubectl apply -f -
linkerd install | kubectl apply -f -

# Activer le mesh sur un namespace (injection du sidecar)
kubectl get deploy -n production -o yaml | linkerd inject - | kubectl apply -f -

# Vérifier que le mTLS est actif entre les services
linkerd viz edges -n production
# SRC           DST              SECURED
# checkout      payment          √
# frontend      checkout         √
# payment       database-proxy   √

💡 Tip DevOps : Si tu débutes avec les service meshes, commence par Linkerd. Tu auras le mTLS automatique en 15 minutes. Istio est plus puissant mais demande une équipe dédiée pour l’opérer. En règle générale : Linkerd pour les petites/moyennes infras, Istio quand tu as besoin de traffic management avancé (canary, fault injection, circuit breaking).

Tailscale : le Zero Trust sans la complexité

Tailscale est un réseau overlay basé sur WireGuard qui implémente le Zero Trust avec une simplicité radicale. Contrairement à un VPN classique qui route tout le trafic via un concentrateur central (hub-and-spoke), Tailscale établit des tunnels WireGuard directs entre les nodes (mesh peer-to-peer).

Chaque node reçoit une IP stable (100.x.y.z) et les communications sont chiffrées de bout en bout. Le control plane (coordination server) ne voit jamais le trafic — il distribue uniquement les clés publiques et les ACLs.

Les ACLs Tailscale définissent qui peut accéder à quoi, avec une granularité par utilisateur, groupe et port :

{
  "acls": [
    {
      "action": "accept",
      "src": ["group:engineering"],
      "dst": [
        "tag:webserver:443",
        "tag:api:8080",
        "tag:monitoring:3000"
      ]
    },
    {
      "action": "accept",
      "src": ["group:ops"],
      "dst": ["tag:server:22"]
    }
  ],
  "groups": {
    "group:engineering": ["alice@company.com", "bob@company.com"],
    "group:ops": ["admin@company.com"]
  },
  "tagOwners": {
    "tag:webserver": ["group:ops"],
    "tag:api": ["group:ops"],
    "tag:server": ["group:ops"]
  }
}

⚠️ Attention : Tailscale est excellent pour les accès humain-vers-machine (remplacer un VPN) et les connexions inter-sites. Mais pour le trafic service-to-service dans Kubernetes, un service mesh (Istio/Linkerd) reste plus adapté — il offre l’observabilité L7, le traffic management et les authorization policies que Tailscale ne couvre pas.

Implémentation progressive : la roadmap réaliste

Le Zero Trust ne se déploie pas en big bang. Voici une roadmap en quatre phases, validée sur des dizaines de migrations en entreprise :

Phase 1 — Identité (mois 1-2) : SSO avec OIDC pour toutes les applications, MFA obligatoire, service accounts Kubernetes dédiés par service. C’est la fondation — sans identité forte, rien d’autre ne tient.

Phase 2 — Réseau (mois 2-4) : Déploiement du service mesh en mode permissif (mTLS optionnel), puis passage progressif en mode strict. Network Policies Kubernetes pour la micro-segmentation :

# Network Policy — payment-service ne peut recevoir que de checkout
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: payment-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: payment-service
  policyTypes: ["Ingress", "Egress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: checkout-service
      ports:
        - port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - port: 5432
    - to:  # DNS
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - port: 53
          protocol: UDP

Phase 3 — Observabilité (mois 4-6) : Chaque décision d’accès (allow et deny) est loguée. Ces logs structurés sont la source de vérité pour détecter les anomalies et les tentatives de lateral movement.

Phase 4 — Continuous Verification (mois 6+) : Les sessions sont réévaluées en continu, pas seulement à l’authentification initiale. Un device qui perd sa compliance voit ses tokens révoqués en temps réel.

🔥 Cas réel : Quand Shopify a migré vers le Zero Trust, ils ont commencé par un inventaire complet des flux de communication entre services (Phase 0 souvent oubliée). Ils ont découvert que 40% des connexions réseau internes étaient inattendues — des services qui communiquaient sans raison documentée. Cette cartographie seule a permis de réduire la surface d’attaque avant même d’activer le mTLS.

Bonnes pratiques et pièges à éviter

Ne confonds pas Zero Trust et “zéro accès”. L’objectif est un accès sécurisé et vérifié, pas un blocage total. Si tes développeurs passent 30 minutes à se battre avec les policies pour déployer, tu as un problème d’implémentation, pas de philosophie.

Méfie-toi du “Zero Trust washing”. Beaucoup de vendeurs collent l’étiquette Zero Trust sur des produits qui sont juste des firewalls ou des VPNs rebrandés. Le vrai test : est-ce que le produit vérifie l’identité à chaque requête ? Est-ce qu’il applique le least privilege ? Est-ce qu’il assume breach ?

Commence par la cartographie des flux. Avant de déployer quoi que ce soit, lance un linkerd viz tap ou un istioctl analyze pour comprendre qui parle à qui. Tu ne peux pas sécuriser ce que tu ne connais pas.

Le NIST SP 800-207 est ta référence. Ce document formalise les 7 principes du Zero Trust et les trois modèles de déploiement (Enhanced Identity Governance, Micro-Segmentation, Software Defined Perimeter). C’est la bible — lis-la.

Résumé — Ce qu’il faut retenir

🧠 À retenir :

  • Le mTLS authentifie les deux parties de chaque communication — c’est le standard pour le trafic service-to-service en Zero Trust
  • SPIFFE/SPIRE automatise la gestion des identités et des certificats pour les workloads — plus de certificats manuels
  • Un service mesh (Istio ou Linkerd) rend le mTLS et les authorization policies transparents pour les développeurs — pas de changement de code
  • Linkerd pour la simplicité, Istio pour la puissance — choisis en fonction de la taille de ton équipe
  • Tailscale remplace le VPN traditionnel avec du WireGuard mesh peer-to-peer et des ACLs granulaires — idéal pour les accès humain-vers-machine
  • L’implémentation est progressive : identité → réseau → observabilité → continuous verification
  • Cartographie tes flux avant de sécuriser quoi que ce soit — tu ne peux pas protéger ce que tu ne connais pas

🖥️ Pratique sur ton propre serveur

Pour suivre Sécurité Cloud en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés