Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Netbox cloud-native no Google Cloud Platform (GCP)

By Mike SparrJan 24, 20236 min read

Esta página também está disponível em English, Deutsch, Español, Français, Italiano e 日本語.

Como entender redes e equipamentos com o Gerenciamento de Endereços IP (IPAM)

Tenho notado nos últimos tempos um número cada vez maior de clientes relatando problemas de rede, principalmente de peering, por causa de colisões de faixas de endereços IP. É um sinal claro de que falta planejar e gerenciar os endereços IP em toda a organização.

Dá para controlar seus IPs em uma planilha compartilhada, mas também existem ferramentas de software para isso. Neste post, mostro como rodar uma ferramenta open source popular de gerenciamento de endereços IP (IPAM), o Netbox, de forma cloud-native no Google Cloud Platform (GCP).

Stack tradicional

Historicamente, o Netbox roda em uma ou mais máquinas virtuais, com um servidor web na frente. Existe uma imagem Docker mantida pela comunidade, mas as únicas instruções disponíveis são para executá-la com docker compose. Essa arquitetura, porém, lembra muitas aplicações que as empresas constroem ou operam, então é uma ótima candidata para também ilustrar como migrar para a nuvem pública.

Fonte: Netbox — instalação padrão do Netbox

Arquitetura cloud-native

Resolvi entender como a imagem Docker funciona, suas dependências e parâmetros de configuração, e implantá-la no GCP usando apenas serviços gerenciados. Este exemplo serve para ilustrar como você pode "mover e melhorar" ou "arrancar e substituir" aplicações ao migrar para a nuvem pública.

Instalação revisada do Netbox no GCP usando serviços gerenciados

Componentes da aplicação

  • Aplicação Netbox (app em Python com o framework Django)
  • Banco de dados PostgreSQL (Cloud SQL)
  • Redis (Cloud Memorystore)

Decisões de arquitetura

  • Banco de dados e cache gerenciados (Cloud SQL, Cloud Memorystore)
  • Apenas IPs privados para bancos de dados e cache (Private Service Access)
  • DNS privado para os hostnames dos bancos (Cloud DNS)
  • Segredos guardados no gerenciador de segredos (Secret Manager)
  • Runtime de contêiner serverless (Cloud Run, Artifact Registry)
  • Load balancer global com TLS (HTTP(S) Load Balancing, Managed Certificate)
  • Firewall WAF (Cloud Armor)

Algo em que vejo muitas organizações tropeçarem é conectar serviços gerenciados e aplicações serverless por endereços IP privados. Este exemplo mostra como reservar faixas privadas na sua rede VPC e atribuí-las aos serviços gerenciados, criando uma ponte de conectividade.

O Cloud DNS é usado para definir hostnames privados pelos quais as aplicações se conectam aos bancos de dados. Isso traz mais flexibilidade lá na frente caso você precise trocar de banco ou fazer failover, porque basta atualizar os registros de DNS e as aplicações continuam apontando para o mesmo domínio. Em tese, eu poderia ter usado encaminhamento de DNS e ligado tudo ao meu domínio público, mas internamente isso não é necessário, então optei por example.com.

Não precisávamos da VM bastion (ou jump host), mas subi uma para testar conexões enquanto montava o resto. Em geral, um bastion seria implantado em um managed instance group (MIG) de tamanho 1 e sem endereços IP externos.

Aplicação web segura e com balanceamento de carga

Aplicação Netbox hospedada e servida pelo Global Load Balancer à frente do serviço Cloud Run

Para deixar mais claro como tudo se encaixa, usei um domínio pessoal e registrei um "registro A" para o IP estático que atribuí ao Global Load Balancer; um certificado gerenciado foi provisionado automaticamente.

Para reforçar a segurança, apliquei uma política do Cloud Armor (firewall WAF) ao load balancer e restringi as faixas de IP (veja abaixo).

Código de implementação

O código abaixo mostra, passo a passo, os comandos que usei para configurar tudo: rede, variáveis de ambiente e segredos, bancos de dados, artifact registry e imagens Docker, Cloud Run, balanceamento de carga e firewall WAF.

Complexidades e considerações adicionais

Um dos motivos pelos quais escolhi o Netbox para ilustrar como modernizar e implantar aplicações de forma cloud-native é justamente sua complexidade técnica. A aplicação inclui sistema de arquivos, sessões, workers e até processamento diário de limpeza via cron.

Trecho do Docker Compose para a aplicação Netbox (repare no netbox-worker e no netbox-housekeeping)

O trecho do arquivo docker-compose.yaml acima mostra um recurso do YAML chamado anchors, que não é exclusivo do docker-compose.

Exemplo do recurso de YAML (anchors) e merge keys

Você pode duplicar configurações de forma enxuta e, em seguida, sobrescrever comandos para executar scripts diferentes em tempo de execução.

Recriando workers no Cloud Run

Para recriar esse tipo de funcionalidade no Cloud Run, dá para usar as flags --cmd e --args. Eu simplesmente duplicaria os comandos usados para implantar a aplicação principal, trocaria o nome e sobrescreveria o CMD para executar um script de entrypoint diferente, como abaixo:

gcloud run deploy $WORKER_NAME \
    --platform managed \
    --allow-unauthenticated \
    --vpc-connector $CONNECTOR_NAME \
    --ingress=internal-and-cloud-load-balancing \
    --region $GCP_REGION \
    --image $IMAGE_PATH \
    --set-env-vars "ALLOWED_HOSTS=$ALLOWED_HOSTS" \

    ...

    --cmd "/opt/netbox/venv/bin/python" \
    --args "/opt/netbox/netbox/manage.py" \
    --args "rqworker"

Job diário de housekeeping com Cloud Run e Cloud Scheduler

O job diário de housekeeping pode ser executado criando um serviço duplicado no Cloud Run e agendando esse job diário para invocar o serviço pelo Cloud Scheduler.

gcloud run deploy $HOUSEKEEPING_NAME \
    --platform managed \
    --allow-unauthenticated \
    --vpc-connector $CONNECTOR_NAME \
    --ingress=internal-and-cloud-load-balancing \
    --region $GCP_REGION \
    --image $IMAGE_PATH \
    --set-env-vars "ALLOWED_HOSTS=$ALLOWED_HOSTS" \

    ...

    --cmd "/opt/netbox/housekeeping.sh"

Depois de implantar o serviço de housekeeping, habilitamos a API do Cloud Scheduler:

gcloud services enable cloudscheduler.googleapis.com

Em seguida, criamos uma service account, concedemos a ela permissões de invoker e criamos o job agendado:

# fetch the service URL
export SVC_URL=$(gcloud run services describe $HOUSEKEEPING_NAME \
  --platform managed --region $GCP_REGION --format="value(status.url)")

#########################################################
# create cloud scheduler job
#########################################################
export SA_NAME="cloud-scheduler-runner"
export SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

# create service account
gcloud iam service-accounts create $SA_NAME \
    --display-name "${SA_NAME}"

# add sa binding to cloud run app
gcloud run services add-iam-policy-binding $HOUSEKEEPING_NAME \
    --platform managed \
    --region $GCP_REGION \
    --member=serviceAccount:$SA_EMAIL \
    --role=roles/run.invoker

# create the job to invoke service every day at 2:30 AM
gcloud scheduler jobs create http housekeeping-job --schedule "30 2 * * *" \
    --http-method=GET \
    --uri=$SVC_URL \
    --oidc-service-account-email=$SA_EMAIL \
    --oidc-token-audience=$SVC_URL

Sistemas de arquivos

Meu objetivo era provar que dá para fatiar uma aplicação complexa como o Netbox e implantá-la na nuvem usando o Cloud Run e outros serviços gerenciados. Pode não ser a melhor solução para esse app específico, mas é viável.

Se você precisa do sistema de arquivos, hoje as plataformas serverless são limitadas, e talvez compense rodar no Kubernetes Engine ou até em uma VM do Compute Engine. Você pode rodar uma VM como contêiner, o que é bem prático, e anexar discos/volumes conforme a necessidade.

Mas tem um truque para ter um "sistema de arquivos" simples no Cloud Run: usar o Secret Manager, como fiz no código de exemplo e no trecho abaixo.

# create secret for all vars
gcloud secrets create $SECRET_ID --replication-policy="automatic"
gcloud secrets versions add $SECRET_ID --data-file=${PWD}/$SECRET_FILE

# mount file path in cloud run
gcloud run deploy $SERVICE --image $IMAGE_URL \
    --update-secrets="/env/netbox.env"=$SECRET_ID:$SECRET_VERSION

Boa prática: service accounts separadas

Embora os exemplos que compartilhei tenham mostrado uma service account separada para o complemento Cloud Scheduler, a boa prática é criar service accounts separadas para cada serviço e para o bastion (VM), atribuindo apenas os papéis IAM mínimos necessários. Isso segue o princípio do menor privilégio.

Para o serviço do Cloud Run, devemos criar uma service account "netbox-runner" separada e conceder a ela apenas os papéis necessários, como:

Espero que este exemplo mostre como dá para modernizar aplicações existentes e tirar proveito dos serviços gerenciados na nuvem pública. Se você só quer colocar o Netbox no ar, os trechos de código acima já resolvem, mas vale considerar também rodá-lo em VM ou K8S.

Você também pode converter o exemplo funcional para Terraform usando soluções de terceiros, como o Terraformer, ou até mesmo as ferramentas de exportação em massa do próprio GCP, que fazem engenharia reversa da sua infraestrutura existente e geram código Terraform.

Se a sua organização vem enfrentando desafios parecidos com colisões de IP ao configurar suas redes, talvez seja hora de adotar o IPAM, seja com uma planilha compartilhada, seja com uma ferramenta popular como o Netbox.