IAM protege lo que tiene identidad. Pero el visitante que recorre el catálogo de AlpinaShop a mil peticiones por segundo para copiar los precios no tiene identidad. Tampoco la tiene el que prueba diez mil contraseñas contra el formulario de acceso, ni el que escribe ' OR 1=1-- en el buscador a ver qué pasa. Ese tráfico llega a alpinashop-lb-ip como cualquier cliente legítimo y, sin nada delante, acaba en las instancias del MIG.

Cloud Armor es el cortafuegos de aplicación (WAF) y el sistema de protección frente a denegación de servicio de Google Cloud. Como Cloud CDN, no es un producto que se despliegue aparte: es una política que se adjunta al servicio de backend del balanceador que construiste en 03-02, y se aplica en el borde de la red de Google, en los mismos puntos de presencia donde se hace el balanceo y la caché. El tráfico malicioso se descarta a miles de kilómetros de europe-west1, sin consumir un solo ciclo de tus instancias.

Esta lección tiene un caso concreto: la campaña de otoño de AlpinaShop. Marta detecta dos problemas simultáneos. Un competidor está rastreando el catálogo entero cada noche, lo que dispara el autoescalado del MIG y hunde el ratio de aciertos del CDN. Y el formulario de acceso recibe intentos de fuerza bruta desde varios cientos de direcciones. Vamos a construir la política pol-catalogo-web que resuelve ambos, y sobre todo vamos a desplegarla de la forma correcta, que consiste en no bloquear nada hasta estar seguros.

Aviso importante. Un WAF no sustituye al código seguro, y una política de seguridad mal calibrada bloquea a clientes legítimos, que es un incidente comercial tan real como el que intentabas evitar. Todo lo que sigue es un modelo docente válido, pero antes de aplicar reglas de bloqueo en un entorno de producción real, el diseño debe revisarlo un profesional de seguridad, y toda decisión de filtrado por geografía debe validarla además el responsable legal y comercial.

Contenido

  1. Qué es un WAF, qué cubre y qué no
  2. Dónde actúa Cloud Armor: el recorrido de una petición
  3. Políticas, reglas, prioridades y la regla por defecto
  4. Reglas por dirección IP
  5. Reglas por geografía y sus implicaciones
  6. Reglas preconfiguradas del OWASP Top 10
  7. Falsos positivos: el problema real de un WAF
  8. El lenguaje de expresiones: reglas a medida para AlpinaShop
  9. Modo vista previa: la única forma correcta de desplegar
  10. Limitación de tasa y rate-based-ban
  11. Protección adaptativa frente a DDoS de capa 7
  12. reCAPTCHA Enterprise para distinguir personas de bots
  13. Niveles Standard y Enterprise, y coste
  14. La política completa de la campaña de otoño

  1. Qué es un WAF, qué cubre y qué no

Un cortafuegos de aplicación web inspecciona el contenido de las peticiones HTTP —ruta, cabeceras, parámetros, cuerpo— y decide si dejarlas pasar. Es distinto del firewall de VPC que configuraste en 03-01: aquel trabaja con direcciones IP y puertos, y no tiene ni idea de lo que viaja dentro; este entiende HTTP.

Capa Herramienta Decide con Ejemplo de decisión
Red (3/4) Firewall de VPC (03-01) IP de origen, puerto, protocolo "El puerto 5432 solo desde sa-catalogo-web"
Aplicación (7) Cloud Armor Ruta, cabeceras, parámetros, cuerpo, geografía, tasa "Esta petición contiene un patrón de inyección SQL"
Identidad IAM / IAP (03-04) Quién eres "Solo gcp-datos@ ve el panel de informes"

Qué cubre bien Cloud Armor:

  • Ataques de inyección en los parámetros: SQLi, XSS, inclusión de ficheros locales o remotos, ejecución remota de comandos.
  • Denegación de servicio volumétrica (capas 3 y 4), de forma automática y sin configuración, por el simple hecho de estar detrás del balanceador global.
  • Denegación de servicio de aplicación (capa 7): rastreo masivo, fuerza bruta, abuso de endpoints caros.
  • Filtrado por origen: direcciones, rangos, países, reputación de la IP.
  • Bots básicos y escáneres automatizados.

Qué no cubre, y es igual de importante saberlo:

  • Fallos de lógica de negocio. Si tu endpoint permite pedir el pedido de otro cliente cambiando un identificador en la URL, cada petición es perfectamente legítima a ojos del WAF. Ese fallo se arregla en el código.
  • Credenciales robadas. Un inicio de sesión con la contraseña correcta es un inicio de sesión correcto.
  • Vulnerabilidades en tus dependencias. Puede mitigar la explotación de algunas conocidas, y gana tiempo mientras parcheas, pero no parchea nada.
  • Errores de configuración de permisos. Eso es IAM.
  • Ataques desde dentro o que no pasen por el balanceador. Si una VM tiene IP pública y se puede alcanzar directamente, el WAF no se entera.

Un WAF es una capa de mitigación, no una absolución. Es lo que te da margen para arreglar las cosas, no lo que las arregla.

  1. Dónde actúa Cloud Armor: el recorrido de una petición

flowchart TB
    A([Petición maliciosa<br/>GET /buscar?q=' OR 1=1--])
    B["PoP de Google más cercano<br/>Madrid, Lisboa, Fráncfort…"]
    C{"Cloud Armor<br/>pol-catalogo-web"}
    D["Cloud CDN<br/>búsqueda en caché"]
    E["Mapa de URL<br/>alpinashop-url-map"]
    F["bs-catalogo-web → MIG"]
    G(["403 Forbidden<br/>desde el borde"])

    A --> B --> C
    C -->|"coincide regla 1000<br/>action: deny-403"| G
    C -->|"no coincide: allow"| D
    D -->|acierto| A
    D -->|fallo| E --> F

Los cuatro hechos que importan de este diagrama:

  1. Cloud Armor se evalúa en el borde, en el mismo punto de presencia donde entra el cliente. El paquete malicioso nunca cruza hasta europe-west1.
  2. Se evalúa antes que la caché. Una petición bloqueada no consulta la caché ni consume relleno; y a la inversa, activar el CDN no crea un camino por el que el tráfico esquive el WAF.
  3. Se evalúa antes que IAP. El bot que ataca el panel de informes se descarta antes de llegar siquiera a la pantalla de inicio de sesión.
  4. La respuesta de bloqueo la genera el borde. Tus instancias no ven la petición, no la registran en sus logs y no gastan CPU.

Las políticas se adjuntan a un servicio de backend:

gcloud compute backend-services update bs-catalogo-web --global \
  --security-policy=pol-catalogo-web

Para los backends de bucket como bb-catalogo-imagenes existe una variante llamada política de seguridad de borde (--edge-security-policy), que admite menos tipos de regla —filtrado por IP, geografía y algunas expresiones básicas— pero se aplica también al contenido servido desde caché. Es la forma de proteger las imágenes sin renunciar al CDN.

  1. Políticas, reglas, prioridades y la regla por defecto

Una política de seguridad es un contenedor ordenado de reglas. Cada regla tiene:

  • Una prioridad (entero). Se evalúan de menor a mayor y gana la primera que coincide; el resto ni se miran.
  • Una condición: o una lista de rangos IP, o una expresión.
  • Una acción: allow, deny-403, deny-404, deny-502, throttle, rate-based-ban, redirect.
gcloud config set project alpinashop-prod

gcloud compute security-policies create pol-catalogo-web \
  --description="Proteccion del catalogo publico de AlpinaShop"

Al crearla, Google añade automáticamente la regla por defecto, con prioridad 2147483647 (el mayor entero de 32 bits con signo) y acción allow. Es la que atrapa todo lo que no coincidió con nada anterior.

Esa regla plantea la decisión de diseño más importante de la lección:

Modelo Regla por defecto Ventaja Inconveniente
Lista negra (por defecto allow) Permitir Nada se rompe; se bloquea lo que se identifica Solo protege de lo que has previsto
Lista blanca (por defecto deny) Denegar Máxima seguridad Inviable en una web pública

Para el catálogo público de AlpinaShop, el modelo es forzosamente lista negra: cualquiera del mundo debe poder ver una mochila. Para una API interna o un panel de administración, la lista blanca sí es viable y es lo correcto.

Deja siempre un hueco de prioridades. Numera de 100 en 100 (1000, 1100, 1200…) para poder insertar reglas entre medias sin renumerar todo:

gcloud compute security-policies rules list --security-policy=pol-catalogo-web \
  --format="table(priority, action, preview, description)"

  1. Reglas por dirección IP

La regla más simple y la que siempre debe ir primero: la oficina de AlpinaShop y el proveedor de pruebas de carga nunca deben ser bloqueados por nada, ni siquiera por una regla del OWASP mal calibrada.

# Prioridad 100: la oficina SIEMPRE pasa. Antes que todo lo demas.
gcloud compute security-policies rules create 100 \
  --security-policy=pol-catalogo-web \
  --src-ip-ranges=203.0.113.24/29 \
  --action=allow \
  --description="Oficina de AlpinaShop: exenta de todas las reglas"

# Prioridad 200: bloqueo permanente de direcciones abusivas confirmadas
gcloud compute security-policies rules create 200 \
  --security-policy=pol-catalogo-web \
  --src-ip-ranges=198.51.100.0/24,192.0.2.77/32 \
  --action=deny-403 \
  --description="Rangos con abuso confirmado, revisado 2026-08"

Detalles prácticos:

  • Se admiten hasta varios miles de rangos por política, pero mantener listas enormes a mano es insostenible. Para eso está la inteligencia de amenazas del nivel Enterprise (apartado 13).
  • Bloquear por IP tiene fecha de caducidad. Las direcciones domésticas son dinámicas: la que hoy es de un atacante mañana es la de un cliente. Documenta la fecha de revisión en la descripción, como en el ejemplo, y revisa esas listas.
  • Detrás de un proxy o de otro CDN, origin.ip es la del proxy. Si ese es tu caso, la expresión correcta usa la IP del X-Forwarded-For de confianza; configúralo con cuidado, porque esa cabecera la puede falsificar el cliente si no se valida bien.

  1. Reglas por geografía y sus implicaciones

Cloud Armor conoce el país de origen de cada petición y lo expone como origin.region_code, con códigos ISO de dos letras.

# Bloquear paises desde los que AlpinaShop no vende NI recibe visitas legitimas
gcloud compute security-policies rules create 300 \
  --security-policy=pol-catalogo-web \
  --expression="origin.region_code == 'XX' || origin.region_code == 'YY'" \
  --action=deny-403 \
  --description="Paises fuera del mercado; revisar con direccion comercial"

Y una variante mucho más razonable: en lugar de bloquear el catálogo entero, restringir solo el panel de administración, que sí tiene un origen legítimo perfectamente acotado.

gcloud compute security-policies rules create 400 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/admin') && origin.region_code != 'ES'" \
  --action=deny-404 \
  --description="Panel de administracion solo desde Espana"

Fíjate en deny-404 en lugar de deny-403: al atacante no le confirmamos que exista un panel de administración. Es una diferencia pequeña que reduce la información que regalas.

Las tres advertencias del bloqueo geográfico, y ninguna es técnica:

  1. Es trivial de esquivar. Una VPN de tres euros al mes lo anula. Frena el ruido automatizado, no a un atacante decidido.
  2. Bloquea clientes reales. Un cliente español de vacaciones, un expatriado, alguien tras una VPN corporativa. En una tienda, cada bloqueo es una venta perdida y una llamada a atención al cliente.
  3. Puede tener implicaciones legales y comerciales. Bloquear países es una decisión de negocio, y en algunos contextos de cumplimiento normativo. No la tome el equipo técnico en solitario.

La postura recomendable: usa la geografía para restringir rutas sensibles (/admin, /api/interna) y para puntuar el riesgo en combinación con otras señales, no para cerrar la tienda a un continente.

  1. Reglas preconfiguradas del OWASP Top 10

Aquí está el valor principal de un WAF gestionado. Google mantiene conjuntos de reglas basados en el ModSecurity Core Rule Set, actualizados por su equipo de seguridad, que se invocan con la función evaluatePreconfiguredWaf().

Conjunto Protege frente a Riesgo de falso positivo
sqli-v33-stable Inyección SQL Alto: los buscadores y los campos de texto libre disparan muchas reglas
xss-v33-stable Cross-site scripting Alto: cualquier campo que acepte HTML o comillas
lfi-v33-stable Inclusión de ficheros locales (../../etc/passwd) Medio
rfi-v33-stable Inclusión de ficheros remotos Bajo
rce-v33-stable Ejecución remota de comandos Medio
scannerdetection-v33-stable Escáneres automáticos (Nikto, sqlmap, Nessus) Bajo
protocolattack-v33-stable Contrabando de peticiones, HTTP response splitting Bajo
methodenforcement-v33-stable Métodos HTTP inesperados Bajo
sessionfixation-v33-stable Fijación de sesión Bajo
php-v33-stable, nodejs-v33-stable, java-v33-stable Ataques específicos de esas pilas Bajo, y innecesarios en una pila Python
cve-canary Vulnerabilidades críticas recientes (Log4Shell y similares) Bajo. Actívalo siempre

La creación de las reglas, con sensibilidad y siempre en vista previa la primera vez:

# SQLi con sensibilidad baja: solo los patrones mas evidentes
gcloud compute security-policies rules create 1000 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 1})" \
  --action=deny-403 \
  --preview \
  --description="OWASP: inyeccion SQL, sensibilidad 1"

gcloud compute security-policies rules create 1100 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('xss-v33-stable', {'sensitivity': 1})" \
  --action=deny-403 --preview \
  --description="OWASP: XSS, sensibilidad 1"

gcloud compute security-policies rules create 1200 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('lfi-v33-stable', {'sensitivity': 1})" \
  --action=deny-403 --preview \
  --description="OWASP: inclusion de ficheros locales"

gcloud compute security-policies rules create 1300 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('rce-v33-stable', {'sensitivity': 1})" \
  --action=deny-403 --preview \
  --description="OWASP: ejecucion remota de comandos"

gcloud compute security-policies rules create 1400 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('scannerdetection-v33-stable', {'sensitivity': 1})" \
  --action=deny-403 --preview \
  --description="OWASP: deteccion de escaneres"

# Vulnerabilidades criticas recientes: esta va directa a bloqueo
gcloud compute security-policies rules create 900 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('cve-canary', {'sensitivity': 1})" \
  --action=deny-403 \
  --description="CVE criticas recientes"

La sensibilidad va de 1 a 4 y funciona como un umbral acumulativo:

Nivel Qué detecta Falsos positivos Recomendación
1 Solo los patrones de ataque más claros Pocos Empieza aquí. Siempre.
2 Añade patrones probables Notables Solo tras depurar el nivel 1
3 Añade patrones sospechosos Muchos Sitios de alto riesgo, con dedicación
4 Todo, incluido lo dudoso Inviable en producción Análisis forense

Un aviso que ahorra mucho tiempo: si tu aplicación es Python con Flask y PostgreSQL, no actives php-v33-stable, nodejs-v33-stable ni java-v33-stable. No aportan protección y cada regla activa cuesta dinero y añade probabilidad de falso positivo.

  1. Falsos positivos: el problema real de un WAF

Esta es la parte que los folletos no cuentan. Las reglas del OWASP funcionan buscando patrones, y muchos patrones legítimos se parecen a un ataque. Casos reales que se dan en una tienda como AlpinaShop:

Petición perfectamente legítima Regla que dispara Por qué
Buscar mochila 40l "trekking" sqli Las comillas dobles
Buscar pantalón O'Neill sqli El apóstrofo
Descripción de producto con <b>Ligera</b> xss Etiquetas HTML
Reseña que contiene 1=1 en cuanto al peso sqli El patrón 1=1
Subida de una imagen con nombre ../foto.jpg lfi La secuencia ../
Un JSON con select como nombre de campo sqli Palabra clave SQL

Hay tres formas de resolverlo, en orden de preferencia:

1. Desactivar reglas concretas del conjunto, en lugar de bajar la sensibilidad global:

gcloud compute security-policies rules update 1000 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 1, 'opt_out_rule_ids': ['owasp-crs-v030301-id942432-sqli', 'owasp-crs-v030301-id942431-sqli']})"

Los identificadores de regla salen del log: cada bloqueo registra exactamente qué regla del conjunto disparó. Esto es cirugía, frente al hachazo de bajar la sensibilidad.

2. Excluir rutas concretas del análisis, cuando sabes que un endpoint recibe texto libre por diseño:

gcloud compute security-policies rules create 950 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/api/resenas') && request.method == 'POST'" \
  --action=allow \
  --description="Resenas: texto libre, exento del WAF. Validado en la app."

Con una condición muy seria: si excluyes una ruta del WAF, esa ruta tiene que estar impecablemente validada en el código. Estás renunciando a la red de seguridad justo donde entra texto arbitrario.

3. Bajar la sensibilidad. Es lo más rápido y lo menos preciso. Válido como medida temporal durante un incidente.

Y el consejo que engloba a los tres: el procedimiento correcto no es reaccionar a los falsos positivos en producción, sino descubrirlos antes con el modo vista previa.

  1. El lenguaje de expresiones: reglas a medida para AlpinaShop

Cloud Armor usa CEL (Common Expression Language), el mismo lenguaje de las condiciones de IAM que viste en 03-04. Los atributos disponibles:

Atributo Ejemplo
origin.ip inIpRange(origin.ip, '203.0.113.0/24')
origin.region_code origin.region_code == 'ES'
request.path request.path.startsWith('/admin')
request.method request.method == 'POST'
request.query request.query.contains('debug=1')
request.headers['nombre'] request.headers['user-agent'].contains('curl')
request.headers['host'] request.headers['host'] == 'alpinashop.example'
has(request.headers['x']) Comprobar la presencia de una cabecera
request.path.matches('regex') Expresión regular (RE2)

Caso 1: el bot que arrasa el catálogo. El competidor rastrea con un cliente que se identifica y no ejecuta JavaScript. Se le reconoce por la combinación de agente de usuario y ausencia de cabeceras de navegador real:

gcloud compute security-policies rules create 2000 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/producto/') && (
      request.headers['user-agent'].contains('python-requests') ||
      request.headers['user-agent'].contains('Scrapy') ||
      request.headers['user-agent'].contains('HeadlessChrome') ||
      !has(request.headers['accept-language'])
    )" \
  --action=deny-403 --preview \
  --description="Rastreo automatizado del catalogo"

La condición !has(request.headers['accept-language']) es la más útil de las cuatro: prácticamente todos los navegadores reales envían esa cabecera y prácticamente ningún script sencillo se molesta en ponerla. Y es precisamente la que debe pasar más tiempo en vista previa, porque también la omiten algunos clientes legítimos.

Caso 2: proteger un endpoint caro. La exportación del catálogo en CSV tarda segundos y consume base de datos. Solo debe usarse desde la oficina:

gcloud compute security-policies rules create 2100 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/exportar') && !inIpRange(origin.ip, '203.0.113.24/29')" \
  --action=deny-403 \
  --description="Exportacion CSV: solo desde la oficina"

Caso 3: rechazar métodos que la aplicación no usa. El catálogo solo sirve GET, HEAD y POST:

gcloud compute security-policies rules create 2200 \
  --security-policy=pol-catalogo-web \
  --expression="request.method == 'TRACE' || request.method == 'TRACK' || request.method == 'CONNECT'" \
  --action=deny-403 \
  --description="Metodos HTTP no utilizados por la aplicacion"

Caso 4: evitar el acceso por IP directa. Toda petición legítima llega con el Host correcto; las que llegan con la IP en el Host son escaneo indiscriminado:

gcloud compute security-policies rules create 2300 \
  --security-policy=pol-catalogo-web \
  --expression="request.headers['host'] != 'alpinashop.example' && request.headers['host'] != 'www.alpinashop.example' && request.headers['host'] != 'imagenes.alpinashop.example'" \
  --action=deny-404 \
  --description="Peticiones sin Host valido: escaneo"

  1. Modo vista previa: la única forma correcta de desplegar

Toda regla admite --preview. En ese modo, la regla se evalúa y se registra, pero no se aplica. La petición sigue su curso normal.

Esto no es una comodidad: es el procedimiento. Una regla del OWASP con sensibilidad mal elegida puede bloquear el buscador de tu tienda el día de más ventas del año, y lo peor es que no te enterarás por una alerta, sino por una caída de conversión que nadie relaciona con el WAF.

El procedimiento de despliegue, paso a paso:

# PASO 1 — Crear TODAS las reglas nuevas en vista previa
gcloud compute security-policies rules create 1000 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 1})" \
  --action=deny-403 --preview

# PASO 2 — Activar el registro detallado de la politica
gcloud compute security-policies update pol-catalogo-web \
  --log-level=VERBOSE

# PASO 3 — Esperar. Como minimo una semana de trafico real,
#          incluyendo un fin de semana y un dia de campana.

# PASO 4 — Analizar QUE habria bloqueado
gcloud logging read '
  resource.type="http_load_balancer"
  AND jsonPayload.previewSecurityPolicy.outcome="DENY"
' --project=alpinashop-prod --freshness=7d --limit=100 \
  --format="table(
    jsonPayload.previewSecurityPolicy.priority,
    httpRequest.requestUrl,
    httpRequest.remoteIp,
    jsonPayload.previewSecurityPolicy.preconfiguredExprIds
  )"

El campo previewSecurityPolicy.preconfiguredExprIds es el que da los identificadores concretos de regla del conjunto OWASP, que son los que necesitas para el opt_out_rule_ids del apartado 7.

Un recuento agregado, para decidir con números en lugar de con impresiones:

gcloud logging read '
  resource.type="http_load_balancer"
  AND jsonPayload.previewSecurityPolicy.outcome="DENY"
' --project=alpinashop-prod --freshness=7d --limit=1000 \
  --format="value(jsonPayload.previewSecurityPolicy.priority)" | sort | uniq -c | sort -rn
    847 1000     ← SQLi: casi todo son busquedas con apostrofos. Falsos positivos.
     93 2000     ← Rastreo: revisar caso por caso.
      6 1200     ← LFI: ataques reales.
      1 900      ← CVE: ataque real.

Ese recuento se lee así: la regla 1000 tal como está bloquearía 847 búsquedas legítimas en una semana. No se activa: se depura con opt_out_rule_ids o se excluye la ruta del buscador, y vuelve a vista previa otra semana.

# PASO 5 — Activar de verdad, regla a regla, empezando por las limpias
gcloud compute security-policies rules update 1200 \
  --security-policy=pol-catalogo-web --no-preview

# PASO 6 — Vigilar 24-48 h el trafico realmente bloqueado
gcloud logging read '
  resource.type="http_load_balancer"
  AND jsonPayload.enforcedSecurityPolicy.outcome="DENY"
' --project=alpinashop-prod --freshness=1d --limit=50 \
  --format="table(timestamp, jsonPayload.enforcedSecurityPolicy.priority, httpRequest.requestUrl)"

La distinción entre los dos campos del log es la clave de todo el apartado:

Campo Significado
jsonPayload.previewSecurityPolicy Lo que habría pasado. La regla está en vista previa
jsonPayload.enforcedSecurityPolicy Lo que ha pasado. La regla está activa

Y una regla de oro operativa: nunca actives reglas nuevas el día antes de una campaña. La campaña de otoño de AlpinaShop empieza el 15 de septiembre; las reglas se ponen en vista previa el 1 de agosto y se activan, como muy tarde, el 1 de septiembre.

  1. Limitación de tasa y rate-based-ban

El segundo problema de Marta es la fuerza bruta contra /acceso. Aquí no hay patrón malicioso que detectar: cada petición individual es legítima. Lo anómalo es la frecuencia.

Cloud Armor ofrece dos acciones:

  • throttle: por encima del umbral, se rechazan las peticiones que exceden, pero en cuanto baja el ritmo se vuelve a servir. Es un limitador continuo.
  • rate-based-ban: por encima del umbral, se veta a ese cliente durante un tiempo fijo, aunque deje de insistir. Es el castigo.
# Formulario de acceso: 5 intentos por minuto y por IP; si se pasa, veto de 10 minutos
gcloud compute security-policies rules create 3000 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/acceso') && request.method == 'POST'" \
  --action=rate-based-ban \
  --rate-limit-threshold-count=5 \
  --rate-limit-threshold-interval-sec=60 \
  --ban-duration-sec=600 \
  --conform-action=allow \
  --exceed-action=deny-429 \
  --enforce-on-key=IP \
  --description="Fuerza bruta contra el formulario de acceso"

# Buscador: caro en base de datos. 30 busquedas por minuto y por IP, con limitacion continua
gcloud compute security-policies rules create 3100 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/buscar')" \
  --action=throttle \
  --rate-limit-threshold-count=30 \
  --rate-limit-threshold-interval-sec=60 \
  --conform-action=allow \
  --exceed-action=deny-429 \
  --enforce-on-key=IP \
  --description="Limite de busquedas por IP"

# Suelo general del sitio, muy holgado: 600 peticiones por minuto
gcloud compute security-policies rules create 3200 \
  --security-policy=pol-catalogo-web \
  --expression="true" \
  --action=throttle \
  --rate-limit-threshold-count=600 \
  --rate-limit-threshold-interval-sec=60 \
  --conform-action=allow \
  --exceed-action=deny-429 \
  --enforce-on-key=IP \
  --description="Limite general por IP"

La clave de agrupación (--enforce-on-key) decide por quién se cuenta, y elegirla mal invalida la protección:

Clave Cuenta por Cuándo usarla Riesgo
IP Dirección de origen Caso general Un colegio o una empresa comparten IP: se penaliza a todos
ALL Todo el tráfico junto Proteger un endpoint frágil con un techo global No distingue: un atacante deja fuera a todos
HTTP_HEADER Valor de una cabecera APIs con clave de cliente El cliente controla la cabecera y puede rotarla
HTTP_COOKIE Valor de una cookie Sesiones Se esquiva borrando la cookie
XFF_IP Primera IP de X-Forwarded-For Detrás de otro proxy Falsificable si no se valida el proxy
REGION_CODE País Ataques concentrados geográficamente Muy grueso
HTTP_PATH Ruta Proteger cada ruta por separado —

Dos consejos de calibración que valen más que cualquier regla:

  • Mide antes de poner un número. El percentil 99 de peticiones por minuto y por IP de tu tráfico real está en el log del balanceador. Pon el umbral en dos o tres veces ese valor, no en un número redondo elegido a ojo.
  • deny-429 y no deny-403. El código 429 (Too Many Requests) es el semánticamente correcto, los clientes legítimos saben reintentar con espera y los buscadores lo interpretan como "vuelve luego" en lugar de "esto está prohibido", lo cual protege tu posicionamiento.

  1. Protección adaptativa frente a DDoS de capa 7

Las reglas anteriores dependen de que alguien haya previsto el ataque. La protección adaptativa no: entrena modelos con el tráfico normal de tu aplicación y detecta desviaciones anómalas, proponiendo reglas concretas.

gcloud compute security-policies update pol-catalogo-web \
  --enable-layer7-ddos-defense \
  --layer7-ddos-defense-rule-visibility=STANDARD

Cómo funciona en la práctica:

  1. Necesita entre varios días y una semana de tráfico para tener una línea base. Actívala mucho antes de necesitarla.
  2. Cuando detecta una anomalía, genera una alerta con la firma del ataque: agentes de usuario implicados, rangos de origen, rutas atacadas, y una puntuación de confianza.
  3. Sugiere una regla de Cloud Armor lista para aplicar, con un impacto estimado sobre el tráfico legítimo.
  4. La decisión de aplicarla sigue siendo tuya. Puede aplicarse automáticamente, pero en una tienda es preferible la revisión humana.

Conviene tener claro qué protege y qué no: los ataques volumétricos de capa 3 y 4 (SYN flood, amplificación UDP) los absorbe la infraestructura de Google automáticamente por el mero hecho de estar detrás del balanceador global, sin configurar nada. La protección adaptativa es para los ataques de capa 7, esos que consisten en peticiones HTTP perfectamente formadas pero en cantidad y patrón anómalos, que son mucho más difíciles de distinguir del tráfico real.

  1. reCAPTCHA Enterprise para distinguir personas de bots

Cuando el bot es sofisticado —ejecuta JavaScript, rota direcciones IP, envía cabeceras de navegador real— ninguna regla estática lo distingue. La respuesta es reCAPTCHA Enterprise, integrado nativamente con Cloud Armor.

El flujo es interesante porque no es el CAPTCHA clásico de "selecciona los semáforos":

  1. La aplicación incluye el script de reCAPTCHA, que evalúa el comportamiento del usuario en segundo plano y emite un token con una puntuación de 0,0 (casi seguro un bot) a 1,0 (casi seguro una persona).
  2. Cloud Armor lee ese token en el borde y actúa según la puntuación.
  3. Solo si la puntuación es dudosa se muestra un desafío visible. La mayoría de los usuarios nunca ven nada.
# 1) Asociar la clave de reCAPTCHA a la politica
gcloud compute security-policies update pol-catalogo-web \
  --recaptcha-redirect-site-key="projects/alpinashop-prod/keys/CLAVE_RECAPTCHA"

# 2) Puntuacion baja en el proceso de compra: desafio, no bloqueo
gcloud compute security-policies rules create 4000 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/pago') && token.recaptcha_session.score < 0.5" \
  --action=redirect \
  --redirect-type=GOOGLE_RECAPTCHA \
  --description="Sospecha de bot en el pago: desafio reCAPTCHA"

La decisión de diseño aquí es redirect y no deny: ante la duda, en una tienda nunca se bloquea, se pregunta. Un falso positivo con deny es una venta perdida; con redirect, un segundo de fricción. Ese criterio —bloquear lo evidente, desafiar lo dudoso— es el que separa una política de seguridad usable de una que hace perder dinero.

  1. Niveles Standard y Enterprise, y coste

Cloud Armor Standard Cloud Armor Enterprise
Modelo Pago por uso Suscripción (mensual o anual)
Reglas por IP, geografía y expresiones Sí Sí
Reglas preconfiguradas OWASP Sí Sí
Limitación de tasa Sí Sí
Protección DDoS de capas 3/4 Sí, automática Sí
Protección adaptativa (capa 7) Limitada Completa
Inteligencia de amenazas No Sí (evaluateThreatIntelligence)
Protección de la factura ante DDoS No Sí
Soporte especializado durante un ataque No Sí

La inteligencia de amenazas merece una mención porque resuelve el problema del apartado 4: en lugar de mantener listas de IP a mano, Google mantiene listas categorizadas y actualizadas:

# Solo con Cloud Armor Enterprise
gcloud compute security-policies rules create 500 \
  --security-policy=pol-catalogo-web \
  --expression="evaluateThreatIntelligence('iplist-known-malicious-ips')" \
  --action=deny-403 --preview \
  --description="Direcciones maliciosas conocidas"

Otras listas disponibles incluyen nodos de salida de Tor, proxies anónimos, escáneres de búsqueda y los rangos de los grandes proveedores de nube (útil: casi ningún cliente legítimo de una tienda navega desde un centro de datos).

Coste orientativo de Standard, como orden de magnitud:

Concepto Aproximado
Política de seguridad ~5 $/mes cada una
Regla ~1 $/mes cada una
Peticiones evaluadas ~0,75 $ por millón

Con la política de esta lección (unas quince reglas) y unos 10 millones de peticiones al mes, salen del orden de 25-30 $/mes. Comparado con lo que cuesta un incidente, o simplemente con lo que cuestan las instancias adicionales que levanta el autoescalado durante un rastreo masivo, es de las inversiones más rentables de la plataforma. Verifica siempre las tarifas vigentes en la documentación oficial, porque cambian y varían por región.

La protección de la factura ante DDoS de Enterprise merece una reflexión: en un ataque volumétrico grande, el coste no está en el daño, está en la factura de salida de datos y de cómputo que genera absorberlo. Ese seguro es la razón principal por la que una empresa con exposición real contrata Enterprise.

  1. La política completa de la campaña de otoño

Este es el resultado final para AlpinaShop, ordenado por prioridad. Léelo como un documento de diseño:

Prioridad Regla Acción Estado
100 Oficina 203.0.113.24/29 allow Activa
200 Rangos con abuso confirmado deny-403 Activa
400 /admin fuera de España deny-404 Activa
500 Inteligencia de amenazas (Enterprise) deny-403 Vista previa
900 cve-canary deny-403 Activa
950 Exención de /api/resenas allow Activa
1000-1400 OWASP: SQLi, XSS, LFI, RCE, escáneres deny-403 Vista previa → activación por fases
2000 Rastreo automatizado del catálogo deny-403 Vista previa
2100 /exportar solo desde la oficina deny-403 Activa
2200 Métodos HTTP no usados deny-403 Activa
2300 Host no válido deny-404 Activa
3000 Fuerza bruta en /acceso rate-based-ban Activa
3100 Límite del buscador throttle Activa
3200 Límite general por IP throttle Activa
4000 reCAPTCHA en /pago redirect Activa
2147483647 Por defecto allow Activa
# Aplicar la politica al servicio de backend
gcloud compute backend-services update bs-catalogo-web --global \
  --security-policy=pol-catalogo-web

# Politica de borde para las imagenes, compatible con el CDN
gcloud compute security-policies create pol-borde-imagenes \
  --type=CLOUD_ARMOR_EDGE \
  --description="Filtrado basico en el borde para el catalogo de imagenes"

gcloud compute backend-buckets update bb-catalogo-imagenes \
  --edge-security-policy=pol-borde-imagenes

# Verificacion
gcloud compute backend-services describe bs-catalogo-web --global \
  --format="value(securityPolicy)"

Y la comprobación de que funciona, que siempre debe hacerse desde fuera de la oficina, porque la regla 100 te exime de todo:

# Deberia devolver 403 (con la regla 1000 ya activa)
curl -s -o /dev/null -w "%{http_code}\n" \
  "https://alpinashop.example/buscar?q=%27%20OR%201%3D1--"

# Deberia devolver 200
curl -s -o /dev/null -w "%{http_code}\n" \
  "https://alpinashop.example/buscar?q=mochila"

# Fuerza bruta: las primeras 5 pasan, el resto 429
for i in $(seq 1 10); do
  curl -s -o /dev/null -w "%{http_code} " \
    -X POST -d "usuario=test&clave=test" https://alpinashop.example/acceso
done; echo

Errores Comunes y Consejos

  • Activar reglas sin vista previa. Es el error grave de esta lección. Una regla de SQLi mal calibrada bloquea el buscador y nadie relaciona la caída de ventas con el WAF.
  • Empezar con sensibilidad 3 o 4. Sensibilidad 1 y se sube solo si el análisis del log lo justifica.
  • No numerar dejando huecos. Prioridades correlativas obligan a renumerar para insertar una regla.
  • Olvidar la regla de exención de la oficina en la prioridad más baja. Si te bloqueas a ti mismo durante un incidente, la depuración se vuelve un infierno.
  • Probar desde la oficina. La regla 100 te deja pasar siempre; parecerá que nada funciona. Prueba desde una red externa.
  • Bloquear países sin consultar. Es una decisión comercial y a veces legal, no técnica.
  • Confundir throttle con rate-based-ban. El primero limita mientras dura el exceso; el segundo veta durante un tiempo fijo. Para fuerza bruta, veto.
  • Umbrales de tasa elegidos a ojo. Mide el percentil 99 real en el log del balanceador y multiplica por dos o tres.
  • enforce-on-key=IP sin pensar en las IP compartidas. Un instituto o una empresa salen por una sola dirección; un umbral bajo bloquea a treinta personas legítimas.
  • Devolver deny-403 a los limitadores de tasa. El código correcto es 429.
  • Activar conjuntos de reglas de tecnologías que no usas. php-v33-stable en una aplicación Python: cuesta dinero y añade falsos positivos sin aportar nada.
  • Creer que el WAF sustituye a la validación en el código. Consultas parametrizadas, escapado de salida y validación de entrada siguen siendo obligatorios. El WAF es la segunda línea.
  • No activar el registro VERBOSE durante la vista previa. Sin los identificadores de regla concretos no puedes usar opt_out_rule_ids y solo te queda el hachazo de bajar la sensibilidad.
  • Consejo: gestiona la política como código (06-07) y exporta su estado antes de cada cambio: gcloud compute security-policies describe pol-catalogo-web --format=yaml > politica-$(date +%F).yaml.
  • Consejo: pon una alerta sobre el número de peticiones denegadas. Un pico de bloqueos puede ser un ataque, pero también un despliegue de tu propia aplicación que empezó a enviar algo que el WAF no reconoce.

Ejercicios

Ejercicio 1 — Interpretar una semana de vista previa

Tras siete días con todas las reglas en vista previa, el recuento por prioridad es:

   1204 1000   SQLi
    412 1100   XSS
    156 2000   Rastreo automatizado
     18 1400   Escaneres
      4 1200   LFI
      2 900    CVE

Una muestra de las peticiones de la regla 1000 muestra que el 90 % son de la forma /buscar?q=camiseta+t%C3%A9cnica+O%27Neill y /buscar?q=%22gore-tex%22. Las de la 1100 son en su mayoría POST /api/resenas con texto que contiene <3 y >>.

Decide, regla por regla, qué activar, qué depurar y qué dejar en vista previa, y escribe los comandos.

Ejercicio 2 — Diseñar la protección de un endpoint nuevo

AlpinaShop lanza una API pública para tiendas asociadas: POST /api/socios/pedidos, autenticada con una cabecera X-Alpina-Api-Key. Requisitos:

  • Máximo 100 peticiones por minuto y por clave de API (no por IP: varias tiendas comparten operador).
  • Las peticiones sin la cabecera se rechazan en el borde, sin llegar a la aplicación.
  • Solo se acepta POST.
  • Las tiendas asociadas están en España, Portugal y Francia.
  • Un socio que supere el límite tres veces seguidas debe quedar vetado 15 minutos.

Escribe las reglas con sus prioridades y justifica el orden.

Ejercicio 3 — Responder a un incidente en curso

Son las 22:00 de un viernes. La tienda va lentísima, el MIG está en 10 instancias (su máximo) y Marta ve en el log del balanceador que el 80 % del tráfico son peticiones GET /buscar?q=<aleatorio> desde unos 4 000 direcciones IP distintas repartidas por todo el mundo, con agentes de usuario de navegador plausibles y sin cabecera Referer.

Describe la respuesta inmediata, la de las 24 horas siguientes y la estructural. ¿Por qué no sirve aquí una regla por IP?


Soluciones

Solución 1

Regla 1000 (SQLi) — depurar, seguir en vista previa. Los 1204 bloqueos son casi todos falsos positivos: apóstrofos de apellidos y comillas de búsquedas de marca. Bloquearla dejaría sin buscador a los clientes. Dos correcciones combinadas:

# a) Excluir del WAF la ruta del buscador, que ya usa consultas parametrizadas
gcloud compute security-policies rules create 990 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/buscar') && request.method == 'GET'" \
  --action=allow \
  --description="Buscador: consultas parametrizadas verificadas en el codigo"

# b) Y ademas desactivar los identificadores concretos que salen del log
gcloud compute security-policies rules update 1000 \
  --security-policy=pol-catalogo-web \
  --expression="evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 1, 'opt_out_rule_ids': ['owasp-crs-v030301-id942432-sqli']})"

La exención de la ruta exige verificar antes con Dani que el buscador usa consultas parametrizadas de verdad. Si no fuera así, la prioridad sería arreglar el código, no relajar el WAF.

Regla 1100 (XSS) — depurar, seguir en vista previa. El problema está localizado en /api/resenas, un endpoint que recibe texto libre por diseño. Se crea la exención del apartado 7 (prioridad 950) y se comprueba que las reseñas se escapan al renderizar. Con esa exención puesta, otra semana de vista previa.

Regla 2000 (rastreo) — vista previa, análisis manual. 156 en una semana es poco tráfico: hay que mirar de dónde vienen. Si son unas pocas direcciones sostenidas, es el competidor y se puede activar. Si están dispersas, probablemente haya clientes legítimos entre ellas (agregadores de precios contratados por la propia AlpinaShop, por ejemplo) y hay que afinar la expresión antes.

Reglas 1400 (escáneres), 1200 (LFI) y 900 (CVE) — activar ya.

for P in 900 1200 1400; do
  gcloud compute security-policies rules update $P \
    --security-policy=pol-catalogo-web --no-preview
done

Volúmenes bajos y patrones que no tienen ninguna explicación legítima: son ataques reales. Se activan sin más discusión.

Solución 2

# 4900 — Solo POST en la ruta de la API
gcloud compute security-policies rules create 4900 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/api/socios/') && request.method != 'POST'" \
  --action=deny-405 \
  --description="API de socios: solo POST"

# 4910 — Sin clave de API, no se pasa del borde
gcloud compute security-policies rules create 4910 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/api/socios/') && !has(request.headers['x-alpina-api-key'])" \
  --action=deny-401 \
  --description="API de socios: falta la cabecera de clave"

# 4920 — Restriccion geografica
gcloud compute security-policies rules create 4920 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/api/socios/') && !(origin.region_code in ['ES','PT','FR'])" \
  --action=deny-403 --preview \
  --description="API de socios: solo ES, PT y FR"

# 4930 — Limite por CLAVE, no por IP, con veto
gcloud compute security-policies rules create 4930 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/api/socios/')" \
  --action=rate-based-ban \
  --rate-limit-threshold-count=100 \
  --rate-limit-threshold-interval-sec=60 \
  --ban-threshold-count=300 \
  --ban-threshold-interval-sec=180 \
  --ban-duration-sec=900 \
  --conform-action=allow \
  --exceed-action=deny-429 \
  --enforce-on-key=HTTP_HEADER \
  --enforce-on-key-name=x-alpina-api-key \
  --description="API de socios: 100 rpm por clave, veto de 15 min"

Justificación del orden. Las reglas se evalúan de menor a mayor prioridad y gana la primera coincidencia, así que van de lo más barato y categórico a lo más costoso:

  1. Método incorrecto (4900) y cabecera ausente (4910) son comprobaciones triviales que descartan tráfico basura sin evaluar nada más. Cuanto antes, mejor.
  2. Geografía (4920) en vista previa, porque un socio francés que use un proxy en Bélgica quedaría fuera y eso hay que confirmarlo con el equipo comercial antes de activarlo.
  3. Limitación de tasa (4930) al final: es la regla más cara de evaluar y solo tiene sentido aplicarla a peticiones que ya han superado los filtros anteriores.

El punto clave es --enforce-on-key=HTTP_HEADER con --enforce-on-key-name. Contar por IP fallaría en los dos sentidos: penalizaría injustamente a varias tiendas que comparten operador y no impediría que un socio abusivo rotase de dirección. Con la advertencia correspondiente: la cabecera la controla el cliente, así que la validación real de la clave sigue haciéndose en la aplicación; Cloud Armor solo la usa para agrupar el conteo.

Solución 3

Por qué no sirve una regla por IP. Son 4 000 direcciones distribuidas, probablemente una botnet o un servicio de proxies residenciales. Bloquear direcciones una a una es perseguir un objetivo que se mueve más rápido de lo que escribes.

Respuesta inmediata (minutos). Lo que hay en común no es el origen, es el comportamiento: rutas /buscar con términos aleatorios y sin Referer.

# 1) Cortar el sangrado: limite agresivo y temporal en el buscador
gcloud compute security-policies rules create 3050 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/buscar') && !has(request.headers['referer'])" \
  --action=throttle \
  --rate-limit-threshold-count=5 \
  --rate-limit-threshold-interval-sec=60 \
  --conform-action=allow --exceed-action=deny-429 \
  --enforce-on-key=IP \
  --description="INCIDENTE 2026-XX: busquedas sin Referer"

# 2) Si no basta, desafio reCAPTCHA en el buscador: no bloquea a personas
gcloud compute security-policies rules create 3060 \
  --security-policy=pol-catalogo-web \
  --expression="request.path.startsWith('/buscar') && token.recaptcha_session.score < 0.7" \
  --action=redirect --redirect-type=GOOGLE_RECAPTCHA \
  --description="INCIDENTE 2026-XX: desafio en el buscador"

El redirect a reCAPTCHA es la mejor herramienta en un incidente de bots en una tienda: las personas siguen comprando, los bots se caen.

Siguientes 24 horas.

  • Activar la protección adaptativa si no lo estaba (aunque tardará en tener línea base, y esa es la lección: se activa antes, no durante).
  • Analizar el log agrupando por rangos, agente de usuario y sistema autónomo, buscando una firma más precisa que permita afinar la regla de emergencia y reducir su impacto en clientes reales.
  • Revisar el impacto colateral: cuántas búsquedas legítimas cayeron con 429 mientras duró la regla 3050.
  • Subir temporalmente el máximo del autoescalado del MIG si sigue habiendo presión.

Estructural.

  • Cachear las búsquedas frecuentes en el CDN (03-03): una búsqueda que se sirve desde el borde no toca la base de datos.
  • Revisar por qué el buscador es tan caro. Un límite de tasa que salva la tienda es un parche sobre un endpoint que debería aguantar más; puede que falte un índice o convenga mover la búsqueda a un servicio dedicado.
  • Dejar las reglas de emergencia documentadas y con fecha de revisión, no permanentes con un umbral de crisis.
  • Evaluar Cloud Armor Enterprise: en un ataque así, la inteligencia de amenazas habría reconocido buena parte de esos orígenes y la protección de factura habría cubierto el sobrecoste.

Conclusión

AlpinaShop ya no recibe todo lo que le llega. Sabes qué es un WAF y, sobre todo, qué no resuelve: no arregla fallos de lógica de negocio, no detecta credenciales robadas y no parchea dependencias vulnerables. Es una capa de mitigación que compra tiempo, no una absolución, y por eso las consultas parametrizadas y la validación de entrada siguen siendo obligatorias en el código de Dani.

Entiendes dónde actúa Cloud Armor: en el borde, en el mismo punto de presencia donde entra el cliente, antes de la caché y antes de IAP, adjuntado como política al servicio de backend bs-catalogo-web y como política de borde al backend de bucket bb-catalogo-imagenes. Dominas el modelo de políticas, reglas y prioridades, con la regla por defecto allow en el extremo, la exención de la oficina en la prioridad 100 y la costumbre de numerar de cien en cien para poder insertar.

Has construido pol-catalogo-web completa: reglas por IP y por geografía —con la advertencia de que bloquear países es una decisión comercial y legal, no técnica—, los conjuntos preconfigurados del OWASP con sensibilidad 1 y su problema real, que son los falsos positivos del buscador y de las reseñas, y las tres formas de tratarlos por orden de precisión: opt_out_rule_ids, exención de ruta y bajada de sensibilidad. Has escrito reglas propias en CEL para el rastreador del competidor, el endpoint caro de exportación, los métodos HTTP inútiles y las peticiones con Host inválido. Y has aprendido el procedimiento que hace todo esto seguro: --preview primero, registro VERBOSE, una semana de tráfico real, recuento por prioridad, depuración, activación por fases y nunca la víspera de una campaña, leyendo la diferencia entre previewSecurityPolicy y enforcedSecurityPolicy en el log.

Has protegido el formulario de acceso con rate-based-ban y el buscador con throttle, eligiendo la clave de agrupación con criterio y devolviendo 429 en lugar de 403. Conoces la protección adaptativa de capa 7 y por qué hay que activarla antes de necesitarla, el uso de reCAPTCHA Enterprise con redirect en lugar de deny —ante la duda, en una tienda se pregunta, no se bloquea—, y la diferencia entre Standard y Enterprise, con la inteligencia de amenazas y la protección de la factura como argumentos de peso.

Queda, sin embargo, un asunto incómodo. La contraseña del usuario app_catalogo de alpinashop-pedidos sigue viajando en una variable de entorno del startup-script de la plantilla del MIG: en texto claro, visible para cualquiera que pueda leer los metadatos de una instancia, imposible de rotar sin volver a desplegar y presente en cada copia de la plantilla. Hemos protegido el borde con esmero mientras la llave de la base de datos está debajo del felpudo. En la siguiente lección, 03-06, Secretos y cifrado: Secret Manager y Cloud KMS, sacamos esa contraseña de ahí y la llevamos a un almacén con versiones, permisos por secreto y rotación; y de paso entendemos cómo cifra Google Cloud tus datos en reposo, qué son las claves gestionadas por el cliente (CMEK) y cuándo compensa asumir la responsabilidad de gestionarlas tú.

Curso de Google Cloud Platform (GCP)

Módulo 1: Introducción a Google Cloud Platform

Módulo 2: Servicios principales de GCP

Módulo 3: Redes y seguridad

Módulo 4: Datos y análisis

Módulo 5: Aprendizaje automático e IA

Módulo 6: DevOps y monitoreo

Módulo 7: Temas avanzados de GCP

Módulo 8: Proyecto final

© Copyright 2026. Todos los derechos reservados