Actualizar Contenido en CloudFront: Cómo Crear una Invalidación para Limpiar el Caché del Edge

Reemplazaste un archivo en S3, recargaste el navegador, y CloudFront sigue sirviendo la versión antigua. Es uno de esos momentos donde sabes exactamente qué pasó, pero necesitas la solución correcta ahora mismo — sin esperar que el TTL expire solo. Este artículo explica cómo funciona el caché de CloudFront y cómo crear una invalidación de CloudFront para forzar la purga inmediata del edge.

TL;DR — Invalidación de CloudFront en 30 Segundos

SituaciónAcción
Archivo actualizado en S3, CloudFront sirve versión viejaCrear invalidación con la ruta del archivo
Múltiples archivos actualizadosUsar wildcard /* o listar rutas específicas
Quieres evitar invalidaciones frecuentesUsar versionado de archivos en el nombre (cache busting)
HerramientaConsola AWS, CLI (aws cloudfront create-invalidation), o SDK

Cómo Funciona el Caché de CloudFront

CloudFront opera como una red de puntos de presencia distribuidos globalmente llamados edge locations. Cuando un usuario solicita un objeto, el edge location más cercano verifica si tiene una copia en caché. Si la tiene y el TTL no ha expirado, sirve esa copia directamente — sin consultar el origen (S3 en este caso). Aquí está el problema: cuando reemplazas el archivo en S3, el edge no lo sabe. Sigue sirviendo lo que tiene almacenado localmente hasta que el TTL expira o tú lo invalidas explícitamente.

sequenceDiagram participant U as Usuario participant E as Edge Location participant S3 as Amazon S3 U->>E: GET /assets/app.js E-->>U: Cache HIT (versión antigua) Note over S3: Subes nueva versión a S3 Note over E: Edge no sabe del cambio U->>E: GET /assets/app.js E-->>U: Cache HIT (versión antigua) Note over E: Creas Invalidación E->>E: Marca objeto como expirado U->>E: GET /assets/app.js E->>S3: Cache MISS → Fetch origen S3-->>E: Nueva versión del archivo E-->>U: Sirve versión nueva
  1. Solicitud del usuario: El navegador pide /assets/app.js al edge location.
  2. Cache HIT: El edge tiene la versión anterior en caché y la sirve directamente, ignorando S3.
  3. Actualización en S3: Subes la nueva versión a S3, pero el edge no recibe notificación.
  4. Invalidación: Creas una invalidación. CloudFront marca el objeto como expirado en todos los edges.
  5. Siguiente solicitud: El edge ya no tiene la versión válida en caché, consulta S3 (Cache MISS), obtiene el archivo nuevo y lo almacena.

Qué es una Invalidación de CloudFront

Una invalidación le indica a CloudFront que elimine objetos específicos de su caché en todos los edge locations. Después de la invalidación, la próxima solicitud a esa ruta genera un cache miss y CloudFront recupera el objeto actualizado desde el origen.

Dos puntos operacionales importantes antes de continuar:

  • Las primeras 1,000 rutas de invalidación por mes no tienen costo adicional. A partir de ahí, se cobra por ruta. Los wildcards cuentan como una sola ruta, pero invalidan múltiples objetos. Verifica el pricing actualizado en la documentación oficial de AWS.
  • Una invalidación no es instantánea — típicamente tarda entre 1 y 5 minutos en propagarse a todos los edges, aunque puede variar. El estado de la invalidación pasa de InProgress a Completed cuando termina.

Crear una Invalidación de CloudFront — Paso a Paso

Paso 1: Identificar el Distribution ID

Antes de cualquier operación, necesitas el ID de tu distribución. Si tienes varias distribuciones, no asumas cuál es la correcta — confírmalo con la CLI. El DomainName en el output te ayuda a identificar cuál corresponde a tu dominio.

aws cloudfront list-distributions \
  --query 'DistributionList.Items[*].{ID:Id,Domain:DomainName,Status:Status}' \
  --output table

Anota el valor de ID (formato: E1XXXXXXXXX). Lo usarás en todos los pasos siguientes.

Paso 2: Crear la Invalidación por CLI

Con el Distribution ID en mano, crea la invalidación. El parámetro --paths acepta rutas absolutas desde la raíz de tu distribución. Si actualizaste un solo archivo, especifica la ruta exacta. Si actualizaste múltiples archivos o quieres limpiar todo el caché, usa /*.

Opción A — Archivo específico:

aws cloudfront create-invalidation \
  --distribution-id E1XXXXXXXXX \
  --paths '/assets/app.js'

Opción B — Múltiples archivos específicos:

aws cloudfront create-invalidation \
  --distribution-id E1XXXXXXXXX \
  --paths '/assets/app.js' '/assets/styles.css' '/index.html'

Opción C — Invalidar todo el caché (wildcard):

aws cloudfront create-invalidation \
  --distribution-id E1XXXXXXXXX \
  --paths '/*'

El output incluye un Invalidation.Id y el estado inicial InProgress. Guarda ese ID si necesitas monitorear el progreso.

🔽 Output de ejemplo de create-invalidation
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/E1XXXXXXXXX/invalidation/I2XXXXXXXXX",
    "Invalidation": {
        "Id": "I2XXXXXXXXX",
        "Status": "InProgress",
        "CreateTime": "2024-01-15T10:30:00.000Z",
        "InvalidationBatch": {
            "Paths": {
                "Quantity": 1,
                "Items": [
                    "/assets/app.js"
                ]
            },
            "CallerReference": "cli-1705312200"
        }
    }
}

Paso 3: Verificar el Estado de la Invalidación

Una invalidación en estado InProgress significa que todavía se está propagando. No confirmes que el problema está resuelto hasta ver Completed. Esto es especialmente importante en deployments automatizados donde el siguiente paso depende de que el caché esté limpio.

aws cloudfront get-invalidation \
  --distribution-id E1XXXXXXXXX \
  --id I2XXXXXXXXX \
  --query 'Invalidation.{ID:Id,Status:Status,CreateTime:CreateTime}'

Si quieres esperar automáticamente hasta que complete (útil en scripts de CI/CD):

aws cloudfront wait invalidation-completed \
  --distribution-id E1XXXXXXXXX \
  --id I2XXXXXXXXX

El comando wait bloquea la ejecución hasta que el estado sea Completed, usando polling interno. Útil para pipelines donde el siguiente paso requiere caché limpio.

Paso 4: Crear la Invalidación desde la Consola AWS

Si prefieres la interfaz gráfica o necesitas guiar a alguien del equipo sin acceso CLI:

  1. Abre la consola de CloudFront → selecciona tu distribución.
  2. Pestaña Invalidations → botón Create invalidation.
  3. Ingresa las rutas (una por línea), por ejemplo /assets/app.js o /*.
  4. Haz clic en Create invalidation y monitorea el estado en la misma pestaña.
graph LR A["Crear Invalidación
CLI / Consola"] --> B["Estado: InProgress
Propagando a edges"] B --> C["Estado: Completed
Todos los edges actualizados"] C --> D["Próxima solicitud
Cache Miss"] D --> E["Edge consulta S3
Obtiene objeto nuevo"] E --> F["Objeto en caché
con nuevo TTL"]
  1. Crear: Envías la solicitud de invalidación vía CLI o consola.
  2. InProgress: CloudFront propaga la invalidación a todos los edge locations globalmente.
  3. Completed: Todos los edges han marcado los objetos como expirados. La próxima solicitud irá al origen.
  4. Cache Miss → Fetch: El edge consulta S3, obtiene el objeto actualizado y lo almacena en caché con el nuevo TTL.

El Error Clásico: Invalidación Completada pero Sigue Viendo el Archivo Viejo

Aquí está el patrón de diagnóstico que más tiempo hace perder en producción:

Síntoma: La invalidación muestra estado Completed, pero el navegador sigue mostrando el archivo antiguo.

Diagnóstico incorrecto: 'La invalidación no funcionó' o 'CloudFront tiene un bug'. Se crea una segunda invalidación, mismos resultados.

Causa real: El navegador tiene el archivo en su propio caché local, completamente independiente de CloudFront. La invalidación limpió el edge, pero el navegador nunca hizo una nueva solicitud al servidor.

Verificación: Abre DevTools → Network → marca 'Disable cache' → recarga. Si ahora ves el archivo nuevo, el problema era el caché del navegador, no CloudFront.

Para confirmar que CloudFront está sirviendo la versión correcta independientemente del navegador, revisa el header x-cache en la respuesta HTTP:

curl -I https://tu-dominio.cloudfront.net/assets/app.js

Un valor x-cache: Miss from cloudfront en la primera solicitud post-invalidación confirma que el edge fue al origen. Un x-cache: Hit from cloudfront inmediatamente después de una invalidación completada indica que la ruta que invalidaste no coincide exactamente con la ruta del objeto en caché — revisa mayúsculas, query strings, y si la distribución tiene configurado compress para diferentes variantes del mismo objeto.

Una invalidación de CloudFront limpia el edge cache, no el caché del navegador. Son dos capas completamente independientes. Confundirlas es el diagnóstico erróneo más común en este escenario.

Estrategia de Largo Plazo: Cache Busting con Versionado de Archivos

Las invalidaciones resuelven el problema inmediato, pero si tu flujo de trabajo implica actualizaciones frecuentes de assets estáticos, el versionado de archivos es más eficiente operacionalmente. En lugar de invalidar, cambias el nombre del archivo en cada deploy:

  • /assets/app.js/assets/app.v2.js o /assets/app.abc123.js

El archivo anterior sigue en caché (no necesitas invalidarlo), el nuevo se sirve inmediatamente porque nunca estuvo en caché, y no incurres en costos de invalidación. La mayoría de los frameworks modernos de frontend (webpack, Vite, etc.) generan estos hashes automáticamente en el build.

Esto no elimina la necesidad de invalidaciones — el archivo index.html que referencia los assets con hash sí necesita invalidación en cada deploy, pero es una sola ruta en lugar de decenas.

IAM: Permisos Necesarios para Crear Invalidaciones

Si estás ejecutando invalidaciones desde un pipeline de CI/CD o un rol de IAM específico, necesitas el permiso cloudfront:CreateInvalidation. Para listar distribuciones, también cloudfront:ListDistributions.

🔽 Política IAM mínima para invalidaciones de CloudFront
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudfrontInvalidation",
      "Effect": "Allow",
      "Action": [
        "cloudfront:CreateInvalidation",
        "cloudfront:GetInvalidation",
        "cloudfront:ListInvalidations"
      ],
      "Resource": "arn:aws:cloudfront::123456789012:distribution/E1XXXXXXXXX"
    },
    {
      "Sid": "AllowListDistributions",
      "Effect": "Allow",
      "Action": "cloudfront:ListDistributions",
      "Resource": "*"
    }
  ]
}

Nota: CloudFront es un servicio global — el ARN de distribución no incluye región. El formato correcto es arn:aws:cloudfront::<account-id>:distribution/<distribution-id>. cloudfront:ListDistributions requiere Resource: "*" porque opera a nivel de cuenta, no de recurso individual.

Próximos Pasos y Recursos

Con la invalidación creada y verificada, el flujo de actualización de contenido en CloudFront queda completo. Para operaciones recurrentes, considera automatizar la invalidación como parte de tu pipeline de deploy usando el comando aws cloudfront create-invalidation seguido de aws cloudfront wait invalidation-completed.

Glosario de Términos Clave

TérminoDefinición
Edge LocationPunto de presencia de CloudFront donde se almacena el caché. Hay cientos distribuidos globalmente.
InvalidaciónInstrucción a CloudFront para eliminar objetos específicos del caché en todos los edge locations.
TTL (Time to Live)Tiempo que un objeto permanece en caché antes de que CloudFront lo considere expirado y consulte el origen.
Cache MissSituación donde el edge no tiene el objeto en caché (o fue invalidado) y debe recuperarlo del origen.
Cache BustingTécnica de incluir un hash o versión en el nombre del archivo para forzar que el navegador y CDN lo traten como un recurso nuevo.

Comentarios

Entradas populares de este blog

EC2 sin acceso a Internet en VPC personalizada: Internet Gateway y Route Table

Aumentar el Timeout de Lambda: Configuración, Límites y Diagnóstico en Producción