Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Modernizzare l'accesso alle applicazioni GKE interne: dalla VPN al Gateway esterno con IAP

By Nir ForerJan 13, 20256 min read

Questa pagina è disponibile anche in English, Deutsch, Español, Français, 日本語 e Português.

Lasci da parte la VPN e adotti una moderna soluzione Zero Trust per le applicazioni HTTPS interne

Sta ancora gestendo connessioni VPN per consentire al personale remoto di accedere alle applicazioni interne ospitate su GKE (Google Kubernetes Engine)? C'è un modo migliore. In questo articolo vedremo come sostituire il classico accesso via VPN con Identity-Aware Proxy (IAP) di Google Cloud, sfruttando il GKE External Gateway. Un approccio moderno che non solo riduce l'overhead operativo, ma offre anche un controllo degli accessi più granulare grazie ad autenticazione e autorizzazione basate su IAM.

Perché cambiare?

L'accesso tradizionale alle applicazioni interne tramite VPN porta con sé diverse criticità:

  • Elevato overhead operativo per la gestione dei tunnel VPN
  • Costi aggiuntivi per l'infrastruttura VPN
  • Configurazioni di routing di rete complesse
  • Controllo degli accessi poco granulare

Adottando un External Gateway con IAP è invece possibile:

  • Consolidare più applicazioni dietro un unico load balancer HTTPS
  • Gestire in modo efficiente gli accessi tra namespace GKE diversi
  • Sfruttare il solido sistema di autenticazione di Google Cloud
  • Ridurre costi e complessità dell'infrastruttura

GKE Ingress vs Gateway: a confronto sull'implementazione di IAP

Per implementare IAP con GKE esistono due strade principali: GKE Ingress oppure GKE Gateway. Capirne le differenze è fondamentale per scegliere la soluzione più adatta al proprio ambiente.

I limiti di GKE Ingress

  • Vincoli sui namespace: GKE Ingress può fare riferimento solo a Service presenti nello stesso namespace in cui è distribuita la risorsa Ingress:

Una GKE Ingress nel namespace Fu non può fare riferimento a un Service nel namespace Bar

  • Risorse Load Balancer: possono servire più load balancer se le applicazioni sono distribuite su namespace diversi:

Quando i servizi si trovano in namespace diversi servono 2 HTTPS LB distinti — e occorre anche il routing su base dominio, che aggiunge un ulteriore livello di complessità

I vantaggi di GKE Gateway

  • Supporto cross-namespace: un'unica risorsa Gateway può instradare il traffico verso Service in namespace diversi
  • Architettura semplificata: un solo load balancer gestisce più applicazioni a prescindere dal namespace
  • Routing più flessibile: è più semplice realizzare pattern di routing complessi tra namespace

Una GKE Gateway in un namespace può inviare traffico a Service in altri namespace tramite un unico HTTPS LB

Guida all'implementazione

Prerequisiti

  • GKE Standard v1.24+ oppure GKE Autopilot v1.26+
  • Cluster configurato in modalità VPC-native
  • Add-on HttpLoadBalancing abilitato

Passo 1: creare il 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

Passo 2: configurare il certificato 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

Passo 3: configurare un IP esterno e creare un record DNS A che punti a tale IP

Per ottenere il provisioning del ManagedCertificate è necessario avere un record DNS A che punti all'HTTPS LB e avere il certificato collegato all'HTTPS LB stesso (operazione che gestiremo nel passo successivo)

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

Passo 4: distribuire la risorsa Gateway

Si noti che gatewayClassName rappresenta un HTTPS LB esterno globale e che l'array dei listener consente l'attacco di HTTPRoute da qualsiasi namespace. Notiamo inoltre che impostiamo l'IP riservato indicando in addresses[0].type il valore NamedAddresses e come valore il nome usato in fase di prenotazione dell'IP statico ("gateway" in questo esempio):

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

# Verify Gateway IP assignment
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

Passo 5: verificare lo stato del ManagedCertificate

# Verify certificate status
while true; do
 STATUS=$(kubectl get managedcertificate gateway-nir-dns-tests-google-com -o=jsonpath="{.status.certificateStatus}")
 if [ "$STATUS" = "Active" ]; then
   break
 fi
 echo "Certificate is in $STATUS status, will check again if it became active in 3 seconds"
 sleep 3
done

Passo 6: distribuire le applicazioni di esempio

kubectl create namespace first-namespace
kubectl create namespace second-namespace

# Deploy App A in 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

# Create Service for 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

# Deploy App B in 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

# Create Service for 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

Passo 7: abilitare IAP e creare un Secret k8s per le credenziali IAP

echo -n CLIENT_SECRET_REDACTED > iap-secret.txt
kubectl create secret generic iap --from-file=key=iap-secret.txt

Passo 8: creare la GCPBackendPolicy che applica IAP

# Enable IAP for 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

# Enable IAP for 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

Passo 9: creare l'HTTPRoute

# Create route for 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

# Create route for 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

Passo 10: accedere alle applicazioni protette da IAP

Apra l'URL protetto da IAP. Verrà mostrata la pagina di accesso di Google. Potrà accedere all'applicazione qualsiasi utente che appartenga alla stessa organizzazione Google Cloud in cui è distribuita l'applicazione e a cui sia assegnato il ruolo IAM IAP-Secured Web App User:

[email protected] è un utente dell'organizzazione GCP doit.com e dispone delle autorizzazioni IAM necessarie per accedere all'applicazione. [email protected] non appartiene a tale organizzazione e quindi non potrà accedere all'applicazione

Quando un utente esterno all'organizzazione, oppure un utente privo delle autorizzazioni richieste, prova ad accedere all'applicazione, viene mostrata una pagina di accesso negato:

La pagina di accesso negato mostrata ai principal non autorizzati

Modernizzare le modalità di accesso a GKE passando dalla VPN a un External Gateway con IAP è solo uno dei tanti modi per rafforzare la sicurezza e l'efficienza operativa della propria infrastruttura Google Cloud. Un approccio che non solo migliora la postura di sicurezza, ma riduce anche overhead operativo e costi.

Questa guida si concentra sulla modernizzazione dell'accesso a GKE, ma analoghe opportunità di trasformazione esistono in tutta la sua infrastruttura cloud. Dall'ottimizzazione dei costi all'automazione dell'infrastruttura, dall'hardening della sicurezza al design dell'architettura cloud, DoiT International mette a disposizione una competenza estesa su numerosi ambiti del cloud. Per scoprire come DoiT può aiutarla a modernizzare altri aspetti della sua infrastruttura cloud o per conoscere le nostre soluzioni di cloud engineering, visiti doit.com/expertise/.