Cómo darle sentido a redes y equipos mediante la gestión de direcciones IP (IPAM)
Últimamente he visto un aumento de clientes que reportan problemas en sus redes, sobre todo en el peering, por colisiones en los rangos de direcciones IP. Es una señal clara de que hace falta planificar y gestionar las direcciones IP en toda la organización.
Aunque puedes llevar el control de tus IPs en una hoja de cálculo compartida, también existen herramientas de software dedicadas. En este post te muestro cómo ejecutar una popular herramienta open source de gestión de direcciones IP (IPAM) llamada Netbox de forma nativa de la nube en Google Cloud Platform (GCP).
Stack tradicional
Tradicionalmente, Netbox se ejecuta en una o más máquinas virtuales con un servidor web al frente. Existe una imagen Docker mantenida por la comunidad, pero las únicas instrucciones disponibles indican ejecutarla con docker compose. Aun así, esta arquitectura se parece mucho a la de muchas aplicaciones que las empresas construyen u operan, así que es un excelente candidato para ilustrar también cómo migrar a la nube pública.

Fuente: Netbox — instalación estándar de Netbox
Diseño nativo de la nube
Decidí investigar cómo funciona la imagen Docker, sus dependencias y parámetros de configuración, y desplegarla en GCP usando únicamente servicios administrados. Este ejemplo sirve para ilustrar cómo "mover y mejorar" o "reemplazar por completo" aplicaciones al migrar a la nube pública.

Instalación revisada de Netbox en GCP con servicios administrados
Componentes de la aplicación
- Aplicación Netbox (app en Python con el framework Django)
- Base de datos PostgreSQL (Cloud SQL)
- Redis (Cloud Memorystore)
Decisiones de diseño
- Base de datos y caché administradas (Cloud SQL, Cloud Memorystore)
- IPs únicamente privadas para bases de datos y caché (Private Service Access)
- DNS privado para los hostnames de las bases de datos (Cloud DNS)
- Secretos almacenados en un gestor de secretos (Secret Manager)
- Runtime de contenedores serverless (Cloud Run, Artifact Registry)
- Load balancer global con TLS (HTTP(S) Load Balancing, Managed Certificate)
- Firewall WAF (Cloud Armor)
Algo con lo que veo batallar a muchas organizaciones es la conexión de servicios administrados y aplicaciones serverless mediante direcciones IP privadas. Este ejemplo muestra cómo se reservan rangos privados en tu red VPC y luego se asignan a los servicios administrados, creando un puente de conectividad.
Cloud DNS se usa para establecer hostnames privados que permitan a las apps conectarse a las bases de datos. Esto da más flexibilidad a futuro si llegas a cambiar de base de datos o necesitas hacer failover, ya que basta con actualizar tus registros DNS y las apps siguen apuntando al mismo dominio. En teoría, podría haber aprovechado el reenvío de DNS y conectarlo todo a mi dominio público, pero internamente no hace falta, así que usé example.com.
No necesitábamos la VM bastion (o jump host), pero levanté una para probar conexiones mientras armaba todo. Lo normal es desplegar un bastion en un managed instance group (MIG) de tamaño 1 y sin direcciones IP externas.
Aplicación web segura y con balanceo de carga

Aplicación Netbox alojada y servida por un Global Load Balancer al frente de un servicio de Cloud Run
Para mostrar mejor cómo encaja todo, usé un dominio personal y registré un "registro A" para la dirección IP estática que asigné al Global Load Balancer; el certificado administrado se aprovisionó automáticamente.

Para mayor seguridad, apliqué una política de Cloud Armor (firewall WAF) al load balancer y restringí los rangos de IP (ver más abajo).
Código de implementación
El código a continuación muestra paso a paso los comandos que utilicé para configurar todo: redes, variables de entorno y secretos, bases de datos, artifact registry e imágenes Docker, Cloud Run, balanceo de carga y firewall WAF.
Complejidad adicional y consideraciones
Una de las razones por las que elegí la aplicación Netbox para ilustrar cómo modernizar y desplegar aplicaciones de forma nativa de la nube es su complejidad técnica. La aplicación incluye sistema de archivos, sesiones, workers e incluso procesos diarios de limpieza vía cron.

Fragmento de Docker Compose para la aplicación Netbox (fíjate en netbox-worker y netbox-housekeeping)
El fragmento del archivo docker-compose.yaml de arriba muestra una característica de YAML llamada anchors, que no es exclusiva de docker-compose.

Ejemplo de característica de YAML (anchors) y merge keys
Puedes duplicar configuraciones de manera concisa y luego sobrescribir comandos para ejecutar distintos scripts en runtime.
Recrear workers en Cloud Run
Para recrear este tipo de funcionalidad en Cloud Run, puedes agregar los flags --cmd y --args. Bastaría con duplicar los comandos usados para desplegar la aplicación principal, cambiar el nombre y luego sobrescribir el CMD para ejecutar un script de entrypoint distinto, como se ve a continuación:
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"
Tarea diaria de housekeeping con Cloud Run y Cloud Scheduler
La tarea diaria de housekeeping puede ejecutarse creando un servicio duplicado en Cloud Run y luego programando ese trabajo diario para que invoque el servicio mediante 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"
Después de desplegar el servicio de housekeeping, habilitamos la API de Cloud Scheduler:
gcloud services enable cloudscheduler.googleapis.com
Luego creamos una cuenta de servicio, le otorgamos permisos de invoker y creamos el trabajo programado:
# 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 archivos
Mi objetivo era demostrar que se puede dividir una aplicación compleja como Netbox y desplegarla en la nube usando Cloud Run y otros servicios administrados. Quizá no sea la mejor solución para esta app en particular, pero es posible.
Si necesitas usar el sistema de archivos, hoy las plataformas serverless tienen limitaciones, así que tal vez prefieras ejecutar la app en Kubernetes Engine, o incluso en una VM de Compute Engine. Puedes ejecutar una VM como contenedor, lo cual es muy práctico, y luego adjuntar discos o volúmenes según necesites.
Sin embargo, un truco para tener un "sistema de archivos" sencillo en Cloud Run es aprovechar Secret Manager, como lo hice en el código de ejemplo y en el fragmento de abajo.
# 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
Buena práctica: cuentas de servicio separadas
Aunque los ejemplos que compartí mostraban una cuenta de servicio separada para el complemento de Cloud Scheduler, lo recomendable es crear cuentas de servicio independientes para cada servicio y para el bastion (VM), y asignarles solo los roles de IAM mínimos que cada uno necesita. Así se respeta el principio de mínimo privilegio.
Para el servicio de Cloud Run, conviene crear una cuenta de servicio aparte llamada "netbox-runner" y otorgarle solo los roles necesarios, como:
Espero que este ejemplo deje claro cómo se pueden modernizar aplicaciones existentes y aprovechar los servicios administrados en la nube pública. Si solo buscas poner Netbox en marcha, los fragmentos de código de arriba deberían bastar, aunque también podrías considerar correrlo en una VM o en K8S.
También podrías convertir el ejemplo funcional a Terraform usando soluciones de terceros como Terraformer, o incluso las propias herramientas de exportación masiva de GCP, que pueden hacer ingeniería inversa de tu infraestructura existente y generar código Terraform.
Si tu organización está enfrentando retos similares con colisiones de IP al configurar sus redes, quizá sea momento de poner en práctica IPAM, ya sea con una hoja de cálculo compartida o con una herramienta popular como Netbox.