* notes / aws
CloudFront y las cookies: por qué necesitas una lista explícita
— Una investigación a fondo sobre por qué CloudFront descarta cookies por defecto, cómo configurar listas blancas con Cache Policy y Origin Request Policy, y la trampa de cacheabilidad que aprendí a la mala.
Detrás de CloudFront y con la convicción (ingenua) de que la distribución solo transportaría peticiones HTTP tal cual. La realidad me golpeó en cuanto el primer usuario intentó iniciar sesión: el formulario aceptaba las credenciales, el backend emitía la cookie session, el navegador la enviaba en la siguiente petición… y el origen jamás la veía. Tras horas revisando cabeceras en CloudWatch descubrí lo evidente: CloudFront, por diseño, omite todas las cookies salvo las que le digas explícitamente que reenvíe.
El contexto: la CDN como ente con memoria propia
Cabe destacar que una CDN no es un simple proxy transparente. CloudFront construye una clave de caché (cache key) para cada objeto, y esa clave determina si dos peticiones se consideran equivalentes. Si la clave ignora las cookies, dos usuarios distintos con cookies de sesión distintas podrían recibir, en teoría, la misma respuesta cacheada, lo cual sería catastrófico. Por consiguiente, AWS optó por una postura defensiva: descartar cookies por defecto, obligando al ingeniero a decidir conscientemente qué información debe formar parte tanto de la cache key como de la petición que llega al origen.
Existen, asimismo, tres dimensiones independientes que conviene no confundir:
- Qué se incluye en la cache key (afecta a la cacheabilidad).
- Qué se reenvía al origen (afecta a lo que ve tu backend).
- Qué se incluye en la respuesta cacheable (afecta a la varianza por encabezado).
Históricamente todo esto se controlaba mediante la sección Cache Behavior con su famoso desplegable "Forward Cookies: None / Whitelist / All". A partir de 2020, AWS introdujo una arquitectura más granular basada en Cache Policy y Origin Request Policy, que recomiendo encarecidamente adoptar en cualquier distribución nueva.
Flujo de una petición con cookie
La trampa de la cacheabilidad
Antes de mostrar configuración, conviene insistir en el motivo por el cual no se debe reenviar todas las cookies (la tentación inicial, lo confieso). Si se selecciona "Forward all cookies", cada combinación distinta de cookies genera una entrada de caché diferente. Dado que cookies como _ga, _fbp o cualquier identificador de A/B testing son prácticamente únicas por usuario, la tasa de aciertos (cache hit ratio) se desploma hasta cifras irrisorias. La distribución deja de comportarse como CDN y se convierte, de facto, en un proxy carísimo. Por consiguiente, el principio es claro: whitelist mínima, semántica y consciente.
Configuración con CDK
A continuación reproduzco, ligeramente simplificada, la Cache Policy y la Origin Request Policy que finalmente desplegué. La distinción es sutil pero crítica: la primera condiciona qué se cachea; la segunda, qué se reenvía al origen sin afectar a la clave.
import { Duration } from 'aws-cdk-lib'
import {
CachePolicy,
CacheCookieBehavior,
CacheHeaderBehavior,
CacheQueryStringBehavior,
OriginRequestPolicy,
OriginRequestCookieBehavior,
OriginRequestHeaderBehavior,
} from 'aws-cdk-lib/aws-cloudfront'
const cachePolicy = new CachePolicy(this, 'AppCachePolicy', {
cachePolicyName: 'app-session-aware',
comment: 'Incluye session y csrf en la cache key',
defaultTtl: Duration.minutes(5),
minTtl: Duration.seconds(0),
maxTtl: Duration.hours(1),
cookieBehavior: CacheCookieBehavior.allowList('session', 'csrf'),
headerBehavior: CacheHeaderBehavior.allowList(
'Accept-Language',
'CloudFront-Viewer-Country',
),
queryStringBehavior: CacheQueryStringBehavior.allowList('lang', 'theme'),
enableAcceptEncodingGzip: true,
enableAcceptEncodingBrotli: true,
})
const originRequestPolicy = new OriginRequestPolicy(this, 'AppOriginRequest', {
originRequestPolicyName: 'app-origin-request',
comment: 'Reenvía cookies de tracking sin afectar a la cache key',
cookieBehavior: OriginRequestCookieBehavior.allowList(
'session',
'csrf',
'_ga',
'ab_test',
),
headerBehavior: OriginRequestHeaderBehavior.allowList(
'User-Agent',
'Referer',
'Accept-Language',
),
})Nótese que _ga y ab_test aparecen únicamente en la Origin Request Policy: el backend las recibe, pero no contaminan la clave de caché. Esta separación, imposible de expresar en la antigua configuración monolítica, es a mi juicio la mejor razón para migrar a las nuevas políticas.
El equivalente con AWS CLI
Para auditorías rápidas o despliegues sin IaC, la CLI sigue siendo la herramienta más directa:
aws cloudfront create-cache-policy \
--cache-policy-config '{
"Name": "app-session-aware",
"DefaultTTL": 300,
"MinTTL": 0,
"MaxTTL": 3600,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"EnableAcceptEncodingBrotli": true,
"CookiesConfig": {
"CookieBehavior": "whitelist",
"Cookies": { "Quantity": 2, "Items": ["session", "csrf"] }
},
"HeadersConfig": { "HeaderBehavior": "none" },
"QueryStringsConfig": { "QueryStringBehavior": "none" }
}
}'¿Y cuándo Lambda@Edge?
Si bien las políticas modernas cubren el 90 % de los casos, existen escenarios en los que se necesita lógica condicional sobre las cookies (por ejemplo, normalizar valores, rotar nombres legacy o extraer un fragmento del JWT antes de calcular la clave). Para esos casos he recurrido en alguna ocasión a Lambda@Edge en el evento viewer-request, donde se puede reescribir la cabecera Cookie antes de que CloudFront construya la cache key. El coste, claro, es no despreciable: una invocación Lambda en cada PoP impone latencia adicional (típicamente de 5 a 20 ms) y duplica la factura del request.
Como alternativa más liviana, CloudFront Functions permite manipulación trivial de cabeceras con un runtime JavaScript restringido y latencia submilisegundo, aunque carece de acceso a red.
Aprendizajes que me llevo
| Lección | Implicación práctica |
|---|---|
| El default es restrictivo, no transparente | Asume que todo se descarta hasta probar lo contrario |
| La cache key y el origen son ejes distintos | Usa Cache Policy + Origin Request Policy en paralelo |
| Reenviar todas las cookies destruye la cacheabilidad | Whitelist mínima y semántica |
| Cookies de tracking no deben formar parte de la clave | Sólo en Origin Request Policy |
| Lambda@Edge para casos exóticos, no como norma | Mide latencia antes y después |
Closure
Cada cookie que reenvías a través de CloudFront tiene dos costos: fragmenta la caché (cada combinación de valores es una entrada distinta) y suma tráfico hacia el origen. Por eso la primera revisión al adoptar CloudFront en cualquier proyecto es enumerar, una por una, las cookies que el backend necesita ver, y reenviar solo esas. No hay magia; solo una lista explícita.