CDN con CloudFront y S3
¿Qué es el CDN?
Un CDN (Content Delivery Network) es una red de servidores distribuidos en diferentes ubicaciones geográficas que trabajan juntos para entregar contenido web de forma rápida y eficiente a los usuarios.
Imagina que tienes un sitio web con imágenes, videos, archivos CSS, etc. en un solo servidor. Cuando un usuario visita tu página, esos archivos deben viajar desde el servidor hasta el dispositivo del usuario. Si el servidor está lejos, la carga puede ser lenta. Con el CDN entregaremos la información al usuario de una forma mucho más rápida y cercana a él.
Un CDN almacena copias de tu contenido en múltiples servidores alrededor del mundo (o donde tu eligas dependiendo del proveedor de cloud). Cuando un usuario accede a tu sitio, el CDN elige el servidor más cercano a su ubicación para entregar el contenido. Esto reduce la distancia que deben recorrer los datos.
En resumen, un CDN es como tener una red de “mini servidores” ubicados por el mundo para asegurar que tu contenido llegue a los usuarios de manera rápida y eficiente, sin importar dónde se encuentren.
Montando un CDN con CloudFront y S3
Vamos a empezar a jugar, vamos a ver como crear un CDN con CloudFront y S3 para almacenar los objetos (archivos) que queremos distribuir. Usaremos terraform para desplegar la infraestructura.
Cuando despleguemos el CloudFront nos entregará una URL (xxxxxxx.cloudfront.net), esta es la URL que tenemos que usar para acceder a nuestros objetos.
El código de terraform usado puedes encontrarlo en: github.com/alvarosaavedrau/cdn.alvarosaavedra.es
Creando el S3
El S3 es el servicio que nos permite almacenar los objetos que queremos entregar. Tenemos que configurar los permisos adecuados para que el CloudFront pueda acceder a los objetos, es buena práctica configurar los permisos de manera que solo el CloudFront tenga acceso a los objetos.
Click para ver el código de S3 y la política
resource "aws_s3_bucket" "s3" {
bucket = "cdn.alvarosaavedra.es"
}
resource "aws_s3_bucket_public_access_block" "s3" {
bucket = aws_s3_bucket.s3.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
depends_on = [aws_s3_bucket.s3]
}
resource "aws_s3_bucket_policy" "s3CDN" {
bucket = "cdn.alvarosaavedra.es"
policy = data.aws_iam_policy_document.s3CDNPolicy.json
depends_on = [aws_s3_bucket.s3]
}
data "aws_caller_identity" "accountID" {}
data "aws_iam_policy_document" "s3CDNPolicy" {
statement {
sid = "AllowCloudFrontServicePrincipalReadOnly"
effect = "Allow"
principals {
type = "Service"
identifiers = ["cloudfront.amazonaws.com"]
}
actions = [
"s3:GetObject"
]
resources = [
"arn:aws:s3:::${aws_s3_bucket.s3.bucket}/*"
]
condition {
test = "StringEquals"
variable = "AWS:SourceArn"
values = ["arn:aws:cloudfront::${data.aws_caller_identity.accountID.account_id}:distribution/${aws_cloudfront_distribution.s3CDN.id}"]
}
}
}
Creando el CloudFront y certificado ACM
AWS nos permite crear un certificado de manera gratuita con el servicio ACM.
Click para ver el código de ACM
resource "aws_acm_certificate" "cdn" {
domain_name = "cdn.alvarosaavedra.es"
validation_method = "DNS"
}
Este certificado tenemos que añadirlo a nuestro DNS como tipo CNAME.
Si usas CloudFlare para administrar tu DNS, no marques la opción Redirigido mediante proxy
para esta entrada de CNAME.
Al S3 se accedera unicamente mediante el CloudFront, para ello se crea el recurso aws_cloudfront_origin_access_control
OAC (Origin Access Control) y se configura en la propiedad origin_access_control_id
del recurso aws_cloudfront_distribution
.
Click para ver el código de CloudFront
resource "aws_cloudfront_origin_access_control" "s3CDN" {
name = "S3 access"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}
resource "aws_cloudfront_distribution" "s3CDN" {
enabled = true
aliases = [aws_s3_bucket.s3.bucket]
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = aws_s3_bucket.s3.bucket
viewer_protocol_policy = "redirect-to-https"
compress = true
min_ttl = 86400
default_ttl = 604800
max_ttl = 31536000
forwarded_values {
query_string = true
cookies {
forward = "none"
}
}
}
origin {
domain_name = aws_s3_bucket.s3.bucket_regional_domain_name
origin_id = aws_s3_bucket.s3.bucket
origin_access_control_id = aws_cloudfront_origin_access_control.s3CDN.id
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.cdn.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2018"
}
depends_on = [aws_s3_bucket.s3, aws_acm_certificate.cdn]
}
Revisa las 3 propiedades min_ttl, default_ttl y max_ttl
. Configúralas como quieras. En mi caso, como el contenido que voy a guardar aquí no cambiará, he configurado un TTL amplio:
min_ttl = 86400 # 24 horas
default_ttl = 604800 # 7 días
max_ttl = 31536000 # 1 año
Despliegue
CloudFront puede tardar hasta 10 minutos en crearse. Una vez creado, podemos acceder a nuestro CDN con la URL que nos devuelve el servicio de CloudFront, en este caso xxxxxxx.cloudfront.net
. Para no tener que acordarnos de esa URL cada vez que queremos acceder a nuestros recursos, vamos a crear un alias en nuestro DNS. Por ejemplo cdn.alvarosaavedra.es
que apuntará a la URL de CloudFront.
Si usas CloudFlare para administrar tu DNS, no marques la opción Redirigido mediante proxy
para esta entrada de CNAME. Deja que CloudFront se encargue de la caché.
Probar
Si quieres probar si esto funciona puedes hacerlo con esta URL: https://cdn.alvarosaavedra.es/prueba.txt, con esto estás accediendo a un fichero que está alojado en S3, pero no estás viéndolo a través del S3, sino a través de CloudFront en una localización muy cercana a ti.
