<h2>GKE Autopilot: Gerenciamento Automático de Clusters Kubernetes</h2>
<p>O Google Kubernetes Engine (GKE) Autopilot é um modo operacional que abstrai completamente a complexidade da gerência de nós Kubernetes. Diferentemente do modo Standard, onde você provisiona e gerencia nós manualmente, o Autopilot remove essa responsabilidade, permitindo que você se concentre apenas na implantação de workloads. O Google gerencia automaticamente o scaling, patches de segurança, atualizações e conformidade com boas práticas.</p>
<p>Quando você cria um cluster Autopilot, o GCP automaticamente configura grupos de nós gerenciados, aplica políticas de segurança, ativa logging e monitoramento, e ajusta recursos conforme a demanda das suas aplicações. Isso significa menos overhead operacional, menos erros de configuração e maior conformidade com padrões de segurança. Para aplicações em produção, especialmente aquelas onde a equipe é pequena ou não possui especialização profunda em Kubernetes, o Autopilot é uma escolha extremamente prática.</p>
<h3>Criando um Cluster Autopilot</h3>
<p>Para criar um cluster Autopilot via gcloud CLI, execute:</p>
<pre><code class="language-bash">gcloud container clusters create meu-cluster-autopilot \
--region us-central1 \
--enable-autopilot \
--enable-stackdriver-kubernetes \
--addons HttpLoadBalancing,HttpsLoadBalancing</code></pre>
<p>O comando acima cria um cluster gerenciado automaticamente na região us-central1. Os flags <code>--enable-stackdriver-kubernetes</code> e <code>--addons</code> ativam logging/monitoramento e controladores de ingress respectivamente. O Autopilot já vem com segurança em rede, RBAC (Role-Based Access Control) e Pod Security Standards habilitados por padrão.</p>
<h3>Diferenças Críticas em Relação ao GKE Standard</h3>
<p>No GKE Standard, você deve gerenciar Node Pools manualmente, decidir tipos de máquina, quantidades de nós e políticas de escalabilidade. O Autopilot decide isso automaticamente baseado nos requisitos de recursos dos seus Pods. Se um Pod necessita 2GB de memória e 0.5 CPUs, o Autopilot provisiona nós suficientes para acomodá-lo. Além disso, o Autopilot impõe restrições (como limites de recurso obrigatórios em containers) que forçam boas práticas desde o início.</p>
<p>---</p>
<h2>Workload Identity: Autenticação Segura para Aplicações</h2>
<p>O Workload Identity é um mecanismo de segurança que permite que containers rodando no GKE acessem APIs do Google Cloud (como Cloud SQL, Cloud Storage, Pub/Sub) sem armazenar credenciais (chaves JSON) dentro da imagem ou no filesystem do container. Funciona através de um mapeamento de confiança entre uma Service Account do Kubernetes (KSA) e uma Service Account do Google Cloud (GSA), usando tokens JWT gerados automaticamente.</p>
<p>Sem Workload Identity, você seria obrigado a injetar um arquivo de chave JSON na sua aplicação, o que aumenta significativamente o risco de vazamento de credenciais. Com Workload Identity, o controle é granular: você cria uma GSA com permissões específicas, mapeia uma KSA do Kubernetes para ela, e a aplicação automaticamente recebe um token de curta duração (com expiração de aproximadamente 1 hora). Esse modelo é mais seguro, mais fácil de auditar e elimina o risco de credenciais vazarem via repositórios Git.</p>
<h3>Configurando Workload Identity Passo a Passo</h3>
<p>Primeiro, certifique-se que o cluster tem Workload Identity habilitado. No Autopilot, isso vem ativado por padrão. Para verificar:</p>
<pre><code class="language-bash">gcloud container clusters describe meu-cluster-autopilot \
--region us-central1 \
--format='value(workloadIdentityConfig.workloadPool)'</code></pre>
<p>Você deve ver um output como <code>projeto-id.svc.id.goog</code>. Se não retornar nada, habilite com:</p>
<pre><code class="language-bash">gcloud container clusters update meu-cluster-autopilot \
--region us-central1 \
--workload-pool=SEU-PROJETO-ID.svc.id.goog</code></pre>
<p>Agora, crie uma Service Account do Google Cloud:</p>
<pre><code class="language-bash">gcloud iam service-accounts create minha-app-sa \
--display-name="Service Account da Minha App"</code></pre>
<p>Conceda permissões à GSA. Se sua aplicação precisa ler do Cloud SQL, por exemplo:</p>
<pre><code class="language-bash">gcloud projects add-iam-policy-binding SEU-PROJETO-ID \
--member="serviceAccount:minha-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"</code></pre>
<p>Crie uma Service Account do Kubernetes no seu namespace:</p>
<pre><code class="language-bash">kubectl create serviceaccount minha-app-ksa -n meu-namespace</code></pre>
<p>Estabeleça a relação de confiança entre KSA e GSA:</p>
<pre><code class="language-bash">gcloud iam service-accounts add-iam-policy-binding \
minha-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:SEU-PROJETO-ID.svc.id.goog[meu-namespace/minha-app-ksa]"</code></pre>
<p>Anotate a KSA com a email da GSA:</p>
<pre><code class="language-bash">kubectl annotate serviceaccount minha-app-ksa \
-n meu-namespace \
iam.gke.io/gcp-service-account=minha-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com</code></pre>
<h3>Exemplo Prático: Pod Acessando Cloud Storage</h3>
<p>Crie um Deployment que use a KSA anotada:</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-reader
namespace: meu-namespace
spec:
replicas: 1
selector:
matchLabels:
app: storage-reader
template:
metadata:
labels:
app: storage-reader
spec:
serviceAccountName: minha-app-ksa
containers:
- name: app
image: google/cloud-sdk:latest
command:
- /bin/bash
- -c
- |
gcloud auth application-default print-access-token
gsutil ls gs://meu-bucket
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"</code></pre>
<p>Quando esse Pod inicia, o Workload Identity injetor (um webhook do Kubernetes) automaticamente:</p>
<ol>
<li>Monta volumes contendo credenciais ephemeral</li>
<li>Configura variáveis de ambiente <code>GOOGLE_APPLICATION_CREDENTIALS</code> apontando para um arquivo de token</li>
<li>A aplicação usa <code>gcloud auth application-default</code> ou a biblioteca cliente Google Cloud, que automaticamente lê essas credenciais</li>
</ol>
<p>O resultado: sua aplicação acessa Cloud Storage sem nenhuma chave JSON armazenada.</p>
<p>---</p>
<h2>Cloud SQL Proxy: Conexão Segura e Simplificada ao Banco de Dados</h2>
<p>O Cloud SQL Proxy é um cliente que estabelece uma conexão segura (via SSL/TLS mutuo) com uma instância Cloud SQL, criptografando toda a comunicação. Em vez de sua aplicação conectar diretamente ao IP do banco (potencialmente exposto na rede), o Proxy atua como intermediário, gerenciando autenticação, criptografia e rotação de certificados automaticamente.</p>
<p>Quando executado dentro do GKE com Workload Identity, o Cloud SQL Proxy não necessita de credenciais explícitas. Ele usa o token JWT fornecido pelo Workload Identity para se autenticar com o Cloud SQL API e obter certificados válidos. Isso elimina completamente a necessidade de senhas de banco de dados ou chaves de conexão armazenadas.</p>
<h3>Implantando Cloud SQL Proxy no GKE</h3>
<p>Você tem duas opções: rodar o Proxy em um sidecar container dentro do Pod, ou usar um proxy gerenciado que o GCP fornece. Demonstrarei o sidecar, que é mais transparente para a aplicação.</p>
<p>Primeiro, certifique-se que sua GSA tem permissão para acessar Cloud SQL:</p>
<pre><code class="language-bash">gcloud projects add-iam-policy-binding SEU-PROJETO-ID \
--member="serviceAccount:minha-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"</code></pre>
<p>Agora, modifique o Deployment anterior para incluir o sidecar:</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
name: app-com-database
namespace: meu-namespace
spec:
replicas: 1
selector:
matchLabels:
app: app-com-database
template:
metadata:
labels:
app: app-com-database
spec:
serviceAccountName: minha-app-ksa
containers:
Container principal da aplicação
- name: app
image: python:3.11-slim
command:
- /bin/bash
- -c
- |
pip install psycopg2-binary
python -c "
import psycopg2
conn = psycopg2.connect(
host='127.0.0.1',
port=5432,
database='meudb',
user='postgres',
password='sua-senha'
)
cursor = conn.cursor()
cursor.execute('SELECT version();')
print(cursor.fetchone())
cursor.close()
conn.close()
"
env:
- name: PGPASSWORD
value: "sua-senha"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
Sidecar: Cloud SQL Proxy
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.6.0
args:
- "PROJETO-ID:REGIAO:NOME-INSTANCIA"
- "--port=5432"
- "--max-connections=5"
ports:
- name: postgres
containerPort: 5432
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL</code></pre>
<p>Neste exemplo, o sidecar Cloud SQL Proxy usa Workload Identity automaticamente (não requer variáveis de ambiente extras) porque o Pod está rodando sob a KSA anotada. O container principal da aplicação conecta em <code>localhost:5432</code>, e toda a criptografia e autenticação é gerenciada pelo Proxy.</p>
<h3>Alternativa: Cloud SQL Auth Proxy Gerenciado (Beta)</h3>
<p>O GCP oferece um serviço gerenciado (ainda em beta em alguns casos) onde você não precisa incluir um sidecar. Isso simplifica ainda mais o Deployment:</p>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
name: app-simples
namespace: meu-namespace
spec:
serviceAccountName: minha-app-ksa
containers:
- name: app
image: python:3.11-slim
command:
- python
- -c
- |
import os
print(f"Conectando via: {os.getenv('CLOUD_SQL_CONNECTION_NAME')}")
env:
- name: CLOUD_SQL_CONNECTION_NAME
value: "PROJETO-ID:REGIAO:NOME-INSTANCIA"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
automountServiceAccountToken: true</code></pre>
<p>Com o serviço gerenciado, você ainda precisa configurar a conexão, mas o overhead operacional é menor.</p>
<h3>Monitorando Conexões e Debugging</h3>
<p>Para verificar se o Proxy está funcionando corretamente, acesse os logs:</p>
<pre><code class="language-bash">kubectl logs -n meu-namespace deployment/app-com-database -c cloud-sql-proxy</code></pre>
<p>Se a autenticação via Workload Identity falhar, você verá erros como "failed to retrieve token" ou "permission denied". Nesse caso, verifique:</p>
<ol>
<li>Se a GSA realmente tem role <code>roles/cloudsql.client</code></li>
<li>Se a anotação na KSA está correta</li>
<li>Se o mapeamento de confiança foi criado com <code>gcloud iam service-accounts add-iam-policy-binding</code></li>
</ol>
<p>Para testar a conectividade manualmente dentro do Pod:</p>
<pre><code class="language-bash">kubectl exec -it POD-NAME -c app -n meu-namespace -- /bin/bash
Dentro do container
curl -v telnet://localhost:5432</code></pre>
<p>---</p>
<h2>Integrando os Três Componentes: Exemplo Completo</h2>
<p>Agora vamos unir tudo em um exemplo real: um aplicativo Python que roda no GKE Autopilot, usa Workload Identity para autenticar no Cloud SQL, e se comunica com um banco de dados PostgreSQL através do Cloud SQL Proxy.</p>
<h3>Pré-requisitos</h3>
<ol>
<li>Um projeto GCP ativo</li>
<li>Um cluster GKE Autopilot já criado (vimos como criar acima)</li>
<li>Uma instância Cloud SQL PostgreSQL (crie com <code>gcloud sql instances create</code>)</li>
</ol>
<h3>Passo 1: Criar a Instância Cloud SQL</h3>
<pre><code class="language-bash">gcloud sql instances create meudb \
--database-version=POSTGRES_15 \
--tier=db-f1-micro \
--region=us-central1 \
--no-backup</code></pre>
<p>Crie um banco de dados e um usuário:</p>
<pre><code class="language-bash">gcloud sql databases create meudb --instance=meudb
gcloud sql users create app_user --instance=meudb --password=MinhaSenhaSegura123</code></pre>
<h3>Passo 2: Configurar Service Accounts e Workload Identity</h3>
<pre><code class="language-bash"># Criar GSA
gcloud iam service-accounts create gke-app-sa \
--display-name="GKE App Service Account"
Conceder permissões
gcloud projects add-iam-policy-binding SEU-PROJETO-ID \
--member="serviceAccount:gke-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Criar namespace
kubectl create namespace producao
Criar KSA
kubectl create serviceaccount app-ksa -n producao
Mapear KSA para GSA
gcloud iam service-accounts add-iam-policy-binding \
gke-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:SEU-PROJETO-ID.svc.id.goog[producao/app-ksa]"
Anotar KSA
kubectl annotate serviceaccount app-ksa \
-n producao \
iam.gke.io/gcp-service-account=gke-app-sa@SEU-PROJETO-ID.iam.gserviceaccount.com</code></pre>
<h3>Passo 3: Criar a Aplicação</h3>
<p>Crie um arquivo <code>app.py</code>:</p>
<pre><code class="language-python">import os
import psycopg2
from psycopg2.extras import RealDictCursor
import json
def get_connection():
"""Conecta ao Cloud SQL via localhost (Cloud SQL Proxy cuida da criptografia)"""
conn = psycopg2.connect(
host='127.0.0.1',
port=5432,
database='meudb',
user='app_user',
password=os.getenv('DB_PASSWORD', 'MinhaSenhaSegura123')
)
return conn
def create_table():
"""Cria tabela de exemplo se não existir"""
try:
conn = get_connection()
with conn.cursor() as cur:
cur.execute('''
CREATE TABLE IF NOT EXISTS usuarios (
id SERIAL PRIMARY KEY,
nome VARCHAR(100),
email VARCHAR(100)
)
''')
conn.commit()
print("Tabela criada ou já existe")
conn.close()
except Exception as e:
print(f"Erro ao criar tabela: {e}")
def inserir_usuario(nome, email):
"""Insere um usuário"""
try:
conn = get_connection()
with conn.cursor() as cur:
cur.execute(
'INSERT INTO usuarios (nome, email) VALUES (%s, %s) RETURNING id',
(nome, email)
)
user_id = cur.fetchone()[0]
conn.commit()
print(f"Usuário inserido com ID: {user_id}")
conn.close()
return user_id
except Exception as e:
print(f"Erro ao inserir usuário: {e}")
return None
def listar_usuarios():
"""Lista todos os usuários"""
try:
conn = get_connection()
with conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute('SELECT * FROM usuarios')
usuarios = cur.fetchall()
conn.close()
return usuarios
except Exception as e:
print(f"Erro ao listar usuários: {e}")
return []
if __name__ == '__main__':
print("Iniciando aplicação...")
create_table()
Insere dois usuários
inserir_usuario('João Silva', 'joao@example.com')
inserir_usuario('Maria Santos', 'maria@example.com')
Lista usuários
usuarios = listar_usuarios()
print("Usuários no banco:")
for user in usuarios:
print(f" - {user['nome']} ({user['email']})")</code></pre>
<p>Crie um <code>Dockerfile</code>:</p>
<pre><code class="language-dockerfile">FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]</code></pre>
<p>Crie <code>requirements.txt</code>:</p>
<pre><code>psycopg2-binary==2.9.9</code></pre>
<h3>Passo 4: Buildar e Fazer Push da Imagem</h3>
<pre><code class="language-bash">docker build -t gcr.io/SEU-PROJETO-ID/minha-app:1.0 .
docker push gcr.io/SEU-PROJETO-ID/minha-app:1.0</code></pre>
<h3>Passo 5: Criar o Deployment Completo</h3>
<p>Salve como <code>deployment.yaml</code>:</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
name: app-db
namespace: producao
spec:
replicas: 1
selector:
matchLabels:
app: app-db
template:
metadata:
labels:
app: app-db
spec:
serviceAccountName: app-ksa
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: app
image: gcr.io/SEU-PROJETO-ID/minha-app:1.0
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.6.0
args:
- "SEU-PROJETO-ID:us-central1:meudb"
- "--port=5432"
- "--max-connections=5"
ports:
- name: postgres
containerPort: 5432
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL</code></pre>
<h3>Passo 6: Criar Secret com Credenciais</h3>
<pre><code class="language-bash">kubectl create secret generic db-credentials \
-n producao \
--from-literal=password='MinhaSenhaSegura123'</code></pre>
<h3>Passo 7: Deploy e Verificação</h3>
<pre><code class="language-bash">kubectl apply -f deployment.yaml
Aguarde alguns segundos
kubectl get pods -n producao
Veja os logs
kubectl logs -n producao deployment/app-db -c app</code></pre>
<p>Você deve ver um output mostrando que os usuários foram inseridos e listados com sucesso. Isso prova que a autenticação via Workload Identity, o Cloud SQL Proxy, e a aplicação estão todos funcionando juntos perfeitamente.</p>
<p>Para verificar os logs do Proxy especificamente:</p>
<pre><code class="language-bash">kubectl logs -n producao deployment/app-db -c cloud-sql-proxy</code></pre>
<p>Você verá mensagens confirmando que a autenticação foi bem-sucedida e as conexões estão abertas.</p>
<p>---</p>
<h2>Conclusão</h2>
<p>Neste artigo, cobrimos três componentes fundamentais para um deployment seguro e robusto no GCP:</p>
<ol>
<li><strong>GKE Autopilot simplifica radicalmente a operação de Kubernetes</strong> ao gerenciar nós, scaling, patches e conformidade de segurança automaticamente. Você escreve Deployments, o Autopilot cuida do resto. Para times pequenos ou que querem focar em aplicação, não em infraestrutura, é a escolha ideal.</li>
</ol>
<ol>
<li><strong>Workload Identity elimina credenciais armazenadas</strong>, substituindo chaves JSON por tokens de curta duração gerenciados automaticamente. O mapeamento KSA→GSA é fino e auditável, tornando o ambiente significativamente mais seguro sem sacrificar a facilidade de uso.</li>
</ol>
<ol>
<li><strong>Cloud SQL Proxy, integrado com Workload Identity, fornece criptografia fim-a-fim transparente</strong> para o banco de dados. A aplicação conecta em localhost sem saber que há criptografia TLS mútuo, rotação de certificados e autenticação automática acontecendo nos bastidores.</li>
</ol>
<p>Quando usados em conjunto — GKE Autopilot + Workload Identity + Cloud SQL Proxy — você obtém um stack extremamente seguro, altamente gerenciado e com overhead operacional mínimo. Nenhuma chave vaza em repositórios, nenhuma credencial precisa ser rodada manualmente, e nenhuma porta de banco fica exposta na rede.</p>
<p>---</p>
<h2>Referências</h2>
<ol>
<li><a href="https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-overview" target="_blank" rel="noopener noreferrer">Google Cloud GKE Autopilot Documentation</a></li>
<li><a href="https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity" target="_blank" rel="noopener noreferrer">Workload Identity in GKE - Official Guide</a></li>
<li><a href="https://cloud.google.com/sql/docs/postgres/cloud-sql-proxy" target="_blank" rel="noopener noreferrer">Cloud SQL Proxy for GKE - Setup Instructions</a></li>
<li><a href="https://cloud.google.com/architecture/best-practices-for-gke" target="_blank" rel="noopener noreferrer">GCP Best Practices for Security in Kubernetes</a></li>
<li><a href="https://www.psycopg.org/documentation/" target="_blank" rel="noopener noreferrer">PostgreSQL Client Libraries - Python psycopg2</a></li>
</ol>
<p><!-- FIM --></p>