Pourquoi votre VPN est une faille de sécurité : l'accès réseau Zero-Trust dans le SaaS moderne
Zero-Trust Network Access in Modern SaaS: Tear Down Your VPNs
Nous devons parler de votre sécurité périmétrique. Si vous comptez toujours sur un réseau privé virtuel (VPN) traditionnel pour sécuriser vos services internes en 2026, vous créez une faille de sécurité. Le modèle classique du « château fort et des douves » est mort. Dès qu'un attaquant franchit les douves, il bénéficie d'un mouvement latéral sans restriction sur l'ensemble de votre réseau interne. C'est inacceptable pour les environnements SaaS (Software as a Service) modernes.
La seule voie viable est l'accès réseau Zero-Trust (Zero-Trust Network Access - ZTNA). Dans un modèle Zero-Trust, le réseau lui-même est considéré comme hostile. Chaque requête, qu'elle provienne d'un travailleur à distance dans un café ou d'un microservice au sein de votre propre cluster Kubernetes, doit être explicitement authentifiée, autorisée et validée en continu.
Cet article détaille le problème des périmètres traditionnels, le changement d'architecture requis pour le ZTNA et une stratégie de mise en œuvre concrète à l'aide de proxys modernes basés sur l'identité.
Le problème : la sécurité périmétrique est une illusion
La sécurité réseau traditionnelle repose sur les adresses IP et les limites du réseau. Vous placez un pare-feu à la périphérie de votre infrastructure et une passerelle VPN pour l'accès à distance. Une fois qu'un utilisateur s'authentifie sur le VPN, une adresse IP interne lui est attribuée et il obtient un accès large au réseau local (LAN) de l'entreprise.
Cette architecture présente trois failles majeures :
- Confiance implicite : Le système fait implicitement confiance à toute entité opérant depuis une adresse IP interne. Si l'ordinateur portable d'un développeur est compromis, l'attaquant dispose d'un tunnel direct vers votre environnement de production.
- Manque de granularité : Les VPN fonctionnent au niveau de la couche OSI 3 ou 4. Ils accordent l'accès à des segments de réseau entiers (sous-réseaux), et non à des applications individuelles. Vous ne pouvez pas facilement dire : « Alice peut accéder au tableau de bord des métriques internes, mais pas à l'API de facturation », sans gérer un labyrinthe de règles ACL réseau complexes.
- Mauvaise expérience utilisateur : Acheminer tout le trafic via une passerelle VPN centrale introduit une latence importante et des goulets d'étranglement de bande passante.
Vous sécurisez le mauvais élément. Vous sécurisez le réseau, alors que vous devriez sécuriser l'application.
Pourquoi c'est difficile : la complexité de l'accès basé sur l'identité
Si l'accès réseau Zero-Trust est si supérieur, pourquoi tout le monde ne l'adopte-t-il pas ? Parce que passer d'une sécurité centrée sur le réseau à une sécurité centrée sur l'identité est difficile sur le plan conceptuel et opérationnel.
Cela nécessite d'abandonner les adresses IP comme unité de confiance et de les remplacer par une identité et un contexte cryptographiques.
Voici ce qui rend cette transition difficile :
- Fédération d'identité : Vous devez centraliser la gestion des identités. Chaque application doit s'intégrer à votre fournisseur d'identité (IdP - Identity Provider) - généralement Google Workspace, Okta ou Azure AD. Adapter d'anciens outils internes qui ne prennent en charge que la Basic Auth ou aucune authentification est un véritable casse-tête.
- Gestion des politiques d'accès : Dans un monde avec VPN, l'accès est binaire : vous êtes sur le réseau ou vous ne l'êtes pas. Dans un monde ZTNA, les politiques d'accès sont très granulaires et contextuelles. Vous devez définir des règles basées sur le rôle de l'utilisateur, l'état de sécurité du terminal (est-ce un appareil géré par l'entreprise ? le chiffrement du disque est-il activé ?), l'heure de la journée et la sensibilité de l'application.
- Performances et latence : Chaque requête doit être interceptée, authentifiée et autorisée. Si votre proxy basé sur l'identité est lent, c'est l'ensemble de votre suite d'applications qui ralentira.
Malgré ces défis, la transition est indispensable. Un périmètre compromis est une question de « quand », pas de « si ».
Architecture : le plan directeur de l'accès réseau Zero-Trust
Une architecture d'accès réseau Zero-Trust robuste dans un environnement SaaS remplace la passerelle VPN par un proxy basé sur l'identité (IAP - Identity-Aware Proxy). Le proxy se place directement devant vos applications internes et sert d'intermédiaire pour chaque requête HTTP.
Les composants clés de cette architecture sont :
- Fournisseur d'identité (IdP) : La source de vérité pour les identités des utilisateurs et les appartenances aux groupes (par exemple, Okta).
- Fournisseur de confiance des terminaux (Device Trust Provider) : Un système qui évalue l'état de santé et de sécurité des terminaux (par exemple, CrowdStrike, Kolide).
- Moteur de politiques (Policy Engine) : Un service centralisé qui stocke et évalue les règles d'accès.
- Proxy basé sur l'identité (IAP) : Le point d'application des règles. Il intercepte les requêtes, consulte le moteur de politiques et transmet la requête à l'application en amont ou la rejette.
Le flux de requêtes
Lorsqu'un développeur tente d'accéder à un service interne (par exemple, metrics.internal.yourcompany.com), le flux suivant se produit :
- Le DNS de l'utilisateur résout le nom d'hôte vers l'IP publique du proxy basé sur l'identité.
- Le navigateur de l'utilisateur initie une connexion TLS vers le proxy.
- Le proxy vérifie la présence d'un cookie de session cryptographique valide. Si aucun n'existe, il redirige l'utilisateur vers l'IdP via OpenID Connect (OIDC).
- L'utilisateur s'authentifie auprès de l'IdP (nécessitant une authentification multifacteur (MFA) résistante au phishing, comme une clé YubiKey).
- L'IdP redirige l'utilisateur vers le proxy avec un jeton d'identité.
- Le proxy transmet l'identité de l'utilisateur, le contexte de l'appareil et l'URL demandée au moteur de politiques.
- Le moteur de politiques évalue la requête par rapport aux règles définies (par exemple : « Seuls les ingénieurs sur des appareils appartenant à l'entreprise peuvent accéder aux métriques »).
- S'il est autorisé, le proxy transmet la requête à l'application en amont. Crucialement, le proxy injecte une assertion (souvent un JWT signé) dans les en-têtes de la requête.
- L'application en amont valide le JWT pour s'assurer que la requête provient bien du proxy de confiance, et non d'un processus malveillant au sein du cluster.
Cette architecture fournit une vérification continue au niveau de la couche 7 (Layer 7).
Mise en œuvre : créer un ZTNA avec Pomerium et Kubernetes
Examinons une mise en œuvre concrète. Nous utiliserons Pomerium comme proxy basé sur l'identité, en le déployant sur un cluster Kubernetes (v1.29+). Pomerium est un excellent choix car il est open-source, extrêmement rapide et s'intègre nativement avec les IdP standards.
Nous supposons que vous avez un cluster Kubernetes opérationnel et un service que vous souhaitez exposer de manière sécurisée, comme un tableau de bord Grafana.
Étape 1 : Déployer Pomerium
Tout d'abord, nous devons configurer Pomerium pour se connecter à notre IdP. Nous utilisons un chart Helm standard. Voici un exemple de configuration values.yaml pour Pomerium, lié à Google Workspace.
# pomerium-values.yaml
authenticate:
idp:
provider: google
clientID: "YOUR_GOOGLE_CLIENT_ID"
clientSecret: "YOUR_GOOGLE_CLIENT_SECRET"
serviceAccount: "base64_encoded_service_account_json"
ingress:
enabled: true
className: "nginx"
hosts:
- authenticate.internal.yourcompany.com
tls:
- secretName: pomerium-tls
hosts:
- authenticate.internal.yourcompany.com
config:
# The shared secret for communication between Pomerium components
sharedSecret: "generate_a_random_base64_string_here"
cookieSecret: "generate_another_random_base64_string_here"
Appliquez le helm chart :
helm repo add pomerium https://helm.pomerium.io
helm install pomerium pomerium/pomerium -f pomerium-values.yaml --namespace pomerium --create-namespace
Étape 2 : Définir les politiques d'accès
Nous devons maintenant sécuriser notre instance Grafana. Pour ce faire, nous définissons une ressource Ingress avec des annotations spécifiques que Pomerium comprend. Au lieu d'une Ingress Kubernetes standard, nous utiliserons la Custom Resource Definition (CRD) de Pomerium, PomeriumRoute.
C'est là que réside toute la puissance du ZTNA. Nous définissons la politique d'accès sous forme de code, directement aux côtés du déploiement de notre application.
# grafana-route.yaml
apiVersion: ingress.pomerium.io/v1
kind: PomeriumRoute
metadata:
name: grafana-secure-route
namespace: monitoring
spec:
from: https://metrics.internal.yourcompany.com
to: http://grafana.monitoring.svc.cluster.local:80
policy:
- allow:
and:
- domain:
is: yourcompany.com
- claim/groups:
has: "engineering-team@yourcompany.com"
Cette configuration indique : Autoriser l'accès à https://metrics.internal.yourcompany.com UNIQUEMENT SI l'utilisateur s'authentifie avec une adresse e-mail @yourcompany.com ET s'il est membre du groupe engineering-team.
Appliquez la route :
kubectl apply -f grafana-route.yaml
Étape 3 : Validation en amont (l'étape critique)
Si vous vous arrêtez à l'étape 2, vous laissez une vulnérabilité. Que se passe-t-il si un attaquant compromet un pod à l'intérieur de votre cluster Kubernetes ? Il pourrait contourner complètement Pomerium et envoyer des requêtes directement à http://grafana.monitoring.svc.cluster.local:80.
Pour obtenir un accès réseau Zero-Trust complet, l'application en amont (Grafana) doit vérifier que chaque requête est passée par Pomerium.
Pomerium injecte un en-tête X-Pomerium-Jwt-Assertion dans chaque requête qu'il relaie. Ce JWT est signé par la clé privée de Pomerium.
Votre application doit valider ce JWT. Si vous construisez des microservices Go personnalisés (par exemple, en utilisant Go 1.22), vous implémentez un middleware pour effectuer cette vérification.
package main
import (
"context"
"crypto/rsa"
"fmt"
"net/http"
"strings"
"github.com/golang-jwt/jwt/v5"
"github.com/lestrrat-go/jwx/v2/jwk"
)
// JWKS URL for Pomerium
const pomeriumJWKSURL = "https://authenticate.internal.yourcompany.com/.well-known/pomerium/jwks.json"
func requirePomeriumAssertion(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assertion := r.Header.Get("X-Pomerium-Jwt-Assertion")
if assertion == "" {
http.Error(w, "Missing Pomerium Assertion", http.StatusUnauthorized)
return
}
// Fetch and cache the public keys from Pomerium
ctx := context.Background()
set, err := jwk.Fetch(ctx, pomeriumJWKSURL)
if err != nil {
http.Error(w, "Failed to fetch keys", http.StatusInternalServerError)
return
}
// Parse and validate the JWT
token, err := jwt.Parse(assertion, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodES256); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
kid, ok := token.Header["kid"].(string)
if !ok {
return nil, fmt.Errorf("missing kid header")
}
key, ok := set.LookupKeyID(kid)
if !ok {
return nil, fmt.Errorf("key %v not found", kid)
}
var rawKey interface{}
if err := key.Raw(&rawKey); err != nil {
return nil, err
}
return rawKey, nil
})
if err != nil || !token.Valid {
http.Error(w, "Invalid Assertion", http.StatusForbidden)
return
}
// Proceed to the application
next.ServeHTTP(w, r)
})
}
En appliquant la validation du JWT au niveau de la couche applicative, les limites du réseau deviennent obsolètes. Même si un attaquant se trouve sur le même sous-réseau, il ne peut pas contourner les contrôles d'autorisation.
Pièges : pourquoi les déploiements ZTNA échouent
Déployer un proxy basé sur l'identité est simple. En revanche, faire basculer une organisation vers un modèle Zero-Trust est difficile. Voici les cas d'échecs les plus courants.
1. Ignorer les applications existantes (legacy)
Les applications SaaS modernes communiquent en HTTP et comprennent nativement OAuth ou OIDC. Les outils internes plus anciens ne le font souvent pas. Ils peuvent dépendre d'adresses IP codées en dur ou d'une authentification de base (basic authentication).
N'essayez pas de réécrire ces applications immédiatement. Utilisez plutôt votre proxy pour injecter des en-têtes ou effectuer une traduction d'authentification de base. Si une application utilise un protocole non-HTTP (comme SSH ou RDP), vous aurez besoin d'un proxy prenant en charge le tunneling (Pomerium et Teleport gèrent tous deux très bien cela).
2. L'anti-pattern du « bouton d'arrêt d'urgence » (Break Glass)
Les équipes mettent souvent en place des politiques ZTNA strictes, mais conservent un VPN de secours « au cas où » le fournisseur d'identité tomberait en panne. Cela va à l'encontre de l'objectif recherché car les attaquants finiront par trouver ce VPN.
Au lieu d'un réseau parallèle non sécurisé, concevez votre architecture ZTNA pour une haute disponibilité. Utilisez des IdP redondants ou assurez-vous que votre proxy peut mettre en cache les décisions de politique d'accès et les clés cryptographiques pour surmonter de brèves pannes d'IdP.
3. La fatigue des alertes (Alert Fatigue)
Une architecture Zero-Trust génère un volume immense de journaux (logs). Chaque requête représente un événement d'autorisation. Si vous déversez tous ces journaux dans un SIEM sans filtrage ni corrélation stricts, votre équipe de sécurité sera submergée par la fatigue des alertes.
Concentrez-vous sur l'enregistrement des requêtes refusées provenant d'appareils connus de l'entreprise, ou sur les scénarios de déplacement géographique impossibles dans vos journaux d'identité.
Résultat : un SaaS moderne et résilient
Passer à un accès réseau Zero-Trust est un investissement technique important. Cela exige de former les équipes, de mettre à jour l'infrastructure et d'adopter de nouvelles mentalités opérationnelles.
Mais le résultat est une organisation fondamentalement plus résiliente.
Lorsque vous éliminez le VPN, vous éliminez le concept de réseaux internes par rapport aux réseaux externes. Vous accordez l'accès sur la base de l'identité et du contexte, et non des adresses IP. Vous bénéficiez d'une visibilité microscopique sur qui accède à quoi, et quand.
Plus important encore, vous réduisez considérablement le rayon d'impact (blast radius) d'un terminal compromis. Dans un monde basé sur la sécurité périmétrique, le vol de l'ordinateur portable d'un développeur est une violation catastrophique. Dans un monde Zero-Trust, il s'agit d'un incident contenu.
Abattez vos douves. Sécurisez vos applications. Commencez à concevoir une architecture Zero-Trust dès aujourd'hui.
Service Seven Labs
Tests de Pénétration VAPT & Cybersécurité
