Aposente a VPN e adote uma solução Zero Trust moderna para aplicações HTTPS internas
Você ainda gerencia conexões VPN para que seu time remoto acesse aplicações internas no GKE (Google Kubernetes Engine)? Existe um caminho melhor. Neste post, vamos mostrar como trocar o acesso tradicional via VPN pelo Identity-Aware Proxy (IAP) do Google Cloud usando o GKE External Gateway. Essa abordagem moderna reduz o esforço operacional e ainda oferece um controle de acesso muito mais granular, com autenticação e autorização via IAM.
Por que fazer a troca?
O acesso tradicional via VPN a aplicações internas traz uma série de desafios:
- Alto esforço operacional para gerenciar túneis VPN
- Custos extras com infraestrutura de VPN
- Configurações de roteamento de rede complexas
- Controle de acesso pouco granular
Ao implementar um External Gateway com IAP habilitado, você consegue:
- Consolidar várias aplicações atrás de um único load balancer HTTPS
- Gerenciar o acesso entre diferentes namespaces do GKE com eficiência
- Aproveitar o robusto sistema de autenticação do Google Cloud
- Reduzir custos e complexidade da infraestrutura
GKE Ingress vs. Gateway: comparativo na implementação do IAP
Ao implementar o IAP com o GKE, você tem duas abordagens principais: usar o GKE Ingress ou o GKE Gateway. Entender as diferenças entre eles é fundamental para escolher a solução certa para o seu ambiente.
Limitações do GKE Ingress
- Restrições de namespace: o GKE Ingress só consegue referenciar Services dentro do mesmo namespace em que o recurso Ingress está implantado:

Um GKE Ingress no namespace Fu não consegue referenciar um Service no namespace Bar
- Recursos de load balancer: pode ser necessário usar vários load balancers se as aplicações estiverem em namespaces diferentes:

É preciso usar 2 load balancers HTTPS diferentes quando os Services estão em namespaces distintos — e ainda recorrer ao roteamento por domínio, o que adiciona mais uma camada de complexidade
Vantagens do GKE Gateway
- Suporte entre namespaces: roteia tráfego para Services em diferentes namespaces a partir de um único recurso Gateway
- Arquitetura simplificada: um único load balancer atende várias aplicações, independentemente do namespace
- Roteamento mais flexível: facilita a implementação de padrões de roteamento complexos entre namespaces

Um GKE Gateway em um namespace consegue enviar tráfego para Services em outros namespaces usando um único load balancer HTTPS
Guia de implementação
Pré-requisitos
- GKE Standard v1.24+ ou GKE Autopilot v1.26+
- Cluster configurado como VPC-native
- Add-on HttpLoadBalancing habilitado
Passo 1: criar o 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: configurar o certificado 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: configurar o IP externo e apontar um registro DNS A para esse IP
Para que o ManagedCertificate seja provisionado, você precisa ter um registro DNS A apontando para o load balancer HTTPS e o certificado anexado a esse load balancer (o que será feito no próximo passo)
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: implantar o recurso Gateway
Repare que o gatewayClassName representa um load balancer HTTPS Global External e que o array de listeners libera HTTPRoutes vindos de qualquer namespace. Note também que estamos definindo o IP reservado com addresses[0].type como NamedAddresses e o valor sendo o nome usado ao reservar o IP estático ("gateway" neste exemplo):
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
# Verifica a atribuição do IP do 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
Passo 5: verificar o status do ManagedCertificate
# Verifica o status do certificado
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: implantar aplicações de exemplo
kubectl create namespace first-namespace
kubectl create namespace second-namespace
# Implanta o App A no 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
# Cria o Service do 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
# Implanta o App B no 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
# Cria o Service do 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: habilitar o IAP e criar um Secret no k8s para as credenciais do IAP
echo -n CLIENT_SECRET_REDACTED > iap-secret.txt
kubectl create secret generic iap --from-file=key=iap-secret.txt
Passo 8: criar uma GCPBackendPolicy que aplique o IAP
# Habilita o IAP para o 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
# Habilita o IAP para o 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: criar a HTTPRoute
# Cria a rota para o 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
# Cria a rota para o 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: acessar as aplicações protegidas pelo IAP
Acesse a URL protegida pelo IAP. A página de login do Google será exibida. Qualquer usuário que pertença à mesma organização do Google Cloud em que a aplicação está implantada e que tenha a permissão IAM IAP-Secured Web App User conseguirá acessar a aplicação:

[email protected] é um usuário da organização GCP doit.com e tem as permissões IAM necessárias para acessar a aplicação. Já [email protected] não pertence a essa organização e, portanto, não conseguirá acessar a aplicação
Quando um usuário fora da organização ou alguém sem as permissões necessárias tenta fazer login e acessar a aplicação, ele se depara com uma página de permissão negada:

Página de permissão negada exibida para principals não autorizados
Modernizar os padrões de acesso ao GKE, saindo da VPN para um External Gateway com IAP, é só uma das muitas formas de elevar a segurança e a eficiência operacional da sua infraestrutura no Google Cloud. Essa abordagem fortalece a postura de segurança e, ao mesmo tempo, reduz o esforço operacional e os custos.
Embora este guia foque na modernização do acesso ao GKE, oportunidades parecidas de transformação existem em toda a sua infraestrutura na nuvem. Da otimização de custos à automação de infraestrutura, do reforço da segurança ao design de arquitetura na nuvem, a DoiT International reúne expertise abrangente em diversos domínios de cloud. Para descobrir como a DoiT pode ajudar a modernizar outros aspectos da sua infraestrutura na nuvem ou conhecer nossas demais soluções de engenharia em cloud, acesse doit.com/expertise/.