Abandonner le VPN au profit d'une solution Zero Trust moderne pour les applications HTTPS internes
Vous gérez encore des connexions VPN pour permettre à vos équipes distantes d'accéder à vos applications internes GKE (Google Kubernetes Engine) ? Il existe une meilleure approche. Dans cet article, nous verrons comment remplacer l'accès VPN traditionnel par l'Identity-Aware Proxy (IAP) de Google Cloud, via le GKE External Gateway. Cette approche moderne réduit la charge opérationnelle tout en offrant un contrôle d'accès plus fin grâce à l'authentification et à l'autorisation IAM.
Pourquoi franchir le pas ?
L'accès VPN traditionnel aux applications internes présente plusieurs limites :
- Charge opérationnelle élevée pour gérer les tunnels VPN
- Coûts supplémentaires liés à l'infrastructure VPN
- Configurations de routage réseau complexes
- Contrôle d'accès granulaire limité
En déployant un External Gateway avec IAP, vous pouvez :
- Regrouper plusieurs applications derrière un seul load balancer HTTPS
- Gérer efficacement les accès entre différents namespaces GKE
- Tirer parti du système d'authentification robuste de Google Cloud
- Réduire les coûts et la complexité de l'infrastructure
GKE Ingress ou Gateway : comparaison de l'implémentation IAP
Pour mettre en place IAP avec GKE, deux approches principales s'offrent à vous : GKE Ingress ou GKE Gateway. Bien comprendre leurs différences est essentiel pour choisir la solution adaptée à votre environnement.
Limites de GKE Ingress
- Restrictions de namespace : GKE Ingress ne peut référencer que les Services présents dans le même namespace que la ressource Ingress :

Un GKE Ingress dans le namespace Fu ne peut pas référencer un Service dans le namespace Bar
- Ressources de load balancer : plusieurs load balancers peuvent être nécessaires si les applications sont réparties sur différents namespaces :

Deux LB HTTPS distincts sont indispensables lorsque les services sont répartis sur des namespaces différents — il faut alors recourir à un routage par domaine, ce qui ajoute une couche de complexité supplémentaire
Atouts de GKE Gateway
- Prise en charge cross-namespace : route le trafic vers des Services situés dans différents namespaces depuis une seule ressource Gateway
- Architecture simplifiée : un seul load balancer prend en charge plusieurs applications, quel que soit leur namespace
- Routage plus souple : facilite la mise en œuvre de schémas de routage complexes entre namespaces

Un GKE Gateway dans un namespace peut acheminer le trafic vers des Services d'autres namespaces via un seul LB HTTPS
Guide d'implémentation
Prérequis
- GKE Standard v1.24+ ou GKE Autopilot v1.26+
- Cluster en configuration VPC-native
- Add-on HttpLoadBalancing activé
Étape 1 : créer le cluster GKE
gcloud container clusters create test-gateway \
--region=us-central1 \
--release-channel=regular \
--enable-ip-alias \
--num-nodes=1 \
--addons HttpLoadBalancing \
--gateway-api=standard
gcloud container clusters get-credentials test-gateway --region us-central1
Étape 2 : configurer le certificat SSL
cat <<EOF | kubectl apply -f -
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
name: gateway-nir-dns-tests-google-com
namespace: default
spec:
domains:
- gateway.nir-dns-tests-google-com
EOF
Étape 3 : configurer l'IP externe et faire pointer un enregistrement DNS A vers cette IP
Pour que le ManagedCertificate soit provisionné, vous devez disposer d'un enregistrement DNS A pointant vers le LB HTTPS et avoir attaché le certificat à ce LB HTTPS (ce qui sera fait à l'étape suivante)
gcloud compute addresses create gateway --project=nir-playground --global
RESERVED_IP=$(gcloud compute addresses describe gateway --global | grep address: | awk '{print $2}')
gcloud dns --project=nir-playground record-sets create gateway.nir-dns-tests-google-com. \
--zone="nir-dns-tests-google-com" --type="A" --ttl="60" --rrdatas=$RESERVED_IP
Étape 4 : déployer la ressource Gateway
À noter : gatewayClassName correspond à un LB HTTPS Global External, et le tableau listeners autorise le rattachement de HTTPRoutes depuis n'importe quel namespace. Notez également que l'IP réservée est définie via addresses[0].type à la valeur NamedAddresses, dont la valeur reprend le nom utilisé lors de la réservation de l'IP statique (gateway dans cet exemple) :
CERT_NAME=$(kubectl get managedcertificate gateway-nir-dns-tests-google-com -o=jsonpath="{.status.certificateName}")
cat <<EOF | kubectl apply -f -
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: external-http
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
options:
networking.gke.io/pre-shared-certs: $CERT_NAME
addresses:
- type: NamedAddress
value: gateway
EOF
# Vérifier l'attribution de l'IP du Gateway
while true; do
GATEWAY_IP=$(kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}")
if [ "$GATEWAY_IP" != "" ]; then
break
fi
sleep 3
done
Étape 5 : vérifier le statut du ManagedCertificate
# Vérifier le statut du certificat
while true; do
STATUS=$(kubectl get managedcertificate gateway-nir-dns-tests-google-com -o=jsonpath="{.status.certificateStatus}")
if [ "$STATUS" = "Active" ]; then
break
fi
echo "Le certificat est au statut $STATUS, nouvelle vérification dans 3 secondes"
sleep 3
done
Étape 6 : déployer les applications de démonstration
kubectl create namespace first-namespace
kubectl create namespace second-namespace
# Déployer App A dans first-namespace
cat <<EOF | kubectl apply -n first-namespace -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-a
spec:
replicas: 2
selector:
matchLabels:
app: app-a
template:
metadata:
labels:
app: app-a
spec:
containers:
- name: app-a
image: hashicorp/http-echo
args: ["-text=Hello from App A"]
ports:
- containerPort: 5678
EOF
# Créer le Service pour App A
cat <<EOF | kubectl apply -n first-namespace -f -
apiVersion: v1
kind: Service
metadata:
name: service-a
spec:
selector:
app: app-a
ports:
- protocol: TCP
port: 80
targetPort: 5678
EOF
# Déployer App B dans second-namespace
cat <<EOF | kubectl apply -n second-namespace -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-b
spec:
replicas: 2
selector:
matchLabels:
app: app-b
template:
metadata:
labels:
app: app-b
spec:
containers:
- name: app-b
image: hashicorp/http-echo
args: ["-text=Hello from App B"]
ports:
- containerPort: 5678
EOF
# Créer le Service pour App B
cat <<EOF | kubectl apply -n second-namespace -f -
apiVersion: v1
kind: Service
metadata:
name: service-b
spec:
selector:
app: app-b
ports:
- protocol: TCP
port: 80
targetPort: 5678
EOF
Étape 7 : activer IAP et créer un Secret k8s pour les identifiants IAP
echo -n CLIENT_SECRET_REDACTED > iap-secret.txt
kubectl create secret generic iap --from-file=key=iap-secret.txt
Étape 8 : créer la GCPBackendPolicy qui applique IAP
# Activer IAP pour App A
cat <<EOF | kubectl apply -n first-namespace -f -
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: backend-policy
spec:
default:
iap:
enabled: true
oauth2ClientSecret:
name: iap
clientID: REPLACE_WITH_YOUR_IAP_OAUTH_CLIENT_ID
targetRef:
group: ""
kind: Service
name: service-a
EOF
# Activer IAP pour App B
cat <<EOF | kubectl apply -n second-namespace -f -
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: backend-policy
spec:
default:
iap:
enabled: true
oauth2ClientSecret:
name: iap
clientID: REPLACE_WITH_YOUR_IAP_OAUTH_CLIENT_ID
targetRef:
group: ""
kind: Service
name: service-b
EOF
Étape 9 : créer la HTTPRoute
# Créer la route pour App A
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: route-a
namespace: first-namespace
spec:
parentRefs:
- name: external-http
kind: Gateway
namespace: default
rules:
- matches:
- path:
value: /first
backendRefs:
- name: service-a
port: 80
EOF
# Créer la route pour App B
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: route-b
namespace: second-namespace
spec:
parentRefs:
- name: external-http
kind: Gateway
namespace: default
rules:
- matches:
- path:
value: /second
backendRefs:
- name: service-b
port: 80
EOF
Étape 10 : accéder aux applications protégées par IAP
Rendez-vous sur l'URL protégée par IAP. La page de connexion Google s'affiche. Tout utilisateur appartenant à la même organisation Google Cloud que celle où l'application est déployée et disposant des permissions IAM IAP-Secured Web App User pourra accéder à l'application :

[email protected] est un utilisateur de l'organisation GCP doit.com et dispose des permissions IAM requises pour accéder à l'application. [email protected] n'appartient pas à cette organisation et ne pourra donc pas y accéder
Lorsqu'un utilisateur extérieur à l'organisation, ou un utilisateur sans les permissions adéquates, tente de se connecter à l'application, une page de refus d'accès s'affiche :

Page de refus d'accès affichée pour les utilisateurs non autorisés
Moderniser vos schémas d'accès GKE en passant du VPN à un External Gateway avec IAP n'est qu'une des nombreuses manières de renforcer la sécurité et l'efficacité opérationnelle de votre infrastructure Google Cloud. Cette approche améliore votre posture de sécurité tout en réduisant la charge opérationnelle et les coûts.
Bien que ce guide se concentre sur la modernisation de l'accès à GKE, des opportunités de transformation similaires existent dans l'ensemble de votre infrastructure cloud. De l'optimisation des coûts à l'automatisation de l'infrastructure, en passant par le renforcement de la sécurité et la conception d'architectures cloud, DoiT International met à votre disposition une expertise étendue couvrant de nombreux domaines du cloud. Pour découvrir comment DoiT peut vous aider à moderniser d'autres pans de votre infrastructure cloud ou en savoir plus sur nos solutions de cloud engineering, rendez-vous sur doit.com/expertise/.